Merge "Priority only dnd doesn't change ringer" into pi-dev
diff --git a/Android.mk b/Android.mk
index e2f88e8..b630c3f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -869,11 +869,27 @@
 $(eval $(call copy-one-file,frameworks/base/config/hiddenapi-blacklist.txt,\
                             $(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST)))
 
+# Automatically add all methods which match the following signatures.
+# These need to be greylisted in order to allow applications to write their
+# own serializers.
+$(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST): REGEX_SERIALIZATION := \
+    "readObject\(Ljava/io/ObjectInputStream;\)V" \
+    "readObjectNoData\(\)V" \
+    "readResolve\(\)Ljava/lang/Object;" \
+    "serialVersionUID:J" \
+    "serialPersistentFields:\[Ljava/io/ObjectStreamField;" \
+    "writeObject\(Ljava/io/ObjectOutputStream;\)V" \
+    "writeReplace\(\)Ljava/lang/Object;"
+$(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST): PRIVATE_API := $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE)
 # Temporarily merge light greylist from two files. Vendor list will become dark
 # grey once we remove the UI toast.
 $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST): frameworks/base/config/hiddenapi-light-greylist.txt \
-                                               frameworks/base/config/hiddenapi-vendor-list.txt
-	sort $^ > $@
+                                               frameworks/base/config/hiddenapi-vendor-list.txt \
+                                               $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE)
+	sort frameworks/base/config/hiddenapi-light-greylist.txt \
+	     frameworks/base/config/hiddenapi-vendor-list.txt \
+	     <(grep -E "\->("$(subst $(space),"|",$(REGEX_SERIALIZATION))")$$" $(PRIVATE_API)) \
+	> $@
 
 # Generate dark greylist as private API minus (blacklist plus light greylist).
 
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 2a67b75..6c3951d 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -9,3 +9,5 @@
                       services/usb/
 
 api_lint_hook = ${REPO_ROOT}/frameworks/base/tools/apilint/apilint_sha.sh ${PREUPLOAD_COMMIT}
+
+strings_lint_hook = ${REPO_ROOT}/frameworks/base/tools/stringslint/stringslint_sha.sh ${PREUPLOAD_COMMIT}
diff --git a/api/current.txt b/api/current.txt
index 5e7fa591..64b2d58 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7041,7 +7041,8 @@
     method public int getBackoffPolicy();
     method public android.content.ClipData getClipData();
     method public int getClipGrantFlags();
-    method public long getEstimatedNetworkBytes();
+    method public long getEstimatedNetworkDownloadBytes();
+    method public long getEstimatedNetworkUploadBytes();
     method public android.os.PersistableBundle getExtras();
     method public long getFlexMillis();
     method public int getId();
@@ -7058,8 +7059,10 @@
     method public long getTriggerContentMaxDelay();
     method public long getTriggerContentUpdateDelay();
     method public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
+    method public boolean isImportantWhileForeground();
     method public boolean isPeriodic();
     method public boolean isPersisted();
+    method public boolean isPrefetch();
     method public boolean isRequireBatteryNotLow();
     method public boolean isRequireCharging();
     method public boolean isRequireDeviceIdle();
@@ -7085,15 +7088,15 @@
     method public android.app.job.JobInfo build();
     method public android.app.job.JobInfo.Builder setBackoffCriteria(long, int);
     method public android.app.job.JobInfo.Builder setClipData(android.content.ClipData, int);
-    method public android.app.job.JobInfo.Builder setEstimatedNetworkBytes(long);
+    method public android.app.job.JobInfo.Builder setEstimatedNetworkBytes(long, long);
     method public android.app.job.JobInfo.Builder setExtras(android.os.PersistableBundle);
     method public android.app.job.JobInfo.Builder setImportantWhileForeground(boolean);
-    method public android.app.job.JobInfo.Builder setIsPrefetch(boolean);
     method public android.app.job.JobInfo.Builder setMinimumLatency(long);
     method public android.app.job.JobInfo.Builder setOverrideDeadline(long);
     method public android.app.job.JobInfo.Builder setPeriodic(long);
     method public android.app.job.JobInfo.Builder setPeriodic(long, long);
     method public android.app.job.JobInfo.Builder setPersisted(boolean);
+    method public android.app.job.JobInfo.Builder setPrefetch(boolean);
     method public android.app.job.JobInfo.Builder setRequiredNetwork(android.net.NetworkRequest);
     method public android.app.job.JobInfo.Builder setRequiredNetworkType(int);
     method public android.app.job.JobInfo.Builder setRequiresBatteryNotLow(boolean);
@@ -7163,10 +7166,11 @@
 
   public final class JobWorkItem implements android.os.Parcelable {
     ctor public JobWorkItem(android.content.Intent);
-    ctor public JobWorkItem(android.content.Intent, long);
+    ctor public JobWorkItem(android.content.Intent, long, long);
     method public int describeContents();
     method public int getDeliveryCount();
-    method public long getEstimatedNetworkBytes();
+    method public long getEstimatedNetworkDownloadBytes();
+    method public long getEstimatedNetworkUploadBytes();
     method public android.content.Intent getIntent();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.job.JobWorkItem> CREATOR;
@@ -7289,6 +7293,7 @@
     method public final java.lang.String getType(android.net.Uri);
     method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
     method public android.app.slice.Slice onBindSlice(android.net.Uri, java.util.List<android.app.slice.SliceSpec>);
+    method public android.app.PendingIntent onCreatePermissionRequest(android.net.Uri);
     method public java.util.Collection<android.net.Uri> onGetSliceDescendants(android.net.Uri);
     method public android.net.Uri onMapIntentToUri(android.content.Intent);
     method public void onSlicePinned(android.net.Uri);
@@ -24479,29 +24484,6 @@
     field public static final int RATING_THUMB_UP_DOWN = 2; // 0x2
   }
 
-  public final class Rating2 {
-    method public static android.media.Rating2 fromBundle(android.content.Context, android.os.Bundle);
-    method public float getPercentRating();
-    method public int getRatingStyle();
-    method public float getStarRating();
-    method public boolean hasHeart();
-    method public boolean isRated();
-    method public boolean isThumbUp();
-    method public static android.media.Rating2 newHeartRating(android.content.Context, boolean);
-    method public static android.media.Rating2 newPercentageRating(android.content.Context, float);
-    method public static android.media.Rating2 newStarRating(android.content.Context, int, float);
-    method public static android.media.Rating2 newThumbRating(android.content.Context, boolean);
-    method public static android.media.Rating2 newUnratedRating(android.content.Context, int);
-    method public android.os.Bundle toBundle();
-    field public static final int RATING_3_STARS = 3; // 0x3
-    field public static final int RATING_4_STARS = 4; // 0x4
-    field public static final int RATING_5_STARS = 5; // 0x5
-    field public static final int RATING_HEART = 1; // 0x1
-    field public static final int RATING_NONE = 0; // 0x0
-    field public static final int RATING_PERCENTAGE = 6; // 0x6
-    field public static final int RATING_THUMB_UP_DOWN = 2; // 0x2
-  }
-
   public deprecated class RemoteControlClient {
     ctor public RemoteControlClient(android.app.PendingIntent);
     ctor public RemoteControlClient(android.app.PendingIntent, android.os.Looper);
@@ -27277,6 +27259,7 @@
     method public static long getMobileTxBytes();
     method public static long getMobileTxPackets();
     method public static int getThreadStatsTag();
+    method public static int getThreadStatsUid();
     method public static long getTotalRxBytes();
     method public static long getTotalRxPackets();
     method public static long getTotalTxBytes();
@@ -27296,7 +27279,7 @@
     method public static void incrementOperationCount(int);
     method public static void incrementOperationCount(int, int);
     method public static void setThreadStatsTag(int);
-    method public static void setThreadStatsUidSelf();
+    method public static void setThreadStatsUid(int);
     method public static void tagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
     method public static void tagFileDescriptor(java.io.FileDescriptor) throws java.io.IOException;
     method public static void tagSocket(java.net.Socket) throws java.net.SocketException;
@@ -32057,7 +32040,6 @@
     ctor public Build.VERSION();
     field public static final java.lang.String BASE_OS;
     field public static final java.lang.String CODENAME;
-    field public static final int FIRST_SDK_INT;
     field public static final java.lang.String INCREMENTAL;
     field public static final int MIN_SUPPORTED_TARGET_SDK_INT;
     field public static final int PREVIEW_SDK_INT;
@@ -33093,8 +33075,6 @@
   }
 
   public final class SystemClock {
-    method public static java.time.Clock currentNetworkTimeClock();
-    method public static long currentNetworkTimeMillis();
     method public static long currentThreadTimeMillis();
     method public static long elapsedRealtime();
     method public static long elapsedRealtimeNanos();
@@ -41675,6 +41655,8 @@
 
   public abstract class CellIdentity implements android.os.Parcelable {
     method public int describeContents();
+    method public java.lang.CharSequence getOperatorAlphaLong();
+    method public java.lang.CharSequence getOperatorAlphaShort();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.CellIdentity> CREATOR;
   }
@@ -41684,8 +41666,6 @@
     method public int getLatitude();
     method public int getLongitude();
     method public int getNetworkId();
-    method public java.lang.CharSequence getOperatorAlphaLong();
-    method public java.lang.CharSequence getOperatorAlphaShort();
     method public int getSystemId();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityCdma> CREATOR;
@@ -41701,8 +41681,6 @@
     method public deprecated int getMnc();
     method public java.lang.String getMncString();
     method public java.lang.String getMobileNetworkOperator();
-    method public java.lang.CharSequence getOperatorAlphaLong();
-    method public java.lang.CharSequence getOperatorAlphaShort();
     method public deprecated int getPsc();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityGsm> CREATOR;
@@ -41717,8 +41695,6 @@
     method public deprecated int getMnc();
     method public java.lang.String getMncString();
     method public java.lang.String getMobileNetworkOperator();
-    method public java.lang.CharSequence getOperatorAlphaLong();
-    method public java.lang.CharSequence getOperatorAlphaShort();
     method public int getPci();
     method public int getTac();
     method public void writeToParcel(android.os.Parcel, int);
@@ -41743,8 +41719,6 @@
     method public deprecated int getMnc();
     method public java.lang.String getMncString();
     method public java.lang.String getMobileNetworkOperator();
-    method public java.lang.CharSequence getOperatorAlphaLong();
-    method public java.lang.CharSequence getOperatorAlphaShort();
     method public int getPsc();
     method public int getUarfcn();
     method public void writeToParcel(android.os.Parcel, int);
@@ -45070,18 +45044,6 @@
     field public static final deprecated boolean RELEASE = true;
   }
 
-  public class DataUnit extends java.lang.Enum {
-    method public long toBytes(long);
-    method public static android.util.DataUnit valueOf(java.lang.String);
-    method public static final android.util.DataUnit[] values();
-    enum_constant public static final android.util.DataUnit GIBIBYTES;
-    enum_constant public static final android.util.DataUnit GIGABYTES;
-    enum_constant public static final android.util.DataUnit KIBIBYTES;
-    enum_constant public static final android.util.DataUnit KILOBYTES;
-    enum_constant public static final android.util.DataUnit MEBIBYTES;
-    enum_constant public static final android.util.DataUnit MEGABYTES;
-  }
-
   public class DebugUtils {
     method public static boolean isObjectSelected(java.lang.Object);
   }
diff --git a/api/removed.txt b/api/removed.txt
index 1228fd1..4279c31 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -54,6 +54,24 @@
 
 }
 
+package android.app.job {
+
+  public class JobInfo implements android.os.Parcelable {
+    method public deprecated long getEstimatedNetworkBytes();
+  }
+
+  public static final class JobInfo.Builder {
+    method public deprecated android.app.job.JobInfo.Builder setEstimatedNetworkBytes(long);
+    method public deprecated android.app.job.JobInfo.Builder setIsPrefetch(boolean);
+  }
+
+  public final class JobWorkItem implements android.os.Parcelable {
+    ctor public deprecated JobWorkItem(android.content.Intent, long);
+    method public deprecated long getEstimatedNetworkBytes();
+  }
+
+}
+
 package android.app.usage {
 
   public final class StorageStats implements android.os.Parcelable {
@@ -261,6 +279,10 @@
     method public static deprecated org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache);
   }
 
+  public class TrafficStats {
+    method public static deprecated void setThreadStatsUidSelf();
+  }
+
 }
 
 package android.os {
diff --git a/api/test-current.txt b/api/test-current.txt
index e84d204..d323725 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -240,6 +240,7 @@
   public abstract class PackageManager {
     method public abstract java.lang.String getDefaultBrowserPackageNameAsUser(int);
     method public abstract int getInstallReason(java.lang.String, android.os.UserHandle);
+    method public abstract java.lang.String[] getNamesForUids(int[]);
     method public abstract java.lang.String getPermissionControllerPackageName();
     method public abstract boolean isPermissionReviewModeEnabled();
     field public static final java.lang.String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage";
@@ -481,6 +482,7 @@
 package android.os {
 
   public static class Build.VERSION {
+    field public static final int FIRST_SDK_INT;
     field public static final int RESOURCES_SDK_INT;
   }
 
@@ -585,6 +587,7 @@
     field public static final java.lang.String HIDDEN_API_BLACKLIST_EXEMPTIONS = "hidden_api_blacklist_exemptions";
     field public static final java.lang.String LOCATION_GLOBAL_KILL_SWITCH = "location_global_kill_switch";
     field public static final java.lang.String LOW_POWER_MODE = "low_power";
+    field public static final java.lang.String LOW_POWER_MODE_STICKY = "low_power_sticky";
     field public static final java.lang.String USE_OPEN_WIFI_PACKAGE = "use_open_wifi_package";
   }
 
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 556709b..1aef0c4 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -206,7 +206,9 @@
     tests/e2e/GaugeMetric_e2e_push_test.cpp \
     tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp \
     tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp \
-    tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
+    tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp \
+    tests/e2e/Anomaly_count_e2e_test.cpp \
+    tests/e2e/Anomaly_duration_sum_e2e_test.cpp
 
 LOCAL_STATIC_LIBRARIES := \
     $(statsd_common_static_libraries) \
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 1be4dc5..a07a355 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -69,6 +69,11 @@
     void dumpStates(FILE* out, bool verbose);
 
 private:
+    // For testing only.
+    inline sp<AlarmMonitor> getAnomalyAlarmMonitor() const {
+        return mAnomalyAlarmMonitor;
+    }
+
     mutable mutex mMetricsMutex;
 
     std::unordered_map<ConfigKey, sp<MetricsManager>> mMetricsManagers;
@@ -133,13 +138,15 @@
     FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_SimpleCondition);
     FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_SimpleCondition);
 
-
-
     FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_AND_CombinationCondition);
     FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_AND_CombinationCondition);
     FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_AND_CombinationCondition);
 
-
+    FRIEND_TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_single_bucket);
+    FRIEND_TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_multiple_buckets);
+    FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket);
+    FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets);
+    FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period);
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index 49de1ac..f0960e3 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -66,6 +66,9 @@
 
 void AnomalyTracker::advanceMostRecentBucketTo(const int64_t& bucketNum) {
     VLOG("advanceMostRecentBucketTo() called.");
+    if (mNumOfPastBuckets <= 0) {
+        return;
+    }
     if (bucketNum <= mMostRecentBucketNum) {
         ALOGW("Cannot advance buckets backwards (bucketNum=%lld but mMostRecentBucketNum=%lld)",
               (long long)bucketNum, (long long)mMostRecentBucketNum);
@@ -170,7 +173,8 @@
 
 int64_t AnomalyTracker::getPastBucketValue(const MetricDimensionKey& key,
                                            const int64_t& bucketNum) const {
-    if (bucketNum < 0 || bucketNum <= mMostRecentBucketNum - mNumOfPastBuckets
+    if (bucketNum < 0 || mMostRecentBucketNum < 0
+            || bucketNum <= mMostRecentBucketNum - mNumOfPastBuckets
             || bucketNum > mMostRecentBucketNum) {
         return 0;
     }
@@ -241,14 +245,10 @@
 }
 
 bool AnomalyTracker::isInRefractoryPeriod(const uint64_t& timestampNs,
-                                          const MetricDimensionKey& key) {
+                                          const MetricDimensionKey& key) const {
     const auto& it = mRefractoryPeriodEndsSec.find(key);
     if (it != mRefractoryPeriodEndsSec.end()) {
-        if (timestampNs < it->second * NS_PER_SEC) {
-            return true;
-        } else {
-            mRefractoryPeriodEndsSec.erase(key);
-        }
+        return timestampNs < it->second * NS_PER_SEC;
     }
     return false;
 }
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.h b/cmds/statsd/src/anomaly/AnomalyTracker.h
index d3da7dc..ae0af64 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.h
@@ -113,6 +113,13 @@
     }
 
 protected:
+    // For testing only.
+    // Returns the alarm timestamp in seconds for the query dimension if it exists. Otherwise
+    // returns 0.
+    virtual uint32_t getAlarmTimestampSec(const MetricDimensionKey& dimensionKey) const {
+        return 0;   // The base AnomalyTracker class doesn't have alarms.
+    }
+
     // statsd_config.proto Alert message that defines this tracker.
     const Alert mAlert;
 
@@ -159,8 +166,7 @@
     void subtractValueFromSum(const MetricDimensionKey& key, const int64_t& bucketValue);
 
     // Returns true if in the refractory period, else false.
-    // If there is a stored refractory period but it ended prior to timestampNs, it is removed.
-    bool isInRefractoryPeriod(const uint64_t& timestampNs, const MetricDimensionKey& key);
+    bool isInRefractoryPeriod(const uint64_t& timestampNs, const MetricDimensionKey& key) const;
 
     // Calculates the corresponding bucket index within the circular array.
     // Requires bucketNum >= 0.
@@ -176,6 +182,9 @@
     FRIEND_TEST(AnomalyTrackerTest, TestSparseBuckets);
     FRIEND_TEST(GaugeMetricProducerTest, TestAnomalyDetection);
     FRIEND_TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced);
+    FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket);
+    FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets);
+    FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period);
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
index 79067eb..cdc4251 100644
--- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
@@ -38,11 +38,10 @@
 void DurationAnomalyTracker::startAlarm(const MetricDimensionKey& dimensionKey,
                                         const uint64_t& timestampNs) {
     // Alarms are stored in secs. Must round up, since if it fires early, it is ignored completely.
-    uint32_t timestampSec = static_cast<uint32_t>((timestampNs -1)/ NS_PER_SEC) + 1; // round up
+    uint32_t timestampSec = static_cast<uint32_t>((timestampNs -1) / NS_PER_SEC) + 1; // round up
     if (isInRefractoryPeriod(timestampNs, dimensionKey)) {
-        // TODO: Bug! By the refractory's end, the data might be erased and the alarm inapplicable.
-        VLOG("Setting a delayed anomaly alarm lest it fall in the refractory period");
-        timestampSec = getRefractoryPeriodEndsSec(dimensionKey) + 1;
+        VLOG("Not setting anomaly alarm since it would fall in the refractory period.");
+        return;
     }
 
     auto itr = mAlarms.find(dimensionKey);
diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.h b/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
index 92bb2bc..53155d9 100644
--- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
@@ -52,6 +52,13 @@
             unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& firedAlarms) override;
 
 protected:
+    // Returns the alarm timestamp in seconds for the query dimension if it exists. Otherwise
+    // returns 0.
+    uint32_t getAlarmTimestampSec(const MetricDimensionKey& dimensionKey) const override {
+        auto it = mAlarms.find(dimensionKey);
+        return it == mAlarms.end() ? 0 : it->second->timestampSec;
+    }
+
     // The alarms owned by this tracker. The alarm monitor also shares the alarm pointers when they
     // are still active.
     std::unordered_map<MetricDimensionKey, sp<const InternalAlarm>> mAlarms;
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index 7a55f60..ef637df 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -92,6 +92,10 @@
 const int FIELD_ID_UID_MAP_DROPPED_SNAPSHOTS = 4;
 const int FIELD_ID_UID_MAP_DROPPED_CHANGES = 5;
 
+const std::map<int, std::pair<size_t, size_t>> StatsdStats::kAtomDimensionKeySizeLimitMap = {
+        {android::util::CPU_TIME_PER_UID_FREQ, {6000, 10000}},
+};
+
 // TODO: add stats for pulled atoms.
 StatsdStats::StatsdStats() {
     mPushedAtomStats.resize(android::util::kMaxPushedAtomId + 1);
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index a4f64dd..7675888 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -81,6 +81,9 @@
     const static int kDimensionKeySizeSoftLimit = 300;
     const static int kDimensionKeySizeHardLimit = 500;
 
+    // Per atom dimension key size limit
+    static const std::map<int, std::pair<size_t, size_t>> kAtomDimensionKeySizeLimitMap;
+
     const static int kMaxConfigCount = 10;
     const static int kMaxAlertCountPerConfig = 100;
     const static int kMaxConditionCountPerConfig = 200;
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 49034ac..f08d54a 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -17,9 +17,9 @@
 #define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
+#include "../guardrail/StatsdStats.h"
 #include "GaugeMetricProducer.h"
-#include "guardrail/StatsdStats.h"
-#include "stats_log_util.h"
+#include "../stats_log_util.h"
 
 #include <cutils/log.h>
 
@@ -60,12 +60,20 @@
 
 GaugeMetricProducer::GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& metric,
                                          const int conditionIndex,
-                                         const sp<ConditionWizard>& wizard,
-                                         const int pullTagId, const uint64_t startTimeNs,
+                                         const sp<ConditionWizard>& wizard, const int pullTagId,
+                                         const uint64_t startTimeNs,
                                          shared_ptr<StatsPullerManager> statsPullerManager)
     : MetricProducer(metric.id(), key, startTimeNs, conditionIndex, wizard),
       mStatsPullerManager(statsPullerManager),
-      mPullTagId(pullTagId) {
+      mPullTagId(pullTagId),
+      mDimensionSoftLimit(StatsdStats::kAtomDimensionKeySizeLimitMap.find(pullTagId) !=
+                                          StatsdStats::kAtomDimensionKeySizeLimitMap.end()
+                                  ? StatsdStats::kAtomDimensionKeySizeLimitMap.at(pullTagId).first
+                                  : StatsdStats::kDimensionKeySizeSoftLimit),
+      mDimensionHardLimit(StatsdStats::kAtomDimensionKeySizeLimitMap.find(pullTagId) !=
+                                          StatsdStats::kAtomDimensionKeySizeLimitMap.end()
+                                  ? StatsdStats::kAtomDimensionKeySizeLimitMap.at(pullTagId).second
+                                  : StatsdStats::kDimensionKeySizeHardLimit) {
     mCurrentSlicedBucket = std::make_shared<DimToGaugeAtomsMap>();
     mCurrentSlicedBucketForAnomaly = std::make_shared<DimToValMap>();
     int64_t bucketSizeMills = 0;
@@ -305,11 +313,11 @@
         return false;
     }
     // 1. Report the tuple count if the tuple count > soft limit
-    if (mCurrentSlicedBucket->size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
+    if (mCurrentSlicedBucket->size() > mDimensionSoftLimit - 1) {
         size_t newTupleCount = mCurrentSlicedBucket->size() + 1;
         StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetricId, newTupleCount);
         // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
-        if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
+        if (newTupleCount > mDimensionHardLimit) {
             ALOGE("GaugeMetric %lld dropping data for dimension key %s",
                 (long long)mMetricId, newKey.toString().c_str());
             return true;
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index dd6aff4..4b543f8 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -150,6 +150,10 @@
 
     static const size_t kBucketSize = sizeof(GaugeBucket{});
 
+    const size_t mDimensionSoftLimit;
+
+    const size_t mDimensionHardLimit;
+
     FRIEND_TEST(GaugeMetricProducerTest, TestWithCondition);
     FRIEND_TEST(GaugeMetricProducerTest, TestNoCondition);
     FRIEND_TEST(GaugeMetricProducerTest, TestPushedEventsWithUpgrade);
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index ea45f43..4983f96 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -188,7 +188,7 @@
 
     // Convenience to compute the current bucket's end time, which is always aligned with the
     // start time of the metric.
-    uint64_t getCurrentBucketEndTimeNs() {
+    uint64_t getCurrentBucketEndTimeNs() const {
         return mStartTimeNs + (mCurrentBucketNum + 1) * mBucketSizeNs;
     }
 
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 46a9b34..05ce84d 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -178,6 +178,12 @@
     FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_AND_CombinationCondition);
     FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_AND_CombinationCondition);
 
+    FRIEND_TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_single_bucket);
+    FRIEND_TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_multiple_buckets);
+    FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket);
+    FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets);
+    FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period);
+
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 767260d..ed4d7e4 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -18,8 +18,8 @@
 #include "Log.h"
 
 #include "ValueMetricProducer.h"
-#include "guardrail/StatsdStats.h"
-#include "stats_log_util.h"
+#include "../guardrail/StatsdStats.h"
+#include "../stats_log_util.h"
 
 #include <cutils/log.h>
 #include <limits.h>
@@ -68,7 +68,15 @@
     : MetricProducer(metric.id(), key, startTimeNs, conditionIndex, wizard),
       mValueField(metric.value_field()),
       mStatsPullerManager(statsPullerManager),
-      mPullTagId(pullTagId) {
+      mPullTagId(pullTagId),
+      mDimensionSoftLimit(StatsdStats::kAtomDimensionKeySizeLimitMap.find(pullTagId) !=
+                                          StatsdStats::kAtomDimensionKeySizeLimitMap.end()
+                                  ? StatsdStats::kAtomDimensionKeySizeLimitMap.at(pullTagId).first
+                                  : StatsdStats::kDimensionKeySizeSoftLimit),
+      mDimensionHardLimit(StatsdStats::kAtomDimensionKeySizeLimitMap.find(pullTagId) !=
+                                          StatsdStats::kAtomDimensionKeySizeLimitMap.end()
+                                  ? StatsdStats::kAtomDimensionKeySizeLimitMap.at(pullTagId).second
+                                  : StatsdStats::kDimensionKeySizeHardLimit) {
     // TODO: valuemetric for pushed events may need unlimited bucket length
     int64_t bucketSizeMills = 0;
     if (metric.has_bucket()) {
@@ -266,11 +274,11 @@
     if (mCurrentSlicedBucket.find(newKey) != mCurrentSlicedBucket.end()) {
         return false;
     }
-    if (mCurrentSlicedBucket.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
+    if (mCurrentSlicedBucket.size() > mDimensionSoftLimit - 1) {
         size_t newTupleCount = mCurrentSlicedBucket.size() + 1;
         StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetricId, newTupleCount);
         // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
-        if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
+        if (newTupleCount > mDimensionHardLimit) {
             ALOGE("ValueMetric %lld dropping data for dimension key %s",
                 (long long)mMetricId, newKey.toString().c_str());
             return true;
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index be57183..c4477b3 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -149,6 +149,10 @@
 
     static const size_t kBucketSize = sizeof(ValueBucket{});
 
+    const size_t mDimensionSoftLimit;
+
+    const size_t mDimensionHardLimit;
+
     FRIEND_TEST(ValueMetricProducerTest, TestNonDimensionalEvents);
     FRIEND_TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition);
     FRIEND_TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade);
diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
index 991a76a..ddfb8cc 100644
--- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
@@ -109,7 +109,7 @@
 
     // Predict the anomaly timestamp given the current status.
     virtual int64_t predictAnomalyTimestampNs(const DurationAnomalyTracker& anomalyTracker,
-                                              const uint64_t currentTimestamp) const = 0;
+                                              const int64_t currentTimestamp) const = 0;
     // Dump internal states for debugging
     virtual void dumpStates(FILE* out, bool verbose) const = 0;
 
@@ -118,12 +118,19 @@
     }
 
 protected:
+    uint64_t getCurrentBucketEndTimeNs() const {
+        return mStartTimeNs + (mCurrentBucketNum + 1) * mBucketSizeNs;
+    }
+
     // Starts the anomaly alarm.
     void startAnomalyAlarm(const uint64_t eventTime) {
         for (auto& anomalyTracker : mAnomalyTrackers) {
             if (anomalyTracker != nullptr) {
-                anomalyTracker->startAlarm(mEventKey,
-                                           predictAnomalyTimestampNs(*anomalyTracker, eventTime));
+                const uint64_t alarmTimestampNs =
+                    predictAnomalyTimestampNs(*anomalyTracker, eventTime);
+                if (alarmTimestampNs > 0) {
+                    anomalyTracker->startAlarm(mEventKey, alarmTimestampNs);
+                }
             }
         }
     }
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
index c9547cf..df9e6ae 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
@@ -313,7 +313,7 @@
 }
 
 int64_t MaxDurationTracker::predictAnomalyTimestampNs(const DurationAnomalyTracker& anomalyTracker,
-                                                      const uint64_t currentTimestamp) const {
+                                                      const int64_t currentTimestamp) const {
     // The allowed time we can continue in the current state is the
     // (anomaly threshold) - max(elapsed time of the started mInfos).
     int64_t maxElapsed = 0;
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
index 0452d37..32d42fa 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
@@ -57,7 +57,7 @@
     void onConditionChanged(bool condition, const uint64_t timestamp) override;
 
     int64_t predictAnomalyTimestampNs(const DurationAnomalyTracker& anomalyTracker,
-                                      const uint64_t currentTimestamp) const override;
+                                      const int64_t currentTimestamp) const override;
     void dumpStates(FILE* out, bool verbose) const override;
 
 private:
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
index b418a85..da79217 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
@@ -166,13 +166,13 @@
         current_info.mDuration = mDuration;
         (*output)[mEventKey].push_back(current_info);
         mDurationFullBucket += mDuration;
-        if (eventTimeNs > fullBucketEnd) {
-            // End of full bucket, can send to anomaly tracker now.
-            addPastBucketToAnomalyTrackers(mDurationFullBucket, mCurrentBucketNum);
-            mDurationFullBucket = 0;
-        }
         VLOG("  duration: %lld", (long long)current_info.mDuration);
     }
+    if (eventTimeNs > fullBucketEnd) {
+        // End of full bucket, can send to anomaly tracker now.
+        addPastBucketToAnomalyTrackers(mDurationFullBucket, mCurrentBucketNum);
+        mDurationFullBucket = 0;
+    }
 
     if (mStarted.size() > 0) {
         for (int i = 1; i < numBucketsForward; i++) {
@@ -186,6 +186,10 @@
             addPastBucketToAnomalyTrackers(info.mDuration, mCurrentBucketNum + i);
             VLOG("  add filling bucket with duration %lld", (long long)info.mDuration);
         }
+    } else {
+        if (numBucketsForward >= 2) {
+            addPastBucketToAnomalyTrackers(0, mCurrentBucketNum + numBucketsForward - 1);
+        }
     }
 
     mDuration = 0;
@@ -320,57 +324,84 @@
 }
 
 int64_t OringDurationTracker::predictAnomalyTimestampNs(
-        const DurationAnomalyTracker& anomalyTracker, const uint64_t eventTimestampNs) const {
+        const DurationAnomalyTracker& anomalyTracker, const int64_t eventTimestampNs) const {
     // TODO: Unit-test this and see if it can be done more efficiently (e.g. use int32).
-    // All variables below represent durations (not timestamps).
 
+    // The anomaly threshold.
     const int64_t thresholdNs = anomalyTracker.getAnomalyThreshold();
 
-    // The time until the current bucket ends. This is how much more 'space' it can hold.
-    const int64_t currRemainingBucketSizeNs =
-            mBucketSizeNs - (eventTimestampNs - mCurrentBucketStartTimeNs);
-    if (currRemainingBucketSizeNs < 0) {
-        ALOGE("OringDurationTracker currRemainingBucketSizeNs < 0");
-        // This should never happen. Return the safest thing possible given that data is corrupt.
-        return eventTimestampNs + thresholdNs;
-    }
+    // The timestamp of the current bucket end.
+    const int64_t currentBucketEndNs = getCurrentBucketEndTimeNs();
+
+    // The past duration ns for the current bucket.
+    int64_t currentBucketPastNs = mDuration + mDurationFullBucket;
 
     // As we move into the future, old buckets get overwritten (so their old data is erased).
-
     // Sum of past durations. Will change as we overwrite old buckets.
-    int64_t pastNs = mDuration + mDurationFullBucket;
-    pastNs += anomalyTracker.getSumOverPastBuckets(mEventKey);
+    int64_t pastNs = currentBucketPastNs + anomalyTracker.getSumOverPastBuckets(mEventKey);
 
-    // How much of the threshold is still unaccounted after considering pastNs.
-    int64_t leftNs = thresholdNs - pastNs;
+    // The refractory period end timestamp for dimension mEventKey.
+    const int64_t refractoryPeriodEndNs =
+            anomalyTracker.getRefractoryPeriodEndsSec(mEventKey) * NS_PER_SEC;
 
-    // First deal with the remainder of the current bucket.
-    if (leftNs <= currRemainingBucketSizeNs) {  // Predict the anomaly will occur in this bucket.
-        return eventTimestampNs + leftNs;
+    // The anomaly should happen when accumulated wakelock duration is above the threshold and
+    // not within the refractory period.
+    int64_t anomalyTimestampNs =
+        std::max(eventTimestampNs + thresholdNs - pastNs, refractoryPeriodEndNs);
+    // If the predicted the anomaly timestamp is within the current bucket, return it directly.
+    if (anomalyTimestampNs <= currentBucketEndNs) {
+        return std::max(eventTimestampNs, anomalyTimestampNs);
     }
-    // The remainder of this bucket contributes, but we must then move to the next bucket.
-    pastNs += currRemainingBucketSizeNs;
 
-    // Now deal with the past buckets, starting with the oldest.
-    for (int futBucketIdx = 0; futBucketIdx < anomalyTracker.getNumOfPastBuckets();
-         futBucketIdx++) {
-        // We now overwrite the oldest bucket with the previous 'current', and start a new
-        // 'current'.
+    // Remove the old bucket.
+    if (anomalyTracker.getNumOfPastBuckets() > 0) {
         pastNs -= anomalyTracker.getPastBucketValue(
-                mEventKey, mCurrentBucketNum - anomalyTracker.getNumOfPastBuckets() + futBucketIdx);
-        leftNs = thresholdNs - pastNs;
-        if (leftNs <= mBucketSizeNs) {  // Predict anomaly will occur in this bucket.
-            return eventTimestampNs + currRemainingBucketSizeNs + (futBucketIdx * mBucketSizeNs) +
-                   leftNs;
-        } else {  // This bucket would be entirely filled, and we'll need to move to the next
-                  // bucket.
-            pastNs += mBucketSizeNs;
+                            mEventKey,
+                            mCurrentBucketNum - anomalyTracker.getNumOfPastBuckets());
+        // Add the remaining of the current bucket to the accumulated wakelock duration.
+        pastNs += (currentBucketEndNs - eventTimestampNs);
+    } else {
+        // The anomaly depends on only one bucket.
+        pastNs = 0;
+    }
+
+    // The anomaly will not happen in the current bucket. We need to iterate over the future buckets
+    // to predict the accumulated wakelock duration and determine the anomaly timestamp accordingly.
+    for (int futureBucketIdx = 1; futureBucketIdx <= anomalyTracker.getNumOfPastBuckets() + 1;
+            futureBucketIdx++) {
+        // The alarm candidate timestamp should meet two requirements:
+        // 1. the accumulated wakelock duration is above the threshold.
+        // 2. it is not within the refractory period.
+        // 3. the alarm timestamp falls in this bucket. Otherwise we need to flush the past buckets,
+        //    find the new alarm candidate timestamp and check these requirements again.
+        const int64_t bucketEndNs = currentBucketEndNs + futureBucketIdx * mBucketSizeNs;
+        int64_t anomalyTimestampNs =
+            std::max(bucketEndNs - mBucketSizeNs + thresholdNs - pastNs, refractoryPeriodEndNs);
+        if (anomalyTimestampNs <= bucketEndNs) {
+            return anomalyTimestampNs;
+        }
+        if (anomalyTracker.getNumOfPastBuckets() <= 0) {
+            continue;
+        }
+
+        // No valid alarm timestamp is found in this bucket. The clock moves to the end of the
+        // bucket. Update the pastNs.
+        pastNs += mBucketSizeNs;
+        // 1. If the oldest past bucket is still in the past bucket window, we could fetch the past
+        // bucket and erase it from pastNs.
+        // 2. If the oldest past bucket is the current bucket, we should compute the
+        //   wakelock duration in the current bucket and erase it from pastNs.
+        // 3. Otherwise all othe past buckets are ancient.
+        if (futureBucketIdx < anomalyTracker.getNumOfPastBuckets()) {
+            pastNs -= anomalyTracker.getPastBucketValue(
+                    mEventKey,
+                    mCurrentBucketNum - anomalyTracker.getNumOfPastBuckets() + futureBucketIdx);
+        } else if (futureBucketIdx == anomalyTracker.getNumOfPastBuckets()) {
+            pastNs -= (currentBucketPastNs + (currentBucketEndNs - eventTimestampNs));
         }
     }
 
-    // If we have reached this point, we even have to overwrite the the original current bucket.
-    // Thus, none of the past data will still be extant - pastNs is now 0.
-    return eventTimestampNs + thresholdNs;
+    return std::max(eventTimestampNs + thresholdNs, refractoryPeriodEndNs);
 }
 
 void OringDurationTracker::dumpStates(FILE* out, bool verbose) const {
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
index 610e3ea..ca8abfe 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
@@ -56,7 +56,7 @@
             std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>* output) override;
 
     int64_t predictAnomalyTimestampNs(const DurationAnomalyTracker& anomalyTracker,
-                                      const uint64_t currentTimestamp) const override;
+                                      const int64_t currentTimestamp) const override;
     void dumpStates(FILE* out, bool verbose) const override;
 
 private:
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index 1cb20bc..8c8152d 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -116,32 +116,16 @@
         lock_guard<mutex> lock(mMutex);  // Exclusively lock for updates.
 
         mMap.clear();
-        ProtoOutputStream proto;
-        uint64_t token = proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
-                                      FIELD_ID_SNAPSHOT_PACKAGE_INFO);
+        vector<const SnapshotPackageInfo> infos;
         for (size_t j = 0; j < uid.size(); j++) {
             string package = string(String8(packageName[j]).string());
             mMap.insert(make_pair(uid[j], AppData(package, versionCode[j])));
-            proto.write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_NAME, package);
-            proto.write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION, (int)versionCode[j]);
-            proto.write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_UID, (int)uid[j]);
+            infos.emplace_back(package, versionCode[j], uid[j]);
         }
-        proto.end(token);
 
-        // Copy ProtoOutputStream output to
-        auto iter = proto.data();
-        size_t pos = 0;
-        vector<char> outData(proto.size());
-        while (iter.readBuffer() != NULL) {
-            size_t toRead = iter.currentToRead();
-            std::memcpy(&(outData[pos]), iter.readBuffer(), toRead);
-            pos += toRead;
-            iter.rp()->move(toRead);
-        }
-        SnapshotRecord record(timestamp, outData);
-        mSnapshots.push_back(record);
+        mSnapshots.emplace_back(timestamp, infos);
 
-        mBytesUsed += proto.size() + kBytesTimestampField;
+        mBytesUsed += mSnapshots.back().bytes;
         ensureBytesUsedBelowLimit();
         StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
         StatsdStats::getInstance().setUidMapSnapshots(mSnapshots.size());
@@ -212,7 +196,7 @@
     while (mBytesUsed > limit) {
         ALOGI("Bytes used %zu is above limit %zu, need to delete something", mBytesUsed, limit);
         if (mSnapshots.size() > 0) {
-            mBytesUsed -= mSnapshots.front().bytes.size() + kBytesTimestampField;
+            mBytesUsed -= mSnapshots.front().bytes;
             mSnapshots.pop_front();
             StatsdStats::getInstance().noteUidMapDropped(1, 0);
         } else if (mChanges.size() > 0) {
@@ -365,8 +349,14 @@
             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(),
-                         record.bytes.size());
+            for (const SnapshotPackageInfo& info : record.infos) {
+                uint64_t token = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
+                                              FIELD_ID_SNAPSHOT_PACKAGE_INFO);
+                proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_NAME, info.package);
+                proto->write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION, info.version);
+                proto->write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_UID, info.uid);
+                proto->end(token);
+            }
             proto->end(snapshotsToken);
         }
     }
@@ -380,7 +370,7 @@
         int64_t cutoff_nanos = newMin;
         for (auto it_snapshots = mSnapshots.begin(); it_snapshots != mSnapshots.end();) {
             if (it_snapshots->timestampNs < cutoff_nanos) {
-                mBytesUsed -= it_snapshots->bytes.size() + kBytesTimestampField;
+                mBytesUsed -= it_snapshots->bytes;
                 it_snapshots = mSnapshots.erase(it_snapshots);
             } else {
                 ++it_snapshots;
@@ -399,31 +389,13 @@
             // 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 snapshotProto;
-            uint64_t token = snapshotProto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
-                                                 FIELD_ID_SNAPSHOT_PACKAGE_INFO);
+            vector<const SnapshotPackageInfo> infos;
             for (const auto& it : mMap) {
-                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);
+                infos.emplace_back(it.second.packageName, it.second.versionCode, it.first);
             }
-            snapshotProto.end(token);
 
-            // Copy ProtoOutputStream output to
-            auto iter = snapshotProto.data();
-            vector<char> snapshotData(snapshotProto.size());
-            size_t pos = 0;
-            while (iter.readBuffer() != NULL) {
-                size_t toRead = iter.currentToRead();
-                std::memcpy(&(snapshotData[pos]), iter.readBuffer(), toRead);
-                pos += toRead;
-                iter.rp()->move(toRead);
-            }
-            mSnapshots.emplace_back(timestamp, snapshotData);
-            mBytesUsed += kBytesTimestampField + snapshotData.size();
+            mSnapshots.emplace_back(timestamp, infos);
+            mBytesUsed += mSnapshots.back().bytes;
         }
     }
     StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index 9dc73f4..a3632d2 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -74,17 +74,35 @@
 // less because of varint encoding).
 const unsigned int kBytesTimestampField = 10;
 
+struct SnapshotPackageInfo {
+    const string package;
+    const int32_t version;
+    const int32_t uid;
+    SnapshotPackageInfo(const string& package, const int32_t version, const int32_t uid)
+        : package(package), version(version), uid(uid) {
+    }
+};
+
+const unsigned int kBytesSnapshotInfo = sizeof(struct SnapshotPackageInfo);
+
 // 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;
 
-    // For performance reasons, we convert the package_info field (which is a
-    // repeated field of PackageInfo messages).
-    vector<char> bytes;
+    // All the package info known.
+    vector<const SnapshotPackageInfo> infos;
 
-    SnapshotRecord(const int64_t timestampNs, vector<char> bytes)
-        : timestampNs(timestampNs), bytes(bytes) {
+    // Tracks the number of bytes this snapshot consumes.
+    uint32_t bytes;
+
+    SnapshotRecord(const int64_t timestampNs, vector<const SnapshotPackageInfo>& infos)
+        : timestampNs(timestampNs), infos(infos) {
+        bytes = 0;
+        for (auto info : infos) {
+            bytes += info.package.size() + kBytesSnapshotInfo;
+        }
+        bytes += kBytesTimestampField;
     }
 };
 
@@ -210,6 +228,7 @@
 
     // Allows unit-test to access private methods.
     FRIEND_TEST(UidMapTest, TestClearingOutput);
+    FRIEND_TEST(UidMapTest, TestOutputIncludesAtLeastOneSnapshot);
     FRIEND_TEST(UidMapTest, TestMemoryComputed);
     FRIEND_TEST(UidMapTest, TestMemoryGuardrail);
 };
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index efed42e..4b9a87d 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -14,6 +14,7 @@
 
 #include "StatsLogProcessor.h"
 #include "config/ConfigKey.h"
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 #include "guardrail/StatsdStats.h"
 #include "logd/LogEvent.h"
@@ -122,6 +123,32 @@
     EXPECT_EQ(0, broadcastCount);
 }
 
+TEST(StatsLogProcessorTest, TestUidMapHasSnapshot) {
+    // Setup simple config key corresponding to empty config.
+    sp<UidMap> m = new UidMap();
+    m->updateMap({1, 2}, {1, 2}, {String16("p1"), String16("p2")});
+    sp<AlarmMonitor> anomalyAlarmMonitor;
+    sp<AlarmMonitor> subscriberAlarmMonitor;
+    int broadcastCount = 0;
+    StatsLogProcessor p(m, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
+                        [&broadcastCount](const ConfigKey& key) { broadcastCount++; });
+    ConfigKey key(3, 4);
+    StatsdConfig config;
+    config.add_allowed_log_source("AID_ROOT");
+    p.OnConfigUpdated(key, config);
+
+    // Expect to get no metrics, but snapshot specified above in uidmap.
+    vector<uint8_t> bytes;
+    p.onDumpReport(key, 1, &bytes);
+
+    ConfigMetricsReportList output;
+    output.ParseFromArray(bytes.data(), bytes.size());
+    EXPECT_TRUE(output.reports_size() > 0);
+    auto uidmap = output.reports(0).uid_map();
+    EXPECT_TRUE(uidmap.snapshots_size() > 0);
+    EXPECT_EQ(2, uidmap.snapshots(0).package_info_size());
+}
+
 #else
 GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
index c9492eb..a9b67e0 100644
--- a/cmds/statsd/tests/UidMap_test.cpp
+++ b/cmds/statsd/tests/UidMap_test.cpp
@@ -173,6 +173,33 @@
     results->ParseFromArray(bytes.data(), bytes.size());
 }
 
+// Test that uid map returns at least one snapshot even if we already obtained
+// this snapshot from a previous call to getData.
+TEST(UidMapTest, TestOutputIncludesAtLeastOneSnapshot) {
+    UidMap m;
+    // Initialize single config key.
+    ConfigKey config1(1, StringToId("config1"));
+    m.OnConfigUpdated(config1);
+    vector<int32_t> uids;
+    vector<int64_t> versions;
+    vector<String16> apps;
+    uids.push_back(1000);
+    apps.push_back(String16(kApp2.c_str()));
+    versions.push_back(5);
+    m.updateMap(1, uids, versions, apps);
+
+    // Set the last timestamp for this config key to be newer.
+    m.mLastUpdatePerConfigKey[config1] = 2;
+
+    ProtoOutputStream proto;
+    m.appendUidMap(3, config1, &proto);
+
+    // Check there's still a uidmap attached this one.
+    UidMapping results;
+    protoOutputStreamToUidMapping(&proto, &results);
+    EXPECT_EQ(1, results.snapshots_size());
+}
+
 TEST(UidMapTest, TestClearingOutput) {
     UidMap m;
 
@@ -199,7 +226,7 @@
     protoOutputStreamToUidMapping(&proto, &results);
     EXPECT_EQ(1, results.snapshots_size());
 
-    // It should be cleared now
+    // We have to keep at least one snapshot in memory at all times.
     EXPECT_EQ(1U, m.mSnapshots.size());
     proto.clear();
     m.appendUidMap(2, config1, &proto);
diff --git a/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp b/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp
new file mode 100644
index 0000000..93ecde5
--- /dev/null
+++ b/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp
@@ -0,0 +1,241 @@
+// 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.
+
+#include <gtest/gtest.h>
+
+#include "src/StatsLogProcessor.h"
+#include "src/stats_log_util.h"
+#include "tests/statsd_test_util.h"
+
+#include <vector>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+#ifdef __ANDROID__
+
+namespace {
+
+StatsdConfig CreateStatsdConfig(int num_buckets, int threshold) {
+    StatsdConfig config;
+    config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+    auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
+
+    *config.add_atom_matcher() = wakelockAcquireMatcher;
+
+    auto countMetric = config.add_count_metric();
+    countMetric->set_id(123456);
+    countMetric->set_what(wakelockAcquireMatcher.id());
+    *countMetric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
+            android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+    countMetric->set_bucket(FIVE_MINUTES);
+
+    auto alert = config.add_alert();
+    alert->set_id(StringToId("alert"));
+    alert->set_metric_id(123456);
+    alert->set_num_buckets(num_buckets);
+    alert->set_refractory_period_secs(10);
+    alert->set_trigger_if_sum_gt(threshold);
+    return config;
+}
+
+}  // namespace
+
+TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_single_bucket) {
+    const int num_buckets = 1;
+    const int threshold = 3;
+    auto config = CreateStatsdConfig(num_buckets, threshold);
+    const uint64_t alert_id = config.alert(0).id();
+    const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
+
+    int64_t bucketStartTimeNs = 10000000000;
+    int64_t bucketSizeNs =
+        TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
+
+    ConfigKey cfgKey;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+
+    sp<AnomalyTracker> anomalyTracker =
+        processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
+
+    std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
+    std::vector<AttributionNodeInternal> attributions2 = {
+        CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1")};
+    std::vector<AttributionNodeInternal> attributions3 = {
+        CreateAttribution(111, "App1"), CreateAttribution(333, "App3")};
+    std::vector<AttributionNodeInternal> attributions4 = {
+        CreateAttribution(222, "GMSCoreModule1"), CreateAttribution(333, "App3")};
+    std::vector<AttributionNodeInternal> attributions5 = {
+        CreateAttribution(222, "GMSCoreModule1") };
+
+    FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
+                           Value((int32_t)111));
+    HashableDimensionKey whatKey1({fieldValue1});
+    MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
+
+    FieldValue fieldValue2(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
+                           Value((int32_t)222));
+    HashableDimensionKey whatKey2({fieldValue2});
+    MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY);
+
+    auto event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 2);
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    event = CreateAcquireWakelockEvent(attributions4, "wl2", bucketStartTimeNs + 2);
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+    event = CreateAcquireWakelockEvent(attributions2, "wl1", bucketStartTimeNs + 3);
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + 3);
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+    event = CreateAcquireWakelockEvent(attributions3, "wl1", bucketStartTimeNs + 4);
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + 4);
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+    // Fired alarm and refractory period end timestamp updated.
+    event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 5);
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(refractory_period_sec + bucketStartTimeNs / NS_PER_SEC + 1,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 100);
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(refractory_period_sec + bucketStartTimeNs / NS_PER_SEC + 1,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + bucketSizeNs - 1);
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs - 1) / NS_PER_SEC + 1,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 1);
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs - 1) / NS_PER_SEC + 1,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    event = CreateAcquireWakelockEvent(attributions4, "wl2", bucketStartTimeNs + bucketSizeNs + 1);
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+    event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + bucketSizeNs + 2);
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+    event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + bucketSizeNs + 3);
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+    event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + bucketSizeNs + 4);
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 4) / NS_PER_SEC + 1,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+}
+
+TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_multiple_buckets) {
+    const int num_buckets = 3;
+    const int threshold = 3;
+    auto config = CreateStatsdConfig(num_buckets, threshold);
+    const uint64_t alert_id = config.alert(0).id();
+    const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
+
+    int64_t bucketStartTimeNs = 10000000000;
+    int64_t bucketSizeNs =
+        TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
+
+    ConfigKey cfgKey;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+
+    sp<AnomalyTracker> anomalyTracker =
+        processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
+
+    std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
+    std::vector<AttributionNodeInternal> attributions2 = {
+        CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1")};
+    std::vector<AttributionNodeInternal> attributions3 = {
+        CreateAttribution(111, "App1"), CreateAttribution(333, "App3")};
+    std::vector<AttributionNodeInternal> attributions4 = {
+        CreateAttribution(222, "GMSCoreModule1"), CreateAttribution(333, "App3")};
+    std::vector<AttributionNodeInternal> attributions5 = {
+        CreateAttribution(222, "GMSCoreModule1") };
+
+    FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
+                           Value((int32_t)111));
+    HashableDimensionKey whatKey1({fieldValue1});
+    MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
+
+    FieldValue fieldValue2(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
+                           Value((int32_t)222));
+    HashableDimensionKey whatKey2({fieldValue2});
+    MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY);
+
+    auto event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 2);
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    event = CreateAcquireWakelockEvent(attributions2, "wl1", bucketStartTimeNs + 3);
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    // Fired alarm and refractory period end timestamp updated.
+    event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 4);
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 1);
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    event = CreateAcquireWakelockEvent(attributions2, "wl1", bucketStartTimeNs + bucketSizeNs + 2);
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    event = CreateAcquireWakelockEvent(
+        attributions2, "wl1", bucketStartTimeNs + 3 * bucketSizeNs + 1);
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    event = CreateAcquireWakelockEvent(
+        attributions2, "wl1", bucketStartTimeNs + 3 * bucketSizeNs + 2);
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + 3 * bucketSizeNs + 2) / NS_PER_SEC + 1,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+}
+
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp b/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp
new file mode 100644
index 0000000..e924b03
--- /dev/null
+++ b/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp
@@ -0,0 +1,486 @@
+// 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.
+
+#include <gtest/gtest.h>
+
+#include "src/anomaly/DurationAnomalyTracker.h"
+#include "src/StatsLogProcessor.h"
+#include "src/stats_log_util.h"
+#include "tests/statsd_test_util.h"
+
+#include <vector>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+#ifdef __ANDROID__
+
+namespace {
+
+StatsdConfig CreateStatsdConfig(int num_buckets,
+                                uint64_t threshold_ns,
+                                DurationMetric::AggregationType aggregationType,
+                                bool nesting) {
+    StatsdConfig config;
+    config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+    *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
+    *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
+    *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
+    *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
+
+    auto screenIsOffPredicate = CreateScreenIsOffPredicate();
+    *config.add_predicate() = screenIsOffPredicate;
+
+    auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
+    FieldMatcher dimensions = CreateAttributionUidDimensions(
+            android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+    dimensions.add_child()->set_field(3);  // The wakelock tag is set in field 3 of the wakelock.
+    *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = dimensions;
+    holdingWakelockPredicate.mutable_simple_predicate()->set_count_nesting(nesting);
+    *config.add_predicate() = holdingWakelockPredicate;
+
+    auto durationMetric = config.add_duration_metric();
+    durationMetric->set_id(StringToId("WakelockDuration"));
+    durationMetric->set_what(holdingWakelockPredicate.id());
+    durationMetric->set_condition(screenIsOffPredicate.id());
+    durationMetric->set_aggregation_type(aggregationType);
+    *durationMetric->mutable_dimensions_in_what() =
+        CreateAttributionUidDimensions(android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+    durationMetric->set_bucket(FIVE_MINUTES);
+
+    auto alert = config.add_alert();
+    alert->set_id(StringToId("alert"));
+    alert->set_metric_id(StringToId("WakelockDuration"));
+    alert->set_num_buckets(num_buckets);
+    alert->set_refractory_period_secs(2);
+    alert->set_trigger_if_sum_gt(threshold_ns);
+    return config;
+}
+
+}  // namespace
+
+std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
+                                                      CreateAttribution(222, "GMSCoreModule1")};
+
+std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(111, "App2"),
+                                                      CreateAttribution(222, "GMSCoreModule1")};
+
+std::vector<AttributionNodeInternal> attributions3 = {CreateAttribution(222, "GMSCoreModule1")};
+
+MetricDimensionKey dimensionKey(
+    HashableDimensionKey({FieldValue(Field(android::util::WAKELOCK_STATE_CHANGED,
+                                           (int32_t)0x02010101), Value((int32_t)111))}),
+    DEFAULT_DIMENSION_KEY);
+
+MetricDimensionKey dimensionKey2(
+    HashableDimensionKey({FieldValue(Field(android::util::WAKELOCK_STATE_CHANGED,
+                                           (int32_t)0x02010101), Value((int32_t)222))}),
+    DEFAULT_DIMENSION_KEY);
+
+TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) {
+    const int num_buckets = 1;
+    const uint64_t threshold_ns = NS_PER_SEC;
+    auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, true);
+    const uint64_t alert_id = config.alert(0).id();
+    const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
+
+    int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
+    int64_t bucketSizeNs =
+        TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
+
+    ConfigKey cfgKey;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+
+    sp<AnomalyTracker> anomalyTracker =
+        processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
+
+    auto screen_on_event = CreateScreenStateChangedEvent(
+            android::view::DisplayStateEnum::DISPLAY_STATE_ON, bucketStartTimeNs + 1);
+    auto screen_off_event = CreateScreenStateChangedEvent(
+            android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 10);
+    processor->OnLogEvent(screen_on_event.get());
+    processor->OnLogEvent(screen_off_event.get());
+
+    // Acquire wakelock wl1.
+    auto acquire_event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 11);
+    processor->OnLogEvent(acquire_event.get());
+    EXPECT_EQ((bucketStartTimeNs + 11 + threshold_ns) / NS_PER_SEC + 1,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey));
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
+
+    // Release wakelock wl1. No anomaly detected. Alarm cancelled at the "release" event.
+    auto release_event = CreateReleaseWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 101);
+    processor->OnLogEvent(release_event.get());
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
+
+    // Acquire wakelock wl1 within bucket #0.
+    acquire_event = CreateAcquireWakelockEvent(attributions2, "wl1", bucketStartTimeNs + 110);
+    processor->OnLogEvent(acquire_event.get());
+    EXPECT_EQ((bucketStartTimeNs + 110 + threshold_ns - 90) / NS_PER_SEC + 1,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey));
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
+
+    // Release wakelock wl1. One anomaly detected.
+    release_event = CreateReleaseWakelockEvent(
+            attributions2, "wl1", bucketStartTimeNs + NS_PER_SEC + 109);
+    processor->OnLogEvent(release_event.get());
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
+    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
+
+    // Acquire wakelock wl1.
+    acquire_event = CreateAcquireWakelockEvent(
+        attributions1, "wl1", bucketStartTimeNs + NS_PER_SEC + 112);
+    processor->OnLogEvent(acquire_event.get());
+    // Wakelock has been hold longer than the threshold in bucket #0. The alarm is set at the
+    // end of the refractory period.
+    const int64_t alarmFiredTimestampSec0 = anomalyTracker->getAlarmTimestampSec(dimensionKey);
+    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1,
+              (uint32_t)alarmFiredTimestampSec0);
+
+    // Anomaly alarm fired.
+    auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
+            static_cast<uint32_t>(alarmFiredTimestampSec0));
+    EXPECT_EQ(1u, alarmSet.size());
+    processor->onAnomalyAlarmFired(alarmFiredTimestampSec0 * NS_PER_SEC, alarmSet);
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
+    EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
+
+    // Release wakelock wl1.
+    release_event = CreateReleaseWakelockEvent(
+            attributions1, "wl1", alarmFiredTimestampSec0 * NS_PER_SEC + NS_PER_SEC + 1);
+    processor->OnLogEvent(release_event.get());
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
+    // Within refractory period. No more anomaly detected.
+    EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
+
+    // Acquire wakelock wl1.
+    acquire_event = CreateAcquireWakelockEvent(
+        attributions2, "wl1", bucketStartTimeNs + bucketSizeNs -  5 * NS_PER_SEC - 11);
+    processor->OnLogEvent(acquire_event.get());
+    const int64_t alarmFiredTimestampSec1 = anomalyTracker->getAlarmTimestampSec(dimensionKey);
+    EXPECT_EQ((bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC) / NS_PER_SEC,
+              (uint64_t)alarmFiredTimestampSec1);
+
+    // Release wakelock wl1.
+    release_event = CreateReleaseWakelockEvent(
+        attributions2, "wl1", bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10);
+    processor->OnLogEvent(release_event.get());
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
+    EXPECT_EQ(refractory_period_sec +
+                    (bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10) / NS_PER_SEC + 1,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
+
+    alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
+                static_cast<uint32_t>(alarmFiredTimestampSec1));
+    EXPECT_EQ(0u, alarmSet.size());
+
+    // Acquire wakelock wl1 near the end of bucket #0.
+    acquire_event = CreateAcquireWakelockEvent(
+            attributions1, "wl1", bucketStartTimeNs + bucketSizeNs - 2);
+    processor->OnLogEvent(acquire_event.get());
+    EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC,
+               anomalyTracker->getAlarmTimestampSec(dimensionKey));
+
+    // Release the event at early bucket #1.
+    release_event = CreateReleaseWakelockEvent(
+            attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + NS_PER_SEC - 1);
+    processor->OnLogEvent(release_event.get());
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
+    // Anomaly detected when stopping the alarm. The refractory period does not change.
+    EXPECT_EQ(refractory_period_sec +
+                    (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
+
+    // Condition changes to false.
+    screen_on_event = CreateScreenStateChangedEvent(
+        android::view::DisplayStateEnum::DISPLAY_STATE_ON,
+        bucketStartTimeNs + 2 * bucketSizeNs + 20);
+    processor->OnLogEvent(screen_on_event.get());
+    EXPECT_EQ(refractory_period_sec +
+                    (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
+
+    acquire_event = CreateAcquireWakelockEvent(
+        attributions2, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 30);
+    processor->OnLogEvent(acquire_event.get());
+    // The condition is false. Do not start the alarm.
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
+    EXPECT_EQ(refractory_period_sec +
+                    (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
+
+    // Condition turns true.
+    screen_off_event = CreateScreenStateChangedEvent(
+        android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
+        bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC);
+    processor->OnLogEvent(screen_off_event.get());
+    EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC + threshold_ns) / NS_PER_SEC,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey));
+
+    // Condition turns to false.
+    screen_on_event = CreateScreenStateChangedEvent(
+        android::view::DisplayStateEnum::DISPLAY_STATE_ON,
+        bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1);
+    processor->OnLogEvent(screen_on_event.get());
+    // Condition turns to false. Cancelled the alarm.
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
+    //  Detected one anomaly.
+    EXPECT_EQ(refractory_period_sec +
+                    (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1) / NS_PER_SEC + 1,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
+
+    // Condition turns to true again.
+    screen_off_event = CreateScreenStateChangedEvent(
+        android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
+        bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 2);
+    processor->OnLogEvent(screen_off_event.get());
+    EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 2 + 1,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey));
+
+    release_event = CreateReleaseWakelockEvent(
+        attributions2, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC);
+    processor->OnLogEvent(release_event.get());
+    EXPECT_EQ(refractory_period_sec +
+                    (bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC) / NS_PER_SEC,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
+}
+
+TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets) {
+    const int num_buckets = 3;
+    const uint64_t threshold_ns = NS_PER_SEC;
+    auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, true);
+    const uint64_t alert_id = config.alert(0).id();
+    const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
+
+    int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
+    int64_t bucketSizeNs =
+        TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
+
+    ConfigKey cfgKey;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+
+    sp<AnomalyTracker> anomalyTracker =
+        processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
+
+    auto screen_off_event = CreateScreenStateChangedEvent(
+            android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 1);
+    processor->OnLogEvent(screen_off_event.get());
+
+    // Acquire wakelock "wc1" in bucket #0.
+    auto acquire_event = CreateAcquireWakelockEvent(
+        attributions1, "wl1", bucketStartTimeNs + bucketSizeNs -  NS_PER_SEC / 2 - 1);
+    processor->OnLogEvent(acquire_event.get());
+    EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey));
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
+
+    // Release wakelock "wc1" in bucket #0.
+    auto release_event = CreateReleaseWakelockEvent(
+        attributions1, "wl1", bucketStartTimeNs + bucketSizeNs - 1);
+    processor->OnLogEvent(release_event.get());
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
+
+    // Acquire wakelock "wc1" in bucket #1.
+    acquire_event = CreateAcquireWakelockEvent(
+        attributions2, "wl1", bucketStartTimeNs + bucketSizeNs + 1);
+    processor->OnLogEvent(acquire_event.get());
+    EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey));
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
+
+    release_event = CreateReleaseWakelockEvent(
+        attributions2, "wl1", bucketStartTimeNs + bucketSizeNs + 100);
+    processor->OnLogEvent(release_event.get());
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
+
+    // Acquire wakelock "wc2" in bucket #2.
+    acquire_event = CreateAcquireWakelockEvent(
+        attributions3, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 1);
+    processor->OnLogEvent(acquire_event.get());
+    EXPECT_EQ((bucketStartTimeNs + 2 *  bucketSizeNs) / NS_PER_SEC + 2,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey2));
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+    // Release wakelock "wc2" in bucket #2.
+    release_event = CreateReleaseWakelockEvent(
+        attributions3, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC);
+    processor->OnLogEvent(release_event.get());
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
+    EXPECT_EQ(refractory_period_sec +
+                   (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC) / NS_PER_SEC,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+    // Acquire wakelock "wc1" in bucket #2.
+    acquire_event = CreateAcquireWakelockEvent(
+        attributions2, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC);
+    processor->OnLogEvent(acquire_event.get());
+    EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 1,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey));
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
+
+    // Release wakelock "wc1" in bucket #2.
+    release_event = CreateReleaseWakelockEvent(
+        attributions2, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC);
+    processor->OnLogEvent(release_event.get());
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
+    EXPECT_EQ(refractory_period_sec +
+                   (int64_t)(bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC) / NS_PER_SEC + 1,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
+
+    acquire_event = CreateAcquireWakelockEvent(
+        attributions3, "wl2", bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 4);
+    processor->OnLogEvent(acquire_event.get());
+    acquire_event = CreateAcquireWakelockEvent(
+        attributions1, "wl1", bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 5);
+    processor->OnLogEvent(acquire_event.get());
+    EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey));
+    EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey2));
+
+    release_event = CreateReleaseWakelockEvent(
+        attributions3, "wl2", bucketStartTimeNs + 6 * bucketSizeNs + 2);
+    processor->OnLogEvent(release_event.get());
+    release_event = CreateReleaseWakelockEvent(
+        attributions1, "wl1", bucketStartTimeNs + 6 * bucketSizeNs + 6);
+    processor->OnLogEvent(release_event.get());
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
+    // The buckets are not messed up across dimensions. Only one dimension has anomaly triggered.
+    EXPECT_EQ(refractory_period_sec +
+                   (int64_t)(bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
+}
+
+TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period) {
+    const int num_buckets = 2;
+    const uint64_t threshold_ns = 3 * NS_PER_SEC;
+    auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, false);
+    int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
+    int64_t bucketSizeNs =
+        TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
+
+    const uint64_t alert_id = config.alert(0).id();
+    const uint32_t refractory_period_sec = 3 * bucketSizeNs / NS_PER_SEC;
+    config.mutable_alert(0)->set_refractory_period_secs(refractory_period_sec);
+
+    ConfigKey cfgKey;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+
+    sp<AnomalyTracker> anomalyTracker =
+        processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
+
+    auto screen_off_event = CreateScreenStateChangedEvent(
+            android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 1);
+    processor->OnLogEvent(screen_off_event.get());
+
+    // Acquire wakelock "wc1" in bucket #0.
+    auto acquire_event = CreateAcquireWakelockEvent(
+        attributions1, "wl1", bucketStartTimeNs + bucketSizeNs - 100);
+    processor->OnLogEvent(acquire_event.get());
+    EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey));
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
+
+    // Acquire the wakelock "wc1" again.
+    acquire_event = CreateAcquireWakelockEvent(
+        attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 2 * NS_PER_SEC + 1);
+    processor->OnLogEvent(acquire_event.get());
+    // The alarm does not change.
+    EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey));
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
+
+    // Anomaly alarm fired late.
+    const int64_t firedAlarmTimestampNs = bucketStartTimeNs + 2 * bucketSizeNs - NS_PER_SEC;
+    auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
+            static_cast<uint32_t>(firedAlarmTimestampNs / NS_PER_SEC));
+    EXPECT_EQ(1u, alarmSet.size());
+    processor->onAnomalyAlarmFired(firedAlarmTimestampNs, alarmSet);
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
+    EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
+
+    acquire_event = CreateAcquireWakelockEvent(
+        attributions1, "wl1", bucketStartTimeNs + 2 * bucketSizeNs - 100);
+    processor->OnLogEvent(acquire_event.get());
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
+    EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
+
+    auto release_event = CreateReleaseWakelockEvent(
+        attributions1, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 1);
+    processor->OnLogEvent(release_event.get());
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
+    // Within the refractory period. No anomaly.
+    EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
+
+    // A new wakelock, but still within refractory period.
+    acquire_event = CreateAcquireWakelockEvent(
+        attributions1, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 10 * NS_PER_SEC);
+    processor->OnLogEvent(acquire_event.get());
+    EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey));
+
+    release_event = CreateReleaseWakelockEvent(
+        attributions1, "wl1", bucketStartTimeNs + 3 * bucketSizeNs - NS_PER_SEC);
+    // Still in the refractory period. No anomaly.
+    processor->OnLogEvent(release_event.get());
+    EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
+
+    acquire_event = CreateAcquireWakelockEvent(
+        attributions1, "wl1", bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 5);
+    processor->OnLogEvent(acquire_event.get());
+    EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey));
+
+    release_event = CreateReleaseWakelockEvent(
+        attributions1, "wl1", bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 4);
+    processor->OnLogEvent(release_event.get());
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
+
+    acquire_event = CreateAcquireWakelockEvent(
+        attributions1, "wl1", bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 3);
+    processor->OnLogEvent(acquire_event.get());
+    EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey));
+}
+
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
index 2287c2b..c2334d8 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
@@ -458,7 +458,7 @@
 }  // namespace
 
 TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_OR_CombinationCondition) {
-    for (auto aggregationType : { DurationMetric::MAX_SPARSE}) { // DurationMetric::SUM,
+    for (auto aggregationType : { DurationMetric::MAX_SPARSE, DurationMetric::SUM}) {
         ConfigKey cfgKey;
         auto config = CreateDurationMetricConfig_NoLink_CombinationCondition(aggregationType);
         int64_t bucketStartTimeNs = 10000000000;
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index 5ef84e6..a75d6c8 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -40,7 +40,7 @@
 const ConfigKey kConfigKey(0, 12345);
 const int tagId = 1;
 const int64_t metricId = 123;
-const int64_t bucketStartTimeNs = 10000000000;
+const int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
 const int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
 const int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
 const int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
diff --git a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
index 9b27f3c..13cdb0b 100644
--- a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
@@ -44,7 +44,7 @@
 const HashableDimensionKey kConditionKey1 = getMockedDimensionKey(TagId, 1, "maps");
 const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
 const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
-const uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+const uint64_t bucketSizeNs = 30 * NS_PER_SEC;
 
 TEST(OringDurationTrackerTest, TestDurationOverlap) {
     const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "event");
@@ -370,6 +370,103 @@
               tracker.predictAnomalyTimestampNs(*anomalyTracker, event3StartTimeNs));
 }
 
+TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp2) {
+    vector<Matcher> dimensionInCondition;
+    Alert alert;
+    alert.set_id(101);
+    alert.set_metric_id(1);
+    alert.set_trigger_if_sum_gt(5 * NS_PER_SEC);
+    alert.set_num_buckets(1);
+    alert.set_refractory_period_secs(20);
+
+    uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
+    uint64_t bucketNum = 0;
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    sp<AlarmMonitor> alarmMonitor;
+    sp<DurationAnomalyTracker> anomalyTracker =
+        new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
+    OringDurationTracker tracker(kConfigKey, metricId, DEFAULT_METRIC_DIMENSION_KEY, wizard, 1,
+                                 dimensionInCondition,
+                                 true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
+                                 bucketSizeNs, true, false, {anomalyTracker});
+
+    uint64_t eventStartTimeNs = bucketStartTimeNs + 9 * NS_PER_SEC;
+    tracker.noteStart(DEFAULT_DIMENSION_KEY, true, eventStartTimeNs, ConditionKey());
+    // Anomaly happens in the bucket #1.
+    EXPECT_EQ((long long)(bucketStartTimeNs + 14 * NS_PER_SEC),
+              tracker.predictAnomalyTimestampNs(*anomalyTracker, eventStartTimeNs));
+
+    tracker.noteStop(DEFAULT_DIMENSION_KEY, bucketStartTimeNs + 14 * NS_PER_SEC, false);
+
+    EXPECT_EQ((long long)(bucketStartTimeNs + 34 * NS_PER_SEC) / NS_PER_SEC,
+              anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY));
+
+    uint64_t event2StartTimeNs = bucketStartTimeNs + 22 * NS_PER_SEC;
+    EXPECT_EQ((long long)(bucketStartTimeNs + 34 * NS_PER_SEC) / NS_PER_SEC,
+              anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY));
+    EXPECT_EQ((long long)(bucketStartTimeNs + 35 * NS_PER_SEC),
+              tracker.predictAnomalyTimestampNs(*anomalyTracker, event2StartTimeNs));
+}
+
+TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp3) {
+    // Test the cases where the refractory period is smaller than the bucket size, longer than
+    // the bucket size, and longer than 2x of the anomaly detection window.
+    for (int j = 0; j < 3; j++) {
+        uint64_t thresholdNs = j * bucketSizeNs + 5 * NS_PER_SEC;
+        for (int i = 0; i <= 7; ++i) {
+            vector<Matcher> dimensionInCondition;
+            Alert alert;
+            alert.set_id(101);
+            alert.set_metric_id(1);
+            alert.set_trigger_if_sum_gt(thresholdNs);
+            alert.set_num_buckets(3);
+            alert.set_refractory_period_secs(
+                bucketSizeNs / NS_PER_SEC / 2 + i * bucketSizeNs / NS_PER_SEC);
+
+            uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
+            uint64_t bucketNum = 101;
+
+            sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+            sp<AlarmMonitor> alarmMonitor;
+            sp<DurationAnomalyTracker> anomalyTracker =
+                new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
+            OringDurationTracker tracker(kConfigKey, metricId, DEFAULT_METRIC_DIMENSION_KEY,
+                                         wizard, 1, dimensionInCondition,
+                                         true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
+                                         bucketSizeNs, true, false, {anomalyTracker});
+
+            uint64_t eventStartTimeNs = bucketStartTimeNs + 9 * NS_PER_SEC;
+            tracker.noteStart(DEFAULT_DIMENSION_KEY, true, eventStartTimeNs, ConditionKey());
+            EXPECT_EQ((long long)(eventStartTimeNs + thresholdNs),
+                      tracker.predictAnomalyTimestampNs(*anomalyTracker, eventStartTimeNs));
+            uint64_t eventStopTimeNs = eventStartTimeNs + thresholdNs + NS_PER_SEC;
+            tracker.noteStop(DEFAULT_DIMENSION_KEY, eventStopTimeNs, false);
+
+            uint64_t refractoryPeriodEndSec =
+                anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY);
+            EXPECT_EQ((long long)(eventStopTimeNs) / NS_PER_SEC + alert.refractory_period_secs(),
+                       refractoryPeriodEndSec);
+
+            // Acquire and release a wakelock in the next bucket.
+            uint64_t event2StartTimeNs = eventStopTimeNs + bucketSizeNs;
+            tracker.noteStart(DEFAULT_DIMENSION_KEY, true, event2StartTimeNs, ConditionKey());
+            uint64_t event2StopTimeNs = event2StartTimeNs + 4 * NS_PER_SEC;
+            tracker.noteStop(DEFAULT_DIMENSION_KEY, event2StopTimeNs, false);
+
+            // Test the alarm prediction works well when seeing another wakelock start event.
+            for (int k = 0; k <= 2; ++k) {
+                uint64_t event3StartTimeNs = event2StopTimeNs + NS_PER_SEC + k * bucketSizeNs;
+                uint64_t alarmTimestampNs =
+                    tracker.predictAnomalyTimestampNs(*anomalyTracker, event3StartTimeNs);
+                EXPECT_GT(alarmTimestampNs, 0u);
+                EXPECT_GE(alarmTimestampNs, event3StartTimeNs);
+                EXPECT_GE(alarmTimestampNs, refractoryPeriodEndSec * NS_PER_SEC);
+            }
+        }
+    }
+}
+
 TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm) {
     const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "event");
 
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index 0f785df..ce44a35 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -447,7 +447,9 @@
 sp<StatsLogProcessor> CreateStatsLogProcessor(const long timeBaseSec, const StatsdConfig& config,
                                               const ConfigKey& key) {
     sp<UidMap> uidMap = new UidMap();
-    sp<AlarmMonitor> anomalyAlarmMonitor;
+    sp<AlarmMonitor> anomalyAlarmMonitor =
+        new AlarmMonitor(1,  [](const sp<IStatsCompanionService>&, int64_t){},
+                [](const sp<IStatsCompanionService>&){});
     sp<AlarmMonitor> periodicAlarmMonitor;
     sp<StatsLogProcessor> processor = new StatsLogProcessor(
         uidMap, anomalyAlarmMonitor, periodicAlarmMonitor, timeBaseSec, [](const ConfigKey&){});
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 8a9c738..8e2e43c 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -330,8 +330,6 @@
 Landroid/app/TaskStackListener;-><init>()V
 Landroid/app/TimePickerDialog;->mTimePicker:Landroid/widget/TimePicker;
 Landroid/app/trust/ITrustManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/app/usage/StorageStatsManager;->getFreeBytes(Ljava/lang/String;)J
-Landroid/app/usage/StorageStatsManager;->getTotalBytes(Ljava/lang/String;)J
 Landroid/app/usage/UsageStatsManager;->mService:Landroid/app/usage/IUsageStatsManager;
 Landroid/app/usage/UsageStats;->mLastEvent:I
 Landroid/app/usage/UsageStats;->mTotalTimeInForeground:J
@@ -824,56 +822,24 @@
 Landroid/hardware/usb/UsbRequest;->mLength:I
 Landroid/hardware/usb/UsbRequest;->mNativeContext:J
 Landroid/icu/impl/CurrencyData;-><init>()V
-Landroid/icu/impl/number/DecimalFormatProperties;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/impl/number/DecimalFormatProperties;->writeObject(Ljava/io/ObjectOutputStream;)V
-Landroid/icu/impl/TimeZoneGenericNames;->readObject(Ljava/io/ObjectInputStream;)V
 Landroid/icu/text/ArabicShaping;->isAlefMaksouraChar(C)Z
 Landroid/icu/text/ArabicShaping;->isSeenTailFamilyChar(C)I
 Landroid/icu/text/ArabicShaping;->isTailChar(C)Z
 Landroid/icu/text/ArabicShaping;->isYehHamzaChar(C)Z
-Landroid/icu/text/DateFormat;->readObject(Ljava/io/ObjectInputStream;)V
 Landroid/icu/text/DateFormatSymbols;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
-Landroid/icu/text/DateFormatSymbols;->readObject(Ljava/io/ObjectInputStream;)V
 Landroid/icu/text/DateIntervalFormat;-><init>()V
-Landroid/icu/text/DateIntervalFormat;->readObject(Ljava/io/ObjectInputStream;)V
 Landroid/icu/text/DateTimePatternGenerator$DistanceInfo;-><init>()V
-Landroid/icu/text/DecimalFormat_ICU58_Android;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/text/DecimalFormat_ICU58_Android;->writeObject(Ljava/io/ObjectOutputStream;)V
-Landroid/icu/text/DecimalFormat;->readObject(Ljava/io/ObjectInputStream;)V
 Landroid/icu/text/DecimalFormatSymbols;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
-Landroid/icu/text/DecimalFormatSymbols;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/text/DecimalFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
-Landroid/icu/text/MessageFormat;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/text/MessageFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
-Landroid/icu/text/NumberFormat;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/text/NumberFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
-Landroid/icu/text/PluralFormat;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/text/PluralRules$FixedDecimal;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/text/PluralRules$FixedDecimal;->writeObject(Ljava/io/ObjectOutputStream;)V
-Landroid/icu/text/PluralRules;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/text/PluralRules;->writeObject(Ljava/io/ObjectOutputStream;)V
 Landroid/icu/text/RuleBasedCollator;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
-Landroid/icu/text/RuleBasedNumberFormat;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/text/RuleBasedNumberFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
-Landroid/icu/text/SelectFormat;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/text/SimpleDateFormat;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/text/SimpleDateFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
 Landroid/icu/text/SpoofChecker$ScriptSet;->and(I)V
 Landroid/icu/text/SpoofChecker$ScriptSet;-><init>()V
 Landroid/icu/text/SpoofChecker$ScriptSet;->isFull()Z
 Landroid/icu/text/SpoofChecker$ScriptSet;->setAll()V
-Landroid/icu/text/TimeZoneFormat;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/text/TimeZoneFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
 Landroid/icu/text/TimeZoneNames$DefaultTimeZoneNames$FactoryImpl;-><init>()V
 Landroid/icu/text/Transliterator;->createFromRules(Ljava/lang/String;Ljava/lang/String;I)Landroid/icu/text/Transliterator;
 Landroid/icu/text/Transliterator;->transliterate(Ljava/lang/String;)Ljava/lang/String;
 Landroid/icu/text/UFormat;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
 Landroid/icu/util/Calendar;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
-Landroid/icu/util/Calendar;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/util/Calendar;->writeObject(Ljava/io/ObjectOutputStream;)V
-Landroid/icu/util/ChineseCalendar;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/util/IslamicCalendar;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/util/SimpleTimeZone;->readObject(Ljava/io/ObjectInputStream;)V
 Landroid/inputmethodservice/InputMethodService;->mExtractEditText:Landroid/inputmethodservice/ExtractEditText;
 Landroid/location/CountryDetector;->detectCountry()Landroid/location/Country;
 Landroid/location/Country;->getCountryIso()Ljava/lang/String;
@@ -1357,7 +1323,6 @@
 Landroid/os/storage/VolumeInfo;->getPath()Ljava/io/File;
 Landroid/os/storage/VolumeInfo;->getState()I
 Landroid/os/storage/VolumeInfo;->getType()I
-Landroid/os/storage/VolumeInfo;->isMountedReadable()Z
 Landroid/os/storage/VolumeInfo;->isPrimary()Z
 Landroid/os/storage/VolumeInfo;->isVisible()Z
 Landroid/os/StrictMode;->disableDeathOnFileUriExposure()V
@@ -1992,7 +1957,6 @@
 Landroid/util/Pools$SynchronizedPool;-><init>(I)V
 Landroid/util/Rational;->mDenominator:I
 Landroid/util/Rational;->mNumerator:I
-Landroid/util/Rational;->readObject(Ljava/io/ObjectInputStream;)V
 Landroid/util/Singleton;->mInstance:Ljava/lang/Object;
 Landroid/util/Slog;->d(Ljava/lang/String;Ljava/lang/String;)I
 Landroid/util/SparseIntArray;->mKeys:[I
@@ -2841,8 +2805,6 @@
 Lcom/android/okhttp/OkHttpClient;->dns:Lcom/android/okhttp/Dns;
 Lcom/android/okhttp/OkHttpClient;->setProtocols(Ljava/util/List;)Lcom/android/okhttp/OkHttpClient;
 Lcom/android/okhttp/OkHttpClient;->setRetryOnConnectionFailure(Z)V
-Lcom/android/okhttp/okio/ByteString;->readObject(Ljava/io/ObjectInputStream;)V
-Lcom/android/okhttp/okio/ByteString;->writeObject(Ljava/io/ObjectOutputStream;)V
 Lcom/android/okhttp/Request;->headers:Lcom/android/okhttp/Headers;
 Lcom/android/okhttp/Request;->method:Ljava/lang/String;
 Lcom/android/okhttp/Request;->url:Lcom/android/okhttp/HttpUrl;
@@ -2945,20 +2907,14 @@
 Ldalvik/system/VMRuntime;->vmLibrary()Ljava/lang/String;
 Ldalvik/system/VMStack;->getCallingClassLoader()Ljava/lang/ClassLoader;
 Ldalvik/system/VMStack;->getStackClass2()Ljava/lang/Class;
-Ljava/awt/font/NumericShaper;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/beans/PropertyChangeSupport;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/beans/PropertyChangeSupport;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/io/FileDescriptor;->descriptor:I
 Ljava/io/FileDescriptor;->getInt$()I
 Ljava/io/FileDescriptor;->setInt$(I)V
 Ljava/io/FileInputStream;->fd:Ljava/io/FileDescriptor;
 Ljava/io/FileOutputStream;->fd:Ljava/io/FileDescriptor;
-Ljava/io/File;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/io/File;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/io/ObjectStreamClass;->getConstructorId(Ljava/lang/Class;)J
 Ljava/io/ObjectStreamClass;->newInstance(Ljava/lang/Class;J)Ljava/lang/Object;
 Ljava/io/ObjectStreamClass;->newInstance()Ljava/lang/Object;
-Ljava/io/UncheckedIOException;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/lang/AbstractStringBuilder;->value:[C
 Ljava/lang/Boolean;->value:Z
 Ljava/lang/Byte;->value:B
@@ -2979,11 +2935,8 @@
 Ljava/lang/Daemons;->start()V
 Ljava/lang/Daemons;->stop()V
 Ljava/lang/Double;->value:D
-Ljava/lang/Enum;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/lang/Float;->value:F
 Ljava/lang/Integer;->value:I
-Ljava/lang/invoke/MethodType;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/lang/invoke/MethodType;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/lang/Long;->value:J
 Ljava/lang/ref/FinalizerReference;->add(Ljava/lang/Object;)V
 Ljava/lang/ref/FinalizerReference;->head:Ljava/lang/ref/FinalizerReference;
@@ -2999,10 +2952,6 @@
 Ljava/lang/Runtime;->load(Ljava/lang/String;Ljava/lang/ClassLoader;)V
 Ljava/lang/Runtime;->nativeLoad(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/String;
 Ljava/lang/Short;->value:S
-Ljava/lang/StringBuffer;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/lang/StringBuffer;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/lang/StringBuilder;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/lang/StringBuilder;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/lang/String;-><init>(II[C)V
 Ljava/lang/System;-><init>()V
 Ljava/lang/Thread;->daemon:Z
@@ -3026,16 +2975,9 @@
 Ljava/lang/Throwable;->cause:Ljava/lang/Throwable;
 Ljava/lang/Throwable;->detailMessage:Ljava/lang/String;
 Ljava/lang/Throwable;->nativeFillInStackTrace()Ljava/lang/Object;
-Ljava/lang/Throwable;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/lang/Throwable;->stackTrace:[Ljava/lang/StackTraceElement;
 Ljava/lang/Throwable;->suppressedExceptions:Ljava/util/List;
-Ljava/lang/Throwable;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/lang/Void;-><init>()V
-Ljava/math/BigDecimal;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/math/BigDecimal;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/math/BigInteger;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/math/BigInteger;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/math/MathContext;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/net/Authenticator;->theAuthenticator:Ljava/net/Authenticator;
 Ljava/net/DatagramSocket;->impl:Ljava/net/DatagramSocketImpl;
 Ljava/net/HttpCookie;->httpOnly:Z
@@ -3047,8 +2989,6 @@
 Ljava/net/Inet6Address$Inet6AddressHolder;->scope_id_set:Z
 Ljava/net/Inet6Address$Inet6AddressHolder;->scope_ifname:Ljava/net/NetworkInterface;
 Ljava/net/Inet6Address;-><init>()V
-Ljava/net/Inet6Address;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/net/Inet6Address;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/net/InetAddress;->clearDnsCache()V
 Ljava/net/InetAddress;->holder:Ljava/net/InetAddress$InetAddressHolder;
 Ljava/net/InetAddress$InetAddressHolder;->address:I
@@ -3057,19 +2997,11 @@
 Ljava/net/InetAddress$InetAddressHolder;->originalHostName:Ljava/lang/String;
 Ljava/net/InetAddress;->isNumeric(Ljava/lang/String;)Z
 Ljava/net/InetAddress;->parseNumericAddress(Ljava/lang/String;)Ljava/net/InetAddress;
-Ljava/net/InetAddress;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/net/InetAddress;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/net/InetSocketAddress;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/net/InetSocketAddress;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/net/Socket;->getFileDescriptor$()Ljava/io/FileDescriptor;
 Ljava/net/Socket;->impl:Ljava/net/SocketImpl;
 Ljava/net/URI;->host:Ljava/lang/String;
-Ljava/net/URI;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/net/URI;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/net/URL;->handler:Ljava/net/URLStreamHandler;
 Ljava/net/URL;->handlers:Ljava/util/Hashtable;
-Ljava/net/URL;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/net/URL;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/nio/Buffer;->address:J
 Ljava/nio/Buffer;->capacity:I
 Ljava/nio/Buffer;->_elementSizeShift:I
@@ -3080,168 +3012,37 @@
 Ljava/nio/ByteBuffer;->offset:I
 Ljava/nio/charset/CharsetEncoder;->canEncode(Ljava/nio/CharBuffer;)Z
 Ljava/nio/DirectByteBuffer;-><init>(JI)V
-Ljava/nio/file/DirectoryIteratorException;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/nio/NIOAccess;->getBaseArray(Ljava/nio/Buffer;)Ljava/lang/Object;
 Ljava/nio/NIOAccess;->getBaseArrayOffset(Ljava/nio/Buffer;)I
 Ljava/nio/NIOAccess;->getBasePointer(Ljava/nio/Buffer;)J
-Ljava/security/cert/CertificateRevokedException;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/security/cert/CertificateRevokedException;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/security/cert/CertPathValidatorException;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/security/CodeSigner;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/security/GuardedObject;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/security/Provider;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/security/SignedObject;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/security/spec/ECParameterSpec;->getCurveName()Ljava/lang/String;
 Ljava/security/spec/ECParameterSpec;->setCurveName(Ljava/lang/String;)V
-Ljava/security/Timestamp;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/text/ChoiceFormat;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/text/DateFormat;->is24Hour:Ljava/lang/Boolean;
-Ljava/text/DateFormatSymbols;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/text/DateFormatSymbols;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/text/DecimalFormat;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/text/DecimalFormatSymbols;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/text/DecimalFormatSymbols;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/text/DecimalFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/text/MessageFormat;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/text/NumberFormat;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/text/NumberFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/text/SimpleDateFormat;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/chrono/AbstractChronology;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/chrono/HijrahChronology;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/chrono/HijrahDate;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/chrono/IsoChronology;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/chrono/JapaneseChronology;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/chrono/JapaneseDate;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/chrono/JapaneseEra;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/chrono/MinguoChronology;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/chrono/MinguoDate;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/chrono/ThaiBuddhistChronology;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/chrono/ThaiBuddhistDate;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/Duration;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/time/Duration;->toSeconds()Ljava/math/BigDecimal;
-Ljava/time/Instant;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/LocalDate;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/LocalDateTime;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/LocalTime;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/MonthDay;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/time/OffsetDateTime;-><init>(Ljava/time/LocalDateTime;Ljava/time/ZoneOffset;)V
-Ljava/time/OffsetDateTime;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/OffsetTime;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/Period;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/temporal/ValueRange;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/temporal/WeekFields;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/YearMonth;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/Year;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/ZonedDateTime;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/ZoneId;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/ZoneOffset;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/zone/ZoneOffsetTransition;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/zone/ZoneOffsetTransitionRule;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/zone/ZoneRules;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/ArrayDeque;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/ArrayDeque;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/ArrayList;->elementData:[Ljava/lang/Object;
-Ljava/util/ArrayList;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/util/ArrayList;->size:I
 Ljava/util/ArrayList$SubList;->parent:Ljava/util/AbstractList;
 Ljava/util/ArrayList$SubList;->parentOffset:I
 Ljava/util/ArrayList$SubList;->size:I
-Ljava/util/ArrayList;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/Arrays$ArrayList;->a:[Ljava/lang/Object;
-Ljava/util/BitSet;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/BitSet;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/Calendar;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/Calendar;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/Calendar;->zone:Ljava/util/TimeZone;
 Ljava/util/Collections$EmptyList;-><init>()V
-Ljava/util/Collections$SetFromMap;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/util/Collections$SynchronizedCollection;->c:Ljava/util/Collection;
-Ljava/util/Collections$SynchronizedCollection;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/Collections$SynchronizedMap;->m:Ljava/util/Map;
-Ljava/util/Collections$SynchronizedMap;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/Collections$UnmodifiableCollection;->c:Ljava/util/Collection;
 Ljava/util/Collections$UnmodifiableMap;->m:Ljava/util/Map;
-Ljava/util/concurrent/atomic/AtomicReferenceArray;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/atomic/DoubleAccumulator;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/atomic/DoubleAdder;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/atomic/LongAccumulator;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/atomic/LongAdder;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/util/concurrent/ConcurrentHashMap$BaseIterator;->hasMoreElements()Z
-Ljava/util/concurrent/ConcurrentHashMap;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/ConcurrentHashMap;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/concurrent/ConcurrentLinkedDeque;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/ConcurrentLinkedDeque;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/concurrent/ConcurrentLinkedQueue;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/ConcurrentLinkedQueue;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/concurrent/ConcurrentSkipListMap;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/ConcurrentSkipListMap;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/concurrent/CopyOnWriteArrayList;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/CopyOnWriteArrayList;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/concurrent/ForkJoinTask;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/ForkJoinTask;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/concurrent/FutureTask;->callable:Ljava/util/concurrent/Callable;
-Ljava/util/concurrent/LinkedBlockingDeque;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/LinkedBlockingDeque;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/concurrent/LinkedBlockingQueue;->capacity:I
-Ljava/util/concurrent/LinkedBlockingQueue;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/LinkedBlockingQueue;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/concurrent/LinkedTransferQueue;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/LinkedTransferQueue;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/concurrent/locks/ReentrantLock$Sync;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/locks/ReentrantReadWriteLock$Sync;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/locks/StampedLock;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/PriorityBlockingQueue;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/PriorityBlockingQueue;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/concurrent/SynchronousQueue;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/SynchronousQueue;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/concurrent/ThreadLocalRandom;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/Date;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/Date;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/EnumMap;->keyType:Ljava/lang/Class;
-Ljava/util/EnumMap;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/EnumMap;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/EnumSet;->elementType:Ljava/lang/Class;
-Ljava/util/EnumSet;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/GregorianCalendar;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/util/HashMap$HashIterator;->hasNext()Z
-Ljava/util/HashMap;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/HashMap;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/HashSet;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/HashSet;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/Hashtable;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/Hashtable;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/IdentityHashMap;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/IdentityHashMap;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/InvalidPropertiesFormatException;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/InvalidPropertiesFormatException;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/LinkedHashMap;->eldest()Ljava/util/Map$Entry;
 Ljava/util/LinkedHashMap$LinkedHashIterator;->hasNext()Z
-Ljava/util/LinkedList;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/LinkedList;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/Locale;->createConstant(Ljava/lang/String;Ljava/lang/String;)Ljava/util/Locale;
-Ljava/util/Locale;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/Locale;->readResolve()Ljava/lang/Object;
-Ljava/util/Locale;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/logging/LogRecord;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/logging/LogRecord;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/prefs/NodeChangeEvent;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/prefs/NodeChangeEvent;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/prefs/PreferenceChangeEvent;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/prefs/PreferenceChangeEvent;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/PriorityQueue;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/PriorityQueue;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/Random;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/util/Random;->seedUniquifier()J
-Ljava/util/Random;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/regex/Matcher;->appendPos:I
-Ljava/util/regex/Pattern;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/SimpleTimeZone;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/SimpleTimeZone;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/TreeMap;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/TreeMap;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/TreeSet;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/TreeSet;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/Vector;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/zip/Deflater;->buf:[B
 Ljava/util/zip/Deflater;->finished:Z
 Ljava/util/zip/Deflater;->finish:Z
@@ -3257,23 +3058,11 @@
 Ljava/util/zip/Inflater;->off:I
 Ljava/util/zip/ZipEntry;-><init>(Ljava/lang/String;Ljava/lang/String;JJJII[BJ)V
 Ljava/util/zip/ZipFile;->jzfile:J
-Ljavax/crypto/SealedObject;->readObject(Ljava/io/ObjectInputStream;)V
 Ljavax/net/ssl/SSLServerSocketFactory;->defaultServerSocketFactory:Ljavax/net/ssl/SSLServerSocketFactory;
 Ljavax/net/ssl/SSLSocketFactory;->defaultSocketFactory:Ljavax/net/ssl/SSLSocketFactory;
-Ljavax/security/auth/Subject;->readObject(Ljava/io/ObjectInputStream;)V
-Ljavax/security/auth/Subject$SecureSet;->readObject(Ljava/io/ObjectInputStream;)V
-Ljavax/security/auth/Subject$SecureSet;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljavax/security/auth/Subject;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljavax/security/auth/x500/X500Principal;->readObject(Ljava/io/ObjectInputStream;)V
-Ljavax/security/auth/x500/X500Principal;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljavax/xml/datatype/DatatypeConfigurationException;->readObject(Ljava/io/ObjectInputStream;)V
-Ljavax/xml/namespace/QName;->readObject(Ljava/io/ObjectInputStream;)V
 Llibcore/util/ZoneInfo;->mTransitions:[J
-Llibcore/util/ZoneInfo;->readObject(Ljava/io/ObjectInputStream;)V
 Lorg/apache/http/conn/ssl/SSLSocketFactory;-><init>(Ljavax/net/ssl/SSLSocketFactory;)V
 Lorg/apache/http/conn/ssl/SSLSocketFactory;-><init>()V
 Lorg/json/JSONArray;->values:Ljava/util/List;
 Lorg/json/JSONObject;->writeTo(Lorg/json/JSONStringer;)V
 Lsun/misc/Unsafe;->theUnsafe:Lsun/misc/Unsafe;
-Lsun/security/util/ObjectIdentifier;->readObject(Ljava/io/ObjectInputStream;)V
-Lsun/security/util/ObjectIdentifier;->writeObject(Ljava/io/ObjectOutputStream;)V
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 4cb7f89..3015398 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -8610,6 +8610,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
     @UserProvisioningState
     public int getUserProvisioningState() {
         throwIfParentInstance("getUserProvisioningState");
@@ -8754,6 +8755,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
     public boolean isDeviceProvisioned() {
         try {
             return mService.isDeviceProvisioned();
@@ -9418,7 +9420,21 @@
      * <p>This method may returns {@code -1} if {@code apnSetting} conflicts with an existing
      * override APN. Update the existing conflicted APN with
      * {@link #updateOverrideApn(ComponentName, int, ApnSetting)} instead of adding a new entry.
-     * <p>See {@link ApnSetting} for the definition of conflict.
+     * <p>Two override APNs are considered to conflict when all the following APIs return
+     * the same values on both override APNs:
+     * <ul>
+     *   <li>{@link ApnSetting#getOperatorNumeric()}</li>
+     *   <li>{@link ApnSetting#getApnName()}</li>
+     *   <li>{@link ApnSetting#getProxyAddress()}</li>
+     *   <li>{@link ApnSetting#getProxyPort()}</li>
+     *   <li>{@link ApnSetting#getMmsProxyAddress()}</li>
+     *   <li>{@link ApnSetting#getMmsProxyPort()}</li>
+     *   <li>{@link ApnSetting#getMmsc()}</li>
+     *   <li>{@link ApnSetting#isEnabled()}</li>
+     *   <li>{@link ApnSetting#getMvnoType()}</li>
+     *   <li>{@link ApnSetting#getProtocol()}</li>
+     *   <li>{@link ApnSetting#getRoamingProtocol()}</li>
+     * </ul>
      *
      * @param admin which {@link DeviceAdminReceiver} this request is associated with
      * @param apnSetting the override APN to insert
@@ -9447,7 +9463,7 @@
      * {@code apnId}.
      * <p>This method may also returns {@code false} if {@code apnSetting} conflicts with an
      * existing override APN. Update the existing conflicted APN instead.
-     * <p>See {@link ApnSetting} for the definition of conflict.
+     * <p>See {@link #addOverrideApn} for the definition of conflict.
      *
      * @param admin which {@link DeviceAdminReceiver} this request is associated with
      * @param apnId the {@code id} of the override APN to update
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index ee13880..02afcc7 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -65,7 +65,6 @@
             NETWORK_TYPE_UNMETERED,
             NETWORK_TYPE_NOT_ROAMING,
             NETWORK_TYPE_CELLULAR,
-            NETWORK_TYPE_METERED,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface NetworkType {}
@@ -253,7 +252,7 @@
     /**
      * @hide
      */
-    public static final int FLAG_IS_PREFETCH = 1 << 2;
+    public static final int FLAG_PREFETCH = 1 << 2;
 
     /**
      * This job needs to be exempted from the app standby throttling. Only the system (UID 1000)
@@ -296,7 +295,8 @@
     private final boolean hasEarlyConstraint;
     private final boolean hasLateConstraint;
     private final NetworkRequest networkRequest;
-    private final long networkBytes;
+    private final long networkDownloadBytes;
+    private final long networkUploadBytes;
     private final long minLatencyMillis;
     private final long maxExecutionDelayMillis;
     private final boolean isPeriodic;
@@ -317,30 +317,28 @@
     }
 
     /**
-     * Bundle of extras which are returned to your application at execution time.
+     * @see JobInfo.Builder#setExtras(PersistableBundle)
      */
     public @NonNull PersistableBundle getExtras() {
         return extras;
     }
 
     /**
-     * Bundle of transient extras which are returned to your application at execution time,
-     * but not persisted by the system.
+     * @see JobInfo.Builder#setTransientExtras(Bundle)
      */
     public @NonNull Bundle getTransientExtras() {
         return transientExtras;
     }
 
     /**
-     * ClipData of information that is returned to your application at execution time,
-     * but not persisted by the system.
+     * @see JobInfo.Builder#setClipData(ClipData, int)
      */
     public @Nullable ClipData getClipData() {
         return clipData;
     }
 
     /**
-     * Permission grants that go along with {@link #getClipData}.
+     * @see JobInfo.Builder#setClipData(ClipData, int)
      */
     public int getClipGrantFlags() {
         return clipGrantFlags;
@@ -369,32 +367,28 @@
     }
 
     /**
-     * Whether this job requires that the device be charging (or be a non-battery-powered
-     * device connected to permanent power, such as Android TV devices).
+     * @see JobInfo.Builder#setRequiresCharging(boolean)
      */
     public boolean isRequireCharging() {
         return (constraintFlags & CONSTRAINT_FLAG_CHARGING) != 0;
     }
 
     /**
-     * Whether this job needs the device's battery level to not be at below the critical threshold.
+     * @see JobInfo.Builder#setRequiresBatteryNotLow(boolean)
      */
     public boolean isRequireBatteryNotLow() {
         return (constraintFlags & CONSTRAINT_FLAG_BATTERY_NOT_LOW) != 0;
     }
 
     /**
-     * Whether this job requires that the user <em>not</em> be interacting with the device.
-     *
-     * <p class="note">This is <em>not</em> the same as "doze" or "device idle";
-     * it is purely about the user's direct interactions.</p>
+     * @see JobInfo.Builder#setRequiresDeviceIdle(boolean)
      */
     public boolean isRequireDeviceIdle() {
         return (constraintFlags & CONSTRAINT_FLAG_DEVICE_IDLE) != 0;
     }
 
     /**
-     * Whether this job needs the device's storage to not be low.
+     * @see JobInfo.Builder#setRequiresStorageNotLow(boolean)
      */
     public boolean isRequireStorageNotLow() {
         return (constraintFlags & CONSTRAINT_FLAG_STORAGE_NOT_LOW) != 0;
@@ -410,6 +404,7 @@
     /**
      * Which content: URIs must change for the job to be scheduled.  Returns null
      * if there are none required.
+     * @see JobInfo.Builder#addTriggerContentUri(TriggerContentUri)
      */
     public @Nullable TriggerContentUri[] getTriggerContentUris() {
         return triggerContentUris;
@@ -418,6 +413,7 @@
     /**
      * When triggering on content URI changes, this is the delay from when a change
      * is detected until the job is scheduled.
+     * @see JobInfo.Builder#setTriggerContentUpdateDelay(long)
      */
     public long getTriggerContentUpdateDelay() {
         return triggerContentUpdateDelay;
@@ -426,6 +422,7 @@
     /**
      * When triggering on content URI changes, this is the maximum delay we will
      * use before scheduling the job.
+     * @see JobInfo.Builder#setTriggerContentMaxDelay(long)
      */
     public long getTriggerContentMaxDelay() {
         return triggerContentMaxDelay;
@@ -466,28 +463,59 @@
     }
 
     /**
-     * Return the estimated size of network traffic that will be performed by
+     * @deprecated replaced by {@link #getEstimatedNetworkDownloadBytes()} and
+     *             {@link #getEstimatedNetworkUploadBytes()}.
+     * @removed
+     */
+    @Deprecated
+    public @BytesLong long getEstimatedNetworkBytes() {
+        if (networkDownloadBytes == NETWORK_BYTES_UNKNOWN
+                && networkUploadBytes == NETWORK_BYTES_UNKNOWN) {
+            return NETWORK_BYTES_UNKNOWN;
+        } else if (networkDownloadBytes == NETWORK_BYTES_UNKNOWN) {
+            return networkUploadBytes;
+        } else if (networkUploadBytes == NETWORK_BYTES_UNKNOWN) {
+            return networkDownloadBytes;
+        } else {
+            return networkDownloadBytes + networkUploadBytes;
+        }
+    }
+
+    /**
+     * Return the estimated size of download traffic that will be performed by
      * this job, in bytes.
      *
-     * @return Estimated size of network traffic, or
+     * @return Estimated size of download traffic, or
      *         {@link #NETWORK_BYTES_UNKNOWN} when unknown.
-     * @see Builder#setEstimatedNetworkBytes(long)
+     * @see Builder#setEstimatedNetworkBytes(long, long)
      */
-    public @BytesLong long getEstimatedNetworkBytes() {
-        return networkBytes;
+    public @BytesLong long getEstimatedNetworkDownloadBytes() {
+        return networkDownloadBytes;
+    }
+
+    /**
+     * Return the estimated size of upload traffic that will be performed by
+     * this job, in bytes.
+     *
+     * @return Estimated size of upload traffic, or
+     *         {@link #NETWORK_BYTES_UNKNOWN} when unknown.
+     * @see Builder#setEstimatedNetworkBytes(long, long)
+     */
+    public @BytesLong long getEstimatedNetworkUploadBytes() {
+        return networkUploadBytes;
     }
 
     /**
      * Set for a job that does not recur periodically, to specify a delay after which the job
      * will be eligible for execution. This value is not set if the job recurs periodically.
+     * @see JobInfo.Builder#setMinimumLatency(long)
      */
     public long getMinLatencyMillis() {
         return minLatencyMillis;
     }
 
     /**
-     * See {@link Builder#setOverrideDeadline(long)}. This value is not set if the job recurs
-     * periodically.
+     * @see JobInfo.Builder#setOverrideDeadline(long)
      */
     public long getMaxExecutionDelayMillis() {
         return maxExecutionDelayMillis;
@@ -495,13 +523,15 @@
 
     /**
      * Track whether this job will repeat with a given period.
+     * @see JobInfo.Builder#setPeriodic(long)
+     * @see JobInfo.Builder#setPeriodic(long, long)
      */
     public boolean isPeriodic() {
         return isPeriodic;
     }
 
     /**
-     * @return Whether or not this job should be persisted across device reboots.
+     * @see JobInfo.Builder#setPersisted(boolean)
      */
     public boolean isPersisted() {
         return isPersisted;
@@ -510,6 +540,8 @@
     /**
      * Set to the interval between occurrences of this job. This value is <b>not</b> set if the
      * job does not recur periodically.
+     * @see JobInfo.Builder#setPeriodic(long)
+     * @see JobInfo.Builder#setPeriodic(long, long)
      */
     public long getIntervalMillis() {
         return intervalMillis;
@@ -518,6 +550,8 @@
     /**
      * Flex time for this job. Only valid if this is a periodic job.  The job can
      * execute at any time in a window of flex length at the end of the period.
+     * @see JobInfo.Builder#setPeriodic(long)
+     * @see JobInfo.Builder#setPeriodic(long, long)
      */
     public long getFlexMillis() {
         return flexMillis;
@@ -527,6 +561,7 @@
      * The amount of time the JobScheduler will wait before rescheduling a failed job. This value
      * will be increased depending on the backoff policy specified at job creation time. Defaults
      * to 30 seconds, minimum is currently 10 seconds.
+     * @see JobInfo.Builder#setBackoffCriteria(long, int)
      */
     public long getInitialBackoffMillis() {
         return initialBackoffMillis;
@@ -534,12 +569,27 @@
 
     /**
      * Return the backoff policy of this job.
+     * @see JobInfo.Builder#setBackoffCriteria(long, int)
      */
     public @BackoffPolicy int getBackoffPolicy() {
         return backoffPolicy;
     }
 
     /**
+     * @see JobInfo.Builder#setImportantWhileForeground(boolean)
+     */
+    public boolean isImportantWhileForeground() {
+        return (flags & FLAG_IMPORTANT_WHILE_FOREGROUND) != 0;
+    }
+
+    /**
+     * @see JobInfo.Builder#setPrefetch(boolean)
+     */
+    public boolean isPrefetch() {
+        return (flags & FLAG_PREFETCH) != 0;
+    }
+
+    /**
      * User can specify an early constraint of 0L, which is valid, so we keep track of whether the
      * function was called at all.
      * @hide
@@ -610,7 +660,10 @@
         if (!Objects.equals(networkRequest, j.networkRequest)) {
             return false;
         }
-        if (networkBytes != j.networkBytes) {
+        if (networkDownloadBytes != j.networkDownloadBytes) {
+            return false;
+        }
+        if (networkUploadBytes != j.networkUploadBytes) {
             return false;
         }
         if (minLatencyMillis != j.minLatencyMillis) {
@@ -673,7 +726,8 @@
         if (networkRequest != null) {
             hashCode = 31 * hashCode + networkRequest.hashCode();
         }
-        hashCode = 31 * hashCode + Long.hashCode(networkBytes);
+        hashCode = 31 * hashCode + Long.hashCode(networkDownloadBytes);
+        hashCode = 31 * hashCode + Long.hashCode(networkUploadBytes);
         hashCode = 31 * hashCode + Long.hashCode(minLatencyMillis);
         hashCode = 31 * hashCode + Long.hashCode(maxExecutionDelayMillis);
         hashCode = 31 * hashCode + Boolean.hashCode(isPeriodic);
@@ -708,7 +762,8 @@
         } else {
             networkRequest = null;
         }
-        networkBytes = in.readLong();
+        networkDownloadBytes = in.readLong();
+        networkUploadBytes = in.readLong();
         minLatencyMillis = in.readLong();
         maxExecutionDelayMillis = in.readLong();
         isPeriodic = in.readInt() == 1;
@@ -737,7 +792,8 @@
         triggerContentUpdateDelay = b.mTriggerContentUpdateDelay;
         triggerContentMaxDelay = b.mTriggerContentMaxDelay;
         networkRequest = b.mNetworkRequest;
-        networkBytes = b.mNetworkBytes;
+        networkDownloadBytes = b.mNetworkDownloadBytes;
+        networkUploadBytes = b.mNetworkUploadBytes;
         minLatencyMillis = b.mMinLatencyMillis;
         maxExecutionDelayMillis = b.mMaxExecutionDelayMillis;
         isPeriodic = b.mIsPeriodic;
@@ -780,7 +836,8 @@
         } else {
             out.writeInt(0);
         }
-        out.writeLong(networkBytes);
+        out.writeLong(networkDownloadBytes);
+        out.writeLong(networkUploadBytes);
         out.writeLong(minLatencyMillis);
         out.writeLong(maxExecutionDelayMillis);
         out.writeInt(isPeriodic ? 1 : 0);
@@ -914,7 +971,8 @@
         // Requirements.
         private int mConstraintFlags;
         private NetworkRequest mNetworkRequest;
-        private long mNetworkBytes = NETWORK_BYTES_UNKNOWN;
+        private long mNetworkDownloadBytes = NETWORK_BYTES_UNKNOWN;
+        private long mNetworkUploadBytes = NETWORK_BYTES_UNKNOWN;
         private ArrayList<TriggerContentUri> mTriggerContentUris;
         private long mTriggerContentUpdateDelay = -1;
         private long mTriggerContentMaxDelay = -1;
@@ -965,6 +1023,7 @@
         /**
          * Set optional extras. This is persisted, so we only allow primitive types.
          * @param extras Bundle containing extras you want the scheduler to hold on to for you.
+         * @see JobInfo#getExtras()
          */
         public Builder setExtras(@NonNull PersistableBundle extras) {
             mExtras = extras;
@@ -979,6 +1038,7 @@
          * {@link android.app.job.JobInfo.Builder#build()} is called.</p>
          *
          * @param extras Bundle containing extras you want the scheduler to hold on to for you.
+         * @see JobInfo#getTransientExtras()
          */
         public Builder setTransientExtras(@NonNull Bundle extras) {
             mTransientExtras = extras;
@@ -1006,6 +1066,8 @@
          * a combination of {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION},
          * {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION}, and
          * {@link android.content.Intent#FLAG_GRANT_PREFIX_URI_PERMISSION}.
+         * @see JobInfo#getClipData()
+         * @see JobInfo#getClipGrantFlags()
          */
         public Builder setClipData(@Nullable ClipData clip, int grantFlags) {
             mClipData = clip;
@@ -1096,6 +1158,16 @@
         }
 
         /**
+         * @deprecated replaced by
+         *             {@link #setEstimatedNetworkBytes(long, long)}.
+         * @removed
+         */
+        @Deprecated
+        public Builder setEstimatedNetworkBytes(@BytesLong long networkBytes) {
+            return setEstimatedNetworkBytes(networkBytes, NETWORK_BYTES_UNKNOWN);
+        }
+
+        /**
          * Set the estimated size of network traffic that will be performed by
          * this job, in bytes.
          * <p>
@@ -1112,23 +1184,30 @@
          * <li>A job that synchronizes email could end up using an extreme range
          * of data, from under 1KB when nothing has changed, to dozens of MB
          * when there are new emails with attachments. Jobs that cannot provide
-         * reasonable estimates should leave this estimated value undefined.
+         * reasonable estimates should use the sentinel value
+         * {@link JobInfo#NETWORK_BYTES_UNKNOWN}.
          * </ul>
          * Note that the system may choose to delay jobs with large network
          * usage estimates when the device has a poor network connection, in
          * order to save battery.
+         * <p>
+         * The values provided here only reflect the traffic that will be
+         * performed by the base job; if you're using {@link JobWorkItem} then
+         * you also need to define the network traffic used by each work item
+         * when constructing them.
          *
-         * @param networkBytes The estimated size of network traffic that will
-         *            be performed by this job, in bytes. This value only
-         *            reflects the traffic that will be performed by the base
-         *            job; if you're using {@link JobWorkItem} then you also
-         *            need to define the network traffic used by each work item
-         *            when constructing them.
-         * @see JobInfo#getEstimatedNetworkBytes()
-         * @see JobWorkItem#JobWorkItem(android.content.Intent, long)
+         * @param downloadBytes The estimated size of network traffic that will
+         *            be downloaded by this job, in bytes.
+         * @param uploadBytes The estimated size of network traffic that will be
+         *            uploaded by this job, in bytes.
+         * @see JobInfo#getEstimatedNetworkDownloadBytes()
+         * @see JobInfo#getEstimatedNetworkUploadBytes()
+         * @see JobWorkItem#JobWorkItem(android.content.Intent, long, long)
          */
-        public Builder setEstimatedNetworkBytes(@BytesLong long networkBytes) {
-            mNetworkBytes = networkBytes;
+        public Builder setEstimatedNetworkBytes(@BytesLong long downloadBytes,
+                @BytesLong long uploadBytes) {
+            mNetworkDownloadBytes = downloadBytes;
+            mNetworkUploadBytes = uploadBytes;
             return this;
         }
 
@@ -1146,6 +1225,7 @@
          *
          * @param requiresCharging Pass {@code true} to require that the device be
          *     charging in order to run the job.
+         * @see JobInfo#isRequireCharging()
          */
         public Builder setRequiresCharging(boolean requiresCharging) {
             mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_CHARGING)
@@ -1159,6 +1239,7 @@
          * is not low, which is generally the point where the user is given a "low battery"
          * warning.
          * @param batteryNotLow Whether or not the device's battery level must not be low.
+         * @see JobInfo#isRequireBatteryNotLow()
          */
         public Builder setRequiresBatteryNotLow(boolean batteryNotLow) {
             mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_BATTERY_NOT_LOW)
@@ -1183,6 +1264,7 @@
          *
          * @param requiresDeviceIdle Pass {@code true} to prevent the job from running
          *     while the device is being used interactively.
+         * @see JobInfo#isRequireDeviceIdle()
          */
         public Builder setRequiresDeviceIdle(boolean requiresDeviceIdle) {
             mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_DEVICE_IDLE)
@@ -1196,6 +1278,7 @@
          * in a low storage state, which is generally the point where the user is given a
          * "low storage" warning.
          * @param storageNotLow Whether or not the device's available storage must not be low.
+         * @see JobInfo#isRequireStorageNotLow()
          */
         public Builder setRequiresStorageNotLow(boolean storageNotLow) {
             mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_STORAGE_NOT_LOW)
@@ -1228,6 +1311,7 @@
          *      job}
          *
          * @param uri The content: URI to monitor.
+         * @see JobInfo#getTriggerContentUris()
          */
         public Builder addTriggerContentUri(@NonNull TriggerContentUri uri) {
             if (mTriggerContentUris == null) {
@@ -1242,6 +1326,7 @@
          * the job is scheduled.  If there are more changes during that time, the delay
          * will be reset to start at the time of the most recent change.
          * @param durationMs Delay after most recent content change, in milliseconds.
+         * @see JobInfo#getTriggerContentUpdateDelay()
          */
         public Builder setTriggerContentUpdateDelay(long durationMs) {
             mTriggerContentUpdateDelay = durationMs;
@@ -1252,6 +1337,7 @@
          * Set the maximum total delay (in milliseconds) that is allowed from the first
          * time a content change is detected until the job is scheduled.
          * @param durationMs Delay after initial content change, in milliseconds.
+         * @see JobInfo#getTriggerContentMaxDelay()
          */
         public Builder setTriggerContentMaxDelay(long durationMs) {
             mTriggerContentMaxDelay = durationMs;
@@ -1265,6 +1351,8 @@
          * Setting this function on the builder with {@link #setMinimumLatency(long)} or
          * {@link #setOverrideDeadline(long)} will result in an error.
          * @param intervalMillis Millisecond interval for which this job will repeat.
+         * @see JobInfo#getIntervalMillis()
+         * @see JobInfo#getFlexMillis()
          */
         public Builder setPeriodic(long intervalMillis) {
             return setPeriodic(intervalMillis, intervalMillis);
@@ -1278,6 +1366,8 @@
          * @param flexMillis Millisecond flex for this job. Flex is clamped to be at least
          *                   {@link #getMinFlexMillis()} or 5 percent of the period, whichever is
          *                   higher.
+         * @see JobInfo#getIntervalMillis()
+         * @see JobInfo#getFlexMillis()
          */
         public Builder setPeriodic(long intervalMillis, long flexMillis) {
             final long minPeriod = getMinPeriodMillis();
@@ -1309,6 +1399,7 @@
          * {@link android.app.job.JobInfo.Builder#build()} is called.
          * @param minLatencyMillis Milliseconds before which this job will not be considered for
          *                         execution.
+         * @see JobInfo#getMinLatencyMillis()
          */
         public Builder setMinimumLatency(long minLatencyMillis) {
             mMinLatencyMillis = minLatencyMillis;
@@ -1322,6 +1413,7 @@
          * this property on a periodic job, doing so will throw an
          * {@link java.lang.IllegalArgumentException} when
          * {@link android.app.job.JobInfo.Builder#build()} is called.
+         * @see JobInfo#getMaxExecutionDelayMillis()
          */
         public Builder setOverrideDeadline(long maxExecutionDelayMillis) {
             mMaxExecutionDelayMillis = maxExecutionDelayMillis;
@@ -1341,6 +1433,8 @@
          * mode.
          * @param initialBackoffMillis Millisecond time interval to wait initially when job has
          *                             failed.
+         * @see JobInfo#getInitialBackoffMillis()
+         * @see JobInfo#getBackoffPolicy()
          */
         public Builder setBackoffCriteria(long initialBackoffMillis,
                 @BackoffPolicy int backoffPolicy) {
@@ -1371,6 +1465,7 @@
          *
          * @param importantWhileForeground whether to relax doze restrictions for this job when the
          *                                 app is in the foreground. False by default.
+         * @see JobInfo#isImportantWhileForeground()
          */
         public Builder setImportantWhileForeground(boolean importantWhileForeground) {
             if (importantWhileForeground) {
@@ -1382,6 +1477,15 @@
         }
 
         /**
+         * @removed
+         * @deprecated replaced with {@link #setPrefetch(boolean)}
+         */
+        @Deprecated
+        public Builder setIsPrefetch(boolean isPrefetch) {
+            return setPrefetch(isPrefetch);
+        }
+
+        /**
          * Setting this to true indicates that this job is designed to prefetch
          * content that will make a material improvement to the experience of
          * the specific user of this device. For example, fetching top headlines
@@ -1393,12 +1497,13 @@
          * network when there is a surplus of metered data available. The system
          * may also use this signal in combination with end user usage patterns
          * to ensure data is prefetched before the user launches your app.
+         * @see JobInfo#isPrefetch()
          */
-        public Builder setIsPrefetch(boolean isPrefetch) {
-            if (isPrefetch) {
-                mFlags |= FLAG_IS_PREFETCH;
+        public Builder setPrefetch(boolean prefetch) {
+            if (prefetch) {
+                mFlags |= FLAG_PREFETCH;
             } else {
-                mFlags &= (~FLAG_IS_PREFETCH);
+                mFlags &= (~FLAG_PREFETCH);
             }
             return this;
         }
@@ -1408,6 +1513,7 @@
          *
          * @param isPersisted True to indicate that the job will be written to
          *            disk and loaded at boot.
+         * @see JobInfo#isPersisted()
          */
         @RequiresPermission(android.Manifest.permission.RECEIVE_BOOT_COMPLETED)
         public Builder setPersisted(boolean isPersisted) {
@@ -1427,7 +1533,7 @@
                         "constraints, this is not allowed.");
             }
             // Check that network estimates require network type
-            if (mNetworkBytes > 0 && mNetworkRequest == null) {
+            if ((mNetworkDownloadBytes > 0 || mNetworkUploadBytes > 0) && mNetworkRequest == null) {
                 throw new IllegalArgumentException(
                         "Can't provide estimated network usage without requiring a network");
             }
diff --git a/core/java/android/app/job/JobWorkItem.java b/core/java/android/app/job/JobWorkItem.java
index 1c46e8e..995f522 100644
--- a/core/java/android/app/job/JobWorkItem.java
+++ b/core/java/android/app/job/JobWorkItem.java
@@ -16,6 +16,8 @@
 
 package android.app.job;
 
+import static android.app.job.JobInfo.NETWORK_BYTES_UNKNOWN;
+
 import android.annotation.BytesLong;
 import android.content.Intent;
 import android.os.Parcel;
@@ -28,7 +30,8 @@
  */
 final public class JobWorkItem implements Parcelable {
     final Intent mIntent;
-    final long mNetworkBytes;
+    final long mNetworkDownloadBytes;
+    final long mNetworkUploadBytes;
     int mDeliveryCount;
     int mWorkId;
     Object mGrants;
@@ -41,22 +44,36 @@
      */
     public JobWorkItem(Intent intent) {
         mIntent = intent;
-        mNetworkBytes = JobInfo.NETWORK_BYTES_UNKNOWN;
+        mNetworkDownloadBytes = NETWORK_BYTES_UNKNOWN;
+        mNetworkUploadBytes = NETWORK_BYTES_UNKNOWN;
+    }
+
+    /**
+     * @deprecated replaced by {@link #JobWorkItem(Intent, long, long)}
+     * @removed
+     */
+    @Deprecated
+    public JobWorkItem(Intent intent, @BytesLong long networkBytes) {
+        this(intent, networkBytes, NETWORK_BYTES_UNKNOWN);
     }
 
     /**
      * Create a new piece of work, which can be submitted to
      * {@link JobScheduler#enqueue JobScheduler.enqueue}.
+     * <p>
+     * See {@link JobInfo.Builder#setEstimatedNetworkBytes(long, long)} for
+     * details about how to estimate network traffic.
      *
      * @param intent The general Intent describing this work.
-     * @param networkBytes The estimated size of network traffic that will be
-     *            performed by this job work item, in bytes. See
-     *            {@link JobInfo.Builder#setEstimatedNetworkBytes(long)} for
-     *            details about how to estimate.
+     * @param downloadBytes The estimated size of network traffic that will be
+     *            downloaded by this job work item, in bytes.
+     * @param uploadBytes The estimated size of network traffic that will be
+     *            uploaded by this job work item, in bytes.
      */
-    public JobWorkItem(Intent intent, @BytesLong long networkBytes) {
+    public JobWorkItem(Intent intent, @BytesLong long downloadBytes, @BytesLong long uploadBytes) {
         mIntent = intent;
-        mNetworkBytes = networkBytes;
+        mNetworkDownloadBytes = downloadBytes;
+        mNetworkUploadBytes = uploadBytes;
     }
 
     /**
@@ -67,14 +84,44 @@
     }
 
     /**
-     * Return the estimated size of network traffic that will be performed by
+     * @deprecated replaced by {@link #getEstimatedNetworkDownloadBytes()} and
+     *             {@link #getEstimatedNetworkUploadBytes()}.
+     * @removed
+     */
+    @Deprecated
+    public @BytesLong long getEstimatedNetworkBytes() {
+        if (mNetworkDownloadBytes == NETWORK_BYTES_UNKNOWN
+                && mNetworkUploadBytes == NETWORK_BYTES_UNKNOWN) {
+            return NETWORK_BYTES_UNKNOWN;
+        } else if (mNetworkDownloadBytes == NETWORK_BYTES_UNKNOWN) {
+            return mNetworkUploadBytes;
+        } else if (mNetworkUploadBytes == NETWORK_BYTES_UNKNOWN) {
+            return mNetworkDownloadBytes;
+        } else {
+            return mNetworkDownloadBytes + mNetworkUploadBytes;
+        }
+    }
+
+    /**
+     * Return the estimated size of download traffic that will be performed by
+     * this job, in bytes.
+     *
+     * @return Estimated size of download traffic, or
+     *         {@link JobInfo#NETWORK_BYTES_UNKNOWN} when unknown.
+     */
+    public @BytesLong long getEstimatedNetworkDownloadBytes() {
+        return mNetworkDownloadBytes;
+    }
+
+    /**
+     * Return the estimated size of upload traffic that will be performed by
      * this job work item, in bytes.
      *
-     * @return estimated size, or {@link JobInfo#NETWORK_BYTES_UNKNOWN} when
-     *         unknown.
+     * @return Estimated size of upload traffic, or
+     *         {@link JobInfo#NETWORK_BYTES_UNKNOWN} when unknown.
      */
-    public @BytesLong long getEstimatedNetworkBytes() {
-        return mNetworkBytes;
+    public @BytesLong long getEstimatedNetworkUploadBytes() {
+        return mNetworkUploadBytes;
     }
 
     /**
@@ -128,9 +175,13 @@
         sb.append(mWorkId);
         sb.append(" intent=");
         sb.append(mIntent);
-        if (mNetworkBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
-            sb.append(" networkBytes=");
-            sb.append(mNetworkBytes);
+        if (mNetworkDownloadBytes != NETWORK_BYTES_UNKNOWN) {
+            sb.append(" downloadBytes=");
+            sb.append(mNetworkDownloadBytes);
+        }
+        if (mNetworkUploadBytes != NETWORK_BYTES_UNKNOWN) {
+            sb.append(" uploadBytes=");
+            sb.append(mNetworkUploadBytes);
         }
         if (mDeliveryCount != 0) {
             sb.append(" dcount=");
@@ -151,7 +202,8 @@
         } else {
             out.writeInt(0);
         }
-        out.writeLong(mNetworkBytes);
+        out.writeLong(mNetworkDownloadBytes);
+        out.writeLong(mNetworkUploadBytes);
         out.writeInt(mDeliveryCount);
         out.writeInt(mWorkId);
     }
@@ -173,7 +225,8 @@
         } else {
             mIntent = null;
         }
-        mNetworkBytes = in.readLong();
+        mNetworkDownloadBytes = in.readLong();
+        mNetworkUploadBytes = in.readLong();
         mDeliveryCount = in.readInt();
         mWorkId = in.readInt();
     }
diff --git a/core/java/android/app/slice/SliceManager.java b/core/java/android/app/slice/SliceManager.java
index 67a72ec..1afe53d 100644
--- a/core/java/android/app/slice/SliceManager.java
+++ b/core/java/android/app/slice/SliceManager.java
@@ -32,9 +32,11 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceManager.ServiceNotFoundException;
+import android.os.UserHandle;
 import android.util.Log;
 
 import com.android.internal.util.Preconditions;
@@ -392,6 +394,9 @@
      */
     public void enforceSlicePermission(Uri uri, String pkg, int pid, int uid) {
         try {
+            if (UserHandle.isSameApp(uid, Process.myUid())) {
+                return;
+            }
             if (pkg == null) {
                 throw new SecurityException("No pkg specified");
             }
diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java
index dd89293..bf856b7 100644
--- a/core/java/android/app/slice/SliceProvider.java
+++ b/core/java/android/app/slice/SliceProvider.java
@@ -37,7 +37,6 @@
 import android.os.Process;
 import android.os.StrictMode;
 import android.os.StrictMode.ThreadPolicy;
-import android.os.UserHandle;
 import android.util.Log;
 
 import java.util.ArrayList;
@@ -146,18 +145,6 @@
      * @hide
      */
     public static final String EXTRA_PROVIDER_PKG = "provider_pkg";
-    /**
-     * @hide
-     */
-    public static final String EXTRA_OVERRIDE_PKG = "override_pkg";
-    /**
-     * @hide
-     */
-    public static final String EXTRA_OVERRIDE_UID = "override_uid";
-    /**
-     * @hide
-     */
-    public static final String EXTRA_OVERRIDE_PID = "override_pid";
 
     private static final boolean DEBUG = false;
 
@@ -257,6 +244,23 @@
                 "This provider has not implemented intent to uri mapping");
     }
 
+    /**
+     * Called when an app requests a slice it does not have write permission
+     * to the uri for.
+     * <p>
+     * The return value will be the action on a slice that prompts the user that
+     * the calling app wants to show slices from this app. The default implementation
+     * launches a dialog that allows the user to grant access to this slice. Apps
+     * that do not want to allow this user grant, can override this and instead
+     * launch their own dialog with different behavior.
+     *
+     * @param sliceUri the Uri of the slice attempting to be bound.
+     * @see #getCallingPackage()
+     */
+    public @NonNull PendingIntent onCreatePermissionRequest(Uri sliceUri) {
+        return createPermissionIntent(getContext(), sliceUri, getCallingPackage());
+    }
+
     @Override
     public final int update(Uri uri, ContentValues values, String selection,
             String[] selectionArgs) {
@@ -312,17 +316,7 @@
             String callingPackage = getCallingPackage();
             int callingUid = Binder.getCallingUid();
             int callingPid = Binder.getCallingPid();
-            if (extras.containsKey(EXTRA_OVERRIDE_PKG)) {
-                if (Binder.getCallingUid() != Process.SYSTEM_UID) {
-                    throw new SecurityException("Only the system can override calling pkg");
-                }
-                // This is safe because we would grant SYSTEM_UID access to all slices
-                // and want to allow it to bind slices as if it were a less privileged app
-                // to check their permission levels.
-                callingPackage = extras.getString(EXTRA_OVERRIDE_PKG);
-                callingUid = extras.getInt(EXTRA_OVERRIDE_UID);
-                callingPid = extras.getInt(EXTRA_OVERRIDE_PID);
-            }
+
             Slice s = handleBindSlice(uri, supportedSpecs, callingPackage, callingUid, callingPid);
             Bundle b = new Bundle();
             b.putParcelable(EXTRA_SLICE, s);
@@ -406,13 +400,11 @@
         // SliceManager#bindSlice.
         String pkg = callingPkg != null ? callingPkg
                 : getContext().getPackageManager().getNameForUid(callingUid);
-        if (!UserHandle.isSameApp(callingUid, Process.myUid())) {
-            try {
-                mSliceManager.enforceSlicePermission(sliceUri, pkg,
-                        callingPid, callingUid);
-            } catch (SecurityException e) {
-                return createPermissionSlice(getContext(), sliceUri, pkg);
-            }
+        try {
+            mSliceManager.enforceSlicePermission(sliceUri, pkg,
+                    callingPid, callingUid);
+        } catch (SecurityException e) {
+            return createPermissionSlice(getContext(), sliceUri, pkg);
         }
         mCallback = "onBindSlice";
         Handler.getMain().postDelayed(mAnr, SLICE_BIND_ANR);
@@ -426,10 +418,18 @@
     /**
      * @hide
      */
-    public static Slice createPermissionSlice(Context context, Uri sliceUri,
+    public Slice createPermissionSlice(Context context, Uri sliceUri,
             String callingPackage) {
+        PendingIntent action;
+        mCallback = "onCreatePermissionRequest";
+        Handler.getMain().postDelayed(mAnr, SLICE_BIND_ANR);
+        try {
+            action = onCreatePermissionRequest(sliceUri);
+        } finally {
+            Handler.getMain().removeCallbacks(mAnr);
+        }
         return new Slice.Builder(sliceUri)
-                .addAction(createPermissionIntent(context, sliceUri, callingPackage),
+                .addAction(action,
                         new Slice.Builder(sliceUri.buildUpon().appendPath("permission").build())
                                 .addText(getPermissionString(context, callingPackage), null,
                                         Collections.emptyList())
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index 656188f..6aeb94d 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -38,7 +38,7 @@
      * This extra represents the current connection state of the profile of the
      * Bluetooth device.
      */
-    public static final String EXTRA_STATE = "android.bluetooth.profile.extra.STATE";
+    String EXTRA_STATE = "android.bluetooth.profile.extra.STATE";
 
     /**
      * Extra for the connection state intents of the individual profiles.
@@ -46,123 +46,130 @@
      * This extra represents the previous connection state of the profile of the
      * Bluetooth device.
      */
-    public static final String EXTRA_PREVIOUS_STATE =
+    String EXTRA_PREVIOUS_STATE =
             "android.bluetooth.profile.extra.PREVIOUS_STATE";
 
     /** The profile is in disconnected state */
-    public static final int STATE_DISCONNECTED = 0;
+    int STATE_DISCONNECTED = 0;
     /** The profile is in connecting state */
-    public static final int STATE_CONNECTING = 1;
+    int STATE_CONNECTING = 1;
     /** The profile is in connected state */
-    public static final int STATE_CONNECTED = 2;
+    int STATE_CONNECTED = 2;
     /** The profile is in disconnecting state */
-    public static final int STATE_DISCONNECTING = 3;
+    int STATE_DISCONNECTING = 3;
 
     /**
      * Headset and Handsfree profile
      */
-    public static final int HEADSET = 1;
+    int HEADSET = 1;
 
     /**
      * A2DP profile.
      */
-    public static final int A2DP = 2;
+    int A2DP = 2;
 
     /**
      * Health Profile
      */
-    public static final int HEALTH = 3;
+    int HEALTH = 3;
 
     /**
      * HID Host
      *
      * @hide
      */
-    public static final int HID_HOST = 4;
+    int HID_HOST = 4;
 
     /**
      * PAN Profile
      *
      * @hide
      */
-    public static final int PAN = 5;
+    int PAN = 5;
 
     /**
      * PBAP
      *
      * @hide
      */
-    public static final int PBAP = 6;
+    int PBAP = 6;
 
     /**
      * GATT
      */
-    public static final int GATT = 7;
+    int GATT = 7;
 
     /**
      * GATT_SERVER
      */
-    public static final int GATT_SERVER = 8;
+    int GATT_SERVER = 8;
 
     /**
      * MAP Profile
      *
      * @hide
      */
-    public static final int MAP = 9;
+    int MAP = 9;
 
     /*
      * SAP Profile
      * @hide
      */
-    public static final int SAP = 10;
+    int SAP = 10;
 
     /**
      * A2DP Sink Profile
      *
      * @hide
      */
-    public static final int A2DP_SINK = 11;
+    int A2DP_SINK = 11;
 
     /**
      * AVRCP Controller Profile
      *
      * @hide
      */
-    public static final int AVRCP_CONTROLLER = 12;
+    int AVRCP_CONTROLLER = 12;
+
+    /**
+     * AVRCP Target Profile
+     *
+     * @hide
+     */
+    int AVRCP = 13;
 
     /**
      * Headset Client - HFP HF Role
      *
      * @hide
      */
-    public static final int HEADSET_CLIENT = 16;
+    int HEADSET_CLIENT = 16;
 
     /**
      * PBAP Client
      *
      * @hide
      */
-    public static final int PBAP_CLIENT = 17;
+    int PBAP_CLIENT = 17;
 
     /**
      * MAP Messaging Client Equipment (MCE)
      *
      * @hide
      */
-    public static final int MAP_CLIENT = 18;
+    int MAP_CLIENT = 18;
 
     /**
      * HID Device
      */
-    public static final int HID_DEVICE = 19;
+    int HID_DEVICE = 19;
 
     /**
      * Object Push Profile (OPP)
      *
      * @hide
      */
-    public static final int OPP = 20;
+    int OPP = 20;
 
     /**
      * Hearing Aid Device
@@ -185,7 +192,7 @@
      *
      * @hide
      **/
-    public static final int PRIORITY_AUTO_CONNECT = 1000;
+    int PRIORITY_AUTO_CONNECT = 1000;
 
     /**
      * Default priority for devices that allow incoming
@@ -194,7 +201,7 @@
      * @hide
      **/
     @SystemApi
-    public static final int PRIORITY_ON = 100;
+    int PRIORITY_ON = 100;
 
     /**
      * Default priority for devices that does not allow incoming
@@ -203,14 +210,14 @@
      * @hide
      **/
     @SystemApi
-    public static final int PRIORITY_OFF = 0;
+    int PRIORITY_OFF = 0;
 
     /**
      * Default priority when not set or when the device is unpaired
      *
      * @hide
      */
-    public static final int PRIORITY_UNDEFINED = -1;
+    int PRIORITY_UNDEFINED = -1;
 
     /**
      * Get connected devices for this specific profile.
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index e1a00b1..920056a 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -621,7 +621,7 @@
      * @throws android.content.res.Resources.NotFoundException if the given ID
      *         does not exist.
      */
-    @NonNull
+    @Nullable
     public final Drawable getDrawable(@DrawableRes int id) {
         return getResources().getDrawable(id, getTheme());
     }
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 387a836..e85058d 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1101,6 +1101,58 @@
     /** @hide */
     public String[] splitClassLoaderNames;
 
+    /**
+     * Represents the default policy. The actual policy used will depend on other properties of
+     * the application, e.g. the target SDK version.
+     * @hide
+     */
+    public static final int HIDDEN_API_ENFORCEMENT_DEFAULT = -1;
+    /**
+     * No API enforcement; the app can access the entire internal private API. Only for use by
+     * system apps.
+     * @hide
+     */
+    public static final int HIDDEN_API_ENFORCEMENT_NONE = 0;
+    /**
+     * Light grey list enforcement, the strictest option. Enforces the light grey, dark grey and
+     * black lists.
+     * @hide
+     * */
+    public static final int HIDDEN_API_ENFORCEMENT_ALL_LISTS = 1;
+    /**
+     * Dark grey list enforcement. Enforces the dark grey and black lists
+     * @hide
+     */
+    public static final int HIDDEN_API_ENFORCEMENT_DARK_GREY_AND_BLACK = 2;
+    /**
+     * Blacklist enforcement only.
+     * @hide
+     */
+    public static final int HIDDEN_API_ENFORCEMENT_BLACK = 3;
+
+    private static final int HIDDEN_API_ENFORCEMENT_MAX = HIDDEN_API_ENFORCEMENT_BLACK;
+
+    /**
+     * Values in this IntDef MUST be kept in sync with enum hiddenapi::EnforcementPolicy in
+     * art/runtime/hidden_api.h
+     * @hide
+     */
+    @IntDef(prefix = { "HIDDEN_API_ENFORCEMENT_" }, value = {
+            HIDDEN_API_ENFORCEMENT_DEFAULT,
+            HIDDEN_API_ENFORCEMENT_NONE,
+            HIDDEN_API_ENFORCEMENT_ALL_LISTS,
+            HIDDEN_API_ENFORCEMENT_DARK_GREY_AND_BLACK,
+            HIDDEN_API_ENFORCEMENT_BLACK,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface HiddenApiEnforcementPolicy {}
+
+    private boolean isValidHiddenApiEnforcementPolicy(int policy) {
+        return policy >= HIDDEN_API_ENFORCEMENT_DEFAULT && policy <= HIDDEN_API_ENFORCEMENT_MAX;
+    }
+
+    private int mHiddenApiPolicy = HIDDEN_API_ENFORCEMENT_DEFAULT;
+
     public void dump(Printer pw, String prefix) {
         dump(pw, prefix, DUMP_FLAG_ALL);
     }
@@ -1188,7 +1240,7 @@
             if (category != CATEGORY_UNDEFINED) {
                 pw.println(prefix + "category=" + category);
             }
-            pw.println(prefix + "isAllowedToUseHiddenApi=" + isAllowedToUseHiddenApi());
+            pw.println(prefix + "HiddenApiEnforcementPolicy=" + getHiddenApiEnforcementPolicy());
         }
         super.dumpBack(pw, prefix);
     }
@@ -1386,6 +1438,7 @@
         appComponentFactory = orig.appComponentFactory;
         compileSdkVersion = orig.compileSdkVersion;
         compileSdkVersionCodename = orig.compileSdkVersionCodename;
+        mHiddenApiPolicy = orig.mHiddenApiPolicy;
     }
 
     public String toString() {
@@ -1459,6 +1512,7 @@
         dest.writeInt(compileSdkVersion);
         dest.writeString(compileSdkVersionCodename);
         dest.writeString(appComponentFactory);
+        dest.writeInt(mHiddenApiPolicy);
     }
 
     public static final Parcelable.Creator<ApplicationInfo> CREATOR
@@ -1529,6 +1583,7 @@
         compileSdkVersion = source.readInt();
         compileSdkVersionCodename = source.readString();
         appComponentFactory = source.readString();
+        mHiddenApiPolicy = source.readInt();
     }
 
     /**
@@ -1599,13 +1654,31 @@
         }
     }
 
+    private boolean isPackageWhitelistedForHiddenApis() {
+        return SystemConfig.getInstance().getHiddenApiWhitelistedApps().contains(packageName);
+    }
+
     /**
      * @hide
      */
-    public boolean isAllowedToUseHiddenApi() {
-        boolean whitelisted =
-                SystemConfig.getInstance().getHiddenApiWhitelistedApps().contains(packageName);
-        return whitelisted && (isSystemApp() || isUpdatedSystemApp());
+    public @HiddenApiEnforcementPolicy int getHiddenApiEnforcementPolicy() {
+        if (mHiddenApiPolicy != HIDDEN_API_ENFORCEMENT_DEFAULT) {
+            return mHiddenApiPolicy;
+        }
+        if (isPackageWhitelistedForHiddenApis() && (isSystemApp() || isUpdatedSystemApp())) {
+            return HIDDEN_API_ENFORCEMENT_NONE;
+        }
+        return HIDDEN_API_ENFORCEMENT_BLACK;
+    }
+
+    /**
+     * @hide
+     */
+    public void setHiddenApiEnforcementPolicy(@HiddenApiEnforcementPolicy int policy) {
+        if (!isValidHiddenApiEnforcementPolicy(policy)) {
+            throw new IllegalArgumentException("Invalid API enforcement policy: " + policy);
+        }
+        mHiddenApiPolicy = policy;
     }
 
     /**
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 114c485..314eb98 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3711,6 +3711,7 @@
      *
      * @hide
      */
+    @TestApi
     public abstract @Nullable String[] getNamesForUids(int[] uids);
 
     /**
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index d813382..c58cde0 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -847,6 +847,7 @@
      * @see #getDrawableForDensity(int, int, Theme)
      * @deprecated Use {@link #getDrawableForDensity(int, int, Theme)} instead.
      */
+    @Nullable
     @Deprecated
     public Drawable getDrawableForDensity(@DrawableRes int id, int density)
             throws NotFoundException {
@@ -864,12 +865,13 @@
      *            found in {@link DisplayMetrics}. A value of 0 means to use the
      *            density returned from {@link #getConfiguration()}.
      *            This is equivalent to calling {@link #getDrawable(int, Theme)}.
-     * @param theme The theme used to style the drawable attributes, may be {@code null}.
+     * @param theme The theme used to style the drawable attributes, may be {@code null} if the
+     *              drawable cannot be decoded.
      * @return Drawable An object that can be used to draw this resource.
      * @throws NotFoundException Throws NotFoundException if the given ID does
-     *             not exist, or cannot be decoded.
+     *             not exist.
      */
-    @NonNull
+    @Nullable
     public Drawable getDrawableForDensity(@DrawableRes int id, int density, @Nullable Theme theme) {
         final TypedValue value = obtainTempTypedValue();
         try {
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 157910a..8c98067 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -544,7 +544,7 @@
         }
     }
 
-    @NonNull
+    @Nullable
     Drawable loadDrawable(@NonNull Resources wrapper, @NonNull TypedValue value, int id,
             int density, @Nullable Resources.Theme theme)
             throws NotFoundException {
@@ -757,6 +757,7 @@
      *
      * This call will handle closing ais.
      */
+    @Nullable
     private Drawable decodeImageDrawable(@NonNull AssetInputStream ais,
             @NonNull Resources wrapper, @NonNull TypedValue value) {
         ImageDecoder.Source src = new ImageDecoder.AssetInputStreamSource(ais,
@@ -774,8 +775,10 @@
 
     /**
      * Loads a drawable from XML or resources stream.
+     *
+     * @return Drawable, or null if Drawable cannot be decoded.
      */
-    @NonNull
+    @Nullable
     private Drawable loadDrawableForCookie(@NonNull Resources wrapper, @NonNull TypedValue value,
             int id, int density) {
         if (value.string == null) {
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
index 91bbdc7..6d9c913 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -105,6 +105,12 @@
     /* Gets the current screen unlocked functions. */
     long getScreenUnlockedFunctions();
 
+    /* Get the functionfs control handle for the given function. Usb
+     * descriptors will already be written, and the handle will be
+     * ready to use.
+     */
+    ParcelFileDescriptor getControlFd(long function);
+
     /* Allow USB debugging from the attached host. If alwaysAllow is true, add the
      * the public key to list of host keys that the user has approved.
      */
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 572c585..46142e3 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -192,14 +192,6 @@
     public static final String USB_DATA_UNLOCKED = "unlocked";
 
     /**
-     * Boolean extra indicating whether the intent represents a change in the usb
-     * configuration (as opposed to a state update).
-     *
-     * {@hide}
-     */
-    public static final String USB_CONFIG_CHANGED = "config_changed";
-
-    /**
      * A placeholder indicating that no USB function is being specified.
      * Used for compatibility with old init scripts to indicate no functions vs. charging function.
      *
@@ -471,6 +463,25 @@
     }
 
     /**
+     * Gets the functionfs control file descriptor for the given function, with
+     * the usb descriptors and strings already written. The file descriptor is used
+     * by the function implementation to handle events and control requests.
+     *
+     * @param function to get control fd for. Currently {@link #FUNCTION_MTP} and
+     * {@link #FUNCTION_PTP} are supported.
+     * @return A ParcelFileDescriptor holding the valid fd, or null if the fd was not found.
+     *
+     * {@hide}
+     */
+    public ParcelFileDescriptor getControlFd(long function) {
+        try {
+            return mService.getControlFd(function);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Returns true if the caller has permission to access the device.
      * Permission might have been granted temporarily via
      * {@link #requestPermission(UsbDevice, PendingIntent)} or
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 93b1b22..e07f586 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -3851,8 +3851,8 @@
 
     /**
      * The network watchlist is a list of domains and IP addresses that are associated with
-     * potentially harmful apps. This method returns the hash of the watchlist currently
-     * used by the system.
+     * potentially harmful apps. This method returns the SHA-256 of the watchlist config file
+     * currently used by the system for validation purposes.
      *
      * @return Hash of network watchlist config file. Null if config does not exist.
      */
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index 7922276..40d53b7 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -16,7 +16,6 @@
 
 package android.net;
 
-import android.annotation.RequiresPermission;
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
@@ -259,30 +258,47 @@
     /**
      * Set specific UID to use when accounting {@link Socket} traffic
      * originating from the current thread. Designed for use when performing an
-     * operation on behalf of another application.
+     * operation on behalf of another application, or when another application
+     * is performing operations on your behalf.
+     * <p>
+     * Any app can <em>accept</em> blame for traffic performed on a socket
+     * originally created by another app by calling this method with the
+     * {@link android.system.Os#getuid()} value. However, only apps holding the
+     * {@code android.Manifest.permission#UPDATE_DEVICE_STATS} permission may
+     * <em>assign</em> blame to another UIDs.
      * <p>
      * Changes only take effect during subsequent calls to
      * {@link #tagSocket(Socket)}.
-     * <p>
-     * To take effect, caller must hold
-     * {@link android.Manifest.permission#UPDATE_DEVICE_STATS} permission.
-     *
-     * @hide
      */
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
+    @SuppressLint("Doclava125")
     public static void setThreadStatsUid(int uid) {
         NetworkManagementSocketTagger.setThreadSocketStatsUid(uid);
     }
 
     /**
+     * Get the active UID used when accounting {@link Socket} traffic originating
+     * from the current thread. Only one active tag per thread is supported.
+     * {@link #tagSocket(Socket)}.
+     *
+     * @see #setThreadStatsUid(int)
+     */
+    public static int getThreadStatsUid() {
+        return NetworkManagementSocketTagger.getThreadSocketStatsUid();
+    }
+
+    /**
      * Set specific UID to use when accounting {@link Socket} traffic
      * originating from the current thread as the calling UID. Designed for use
      * when another application is performing operations on your behalf.
      * <p>
      * Changes only take effect during subsequent calls to
      * {@link #tagSocket(Socket)}.
+     *
+     * @removed
+     * @deprecated use {@link #setThreadStatsUid(int)} instead.
      */
+    @Deprecated
     public static void setThreadStatsUidSelf() {
         setThreadStatsUid(android.os.Process.myUid());
     }
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index df6ce8e..e22c65f 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -242,7 +242,9 @@
          * Possible values are defined in {@link Build.VERSION_CODES}.
          *
          * @see #SDK_INT
+         * @hide
          */
+        @TestApi
         public static final int FIRST_SDK_INT = SystemProperties
                 .getInt("ro.product.first_api_level", 0);
 
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 1160415..88d6e84 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -411,6 +411,9 @@
                 checkpoint = 0;
             }
         }
+        if (listener != null) {
+            listener.onProgress(progress);
+        }
         return progress;
     }
 
@@ -440,6 +443,9 @@
                 checkpoint = 0;
             }
         }
+        if (listener != null) {
+            listener.onProgress(progress);
+        }
         return progress;
     }
 
@@ -479,6 +485,9 @@
                 checkpoint = 0;
             }
         }
+        if (listener != null) {
+            listener.onProgress(progress);
+        }
         return progress;
     }
 
diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java
index 0f70427..b254166 100644
--- a/core/java/android/os/SystemClock.java
+++ b/core/java/android/os/SystemClock.java
@@ -269,6 +269,7 @@
      * time or throw.
      *
      * @throws DateTimeException when no accurate network time can be provided.
+     * @hide
      */
     public static long currentNetworkTimeMillis() {
         final IAlarmManager mgr = IAlarmManager.Stub
@@ -302,6 +303,7 @@
      * time or throw.
      *
      * @throws DateTimeException when no accurate network time can be provided.
+     * @hide
      */
     public static @NonNull Clock currentNetworkTimeClock() {
         return new SimpleClock(ZoneOffset.UTC) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index a013d3d..9ecae8c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1348,10 +1348,18 @@
             = "android.settings.NOTIFICATION_SETTINGS";
 
     /**
+     * Activity Action: Show app listing settings, filtered by those that send notifications.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_ALL_APPS_NOTIFICATION_SETTINGS =
+            "android.settings.ALL_APPS_NOTIFICATION_SETTINGS";
+
+    /**
      * Activity Action: Show notification settings for a single app.
      * <p>
-     *     Input: {@link #EXTRA_APP_PACKAGE}, the package containing the channel to display.
-     *     Input: Optionally, {@link #EXTRA_CHANNEL_ID}, to highlight that channel.
+     *     Input: {@link #EXTRA_APP_PACKAGE}, the package to display.
      * <p>
      * Output: Nothing.
      */
@@ -11004,13 +11012,21 @@
         public static final String SHOW_PROCESSES = "show_processes";
 
         /**
-         * If 1 low power mode is enabled.
+         * If 1 low power mode (aka battery saver) is enabled.
          * @hide
          */
         @TestApi
         public static final String LOW_POWER_MODE = "low_power";
 
         /**
+         * If 1, battery saver ({@link #LOW_POWER_MODE}) will be re-activated after the device
+         * is unplugged from a charger or rebooted.
+         * @hide
+         */
+        @TestApi
+        public static final String LOW_POWER_MODE_STICKY = "low_power_sticky";
+
+        /**
          * Battery level [1-100] at which low power mode automatically turns on.
          * If 0, it will not automatically turn on.
          * @hide
diff --git a/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java b/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java
index d42424e..2a66206 100644
--- a/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java
+++ b/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java
@@ -94,21 +94,6 @@
     private KeyDerivationParams mKeyDerivationParams;
     private byte[] mSecret; // Derived from user secret. The field must have limited visibility.
 
-    /**
-     * @param secret Constructor creates a reference to the secret. Caller must use
-     * @link {#clearSecret} to overwrite its value in memory.
-     * @hide
-     */
-    public KeyChainProtectionParams(@UserSecretType int userSecretType,
-            @LockScreenUiFormat int lockScreenUiFormat,
-            @NonNull KeyDerivationParams keyDerivationParams,
-            @NonNull byte[] secret) {
-        mUserSecretType = userSecretType;
-        mLockScreenUiFormat = lockScreenUiFormat;
-        mKeyDerivationParams = Preconditions.checkNotNull(keyDerivationParams);
-        mSecret = Preconditions.checkNotNull(secret);
-    }
-
     private KeyChainProtectionParams() {
 
     }
@@ -158,6 +143,7 @@
 
         /**
          * Sets user secret type.
+         * Default value is {@link TYPE_LOCKSCREEN}.
          *
          * @see TYPE_LOCKSCREEN
          * @param userSecretType The secret type
@@ -185,7 +171,7 @@
         /**
          * Sets parameters of the key derivation function.
          *
-         * @param keyDerivationParams Key derivation Params
+         * @param keyDerivationParams Key derivation parameters
          * @return This builder.
          */
         public Builder setKeyDerivationParams(@NonNull KeyDerivationParams
diff --git a/core/java/android/security/keystore/recovery/KeyChainSnapshot.java b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
index ccb627e..24ff182 100644
--- a/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
+++ b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
@@ -252,12 +252,12 @@
         /**
          * Sets UI and key derivation parameters
          *
-         * @param recoveryMetadata The UI and key derivation parameters
+         * @param keyChainProtectionParams The UI and key derivation parameters
          * @return This builder.
          */
         public Builder setKeyChainProtectionParams(
-                @NonNull List<KeyChainProtectionParams> recoveryMetadata) {
-            mInstance.mKeyChainProtectionParams = recoveryMetadata;
+                @NonNull List<KeyChainProtectionParams> keyChainProtectionParams) {
+            mInstance.mKeyChainProtectionParams = keyChainProtectionParams;
             return this;
         }
 
@@ -292,7 +292,7 @@
          */
         @NonNull public KeyChainSnapshot build() {
             Preconditions.checkCollectionElementsNotNull(mInstance.mKeyChainProtectionParams,
-                    "recoveryMetadata");
+                    "keyChainProtectionParams");
             Preconditions.checkCollectionElementsNotNull(mInstance.mEntryRecoveryData,
                     "entryRecoveryData");
             Preconditions.checkNotNull(mInstance.mEncryptedRecoveryKeyBlob);
diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java
index 61b4dd8..ab52d32 100644
--- a/core/java/android/security/keystore/recovery/RecoveryController.java
+++ b/core/java/android/security/keystore/recovery/RecoveryController.java
@@ -159,7 +159,7 @@
      * Gets a new instance of the class.
      */
     @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
-    public static RecoveryController getInstance(Context context) {
+    @NonNull public static RecoveryController getInstance(@NonNull Context context) {
         ILockSettings lockSettings =
                 ILockSettings.Stub.asInterface(ServiceManager.getService("lock_settings"));
         return new RecoveryController(lockSettings, KeyStore.getInstance());
diff --git a/core/java/android/text/method/LinkMovementMethod.java b/core/java/android/text/method/LinkMovementMethod.java
index 31ed549..f332358 100644
--- a/core/java/android/text/method/LinkMovementMethod.java
+++ b/core/java/android/text/method/LinkMovementMethod.java
@@ -16,6 +16,7 @@
 
 package android.text.method;
 
+import android.os.Build;
 import android.text.Layout;
 import android.text.NoCopySpan;
 import android.text.Selection;
@@ -35,6 +36,8 @@
     private static final int UP = 2;
     private static final int DOWN = 3;
 
+    private static final int HIDE_FLOATING_TOOLBAR_DELAY_MS = 200;
+
     @Override
     public boolean canSelectArbitrarily() {
         return true;
@@ -65,7 +68,7 @@
 
         return super.up(widget, buffer);
     }
-        
+
     @Override
     protected boolean down(TextView widget, Spannable buffer) {
         if (action(DOWN, widget, buffer)) {
@@ -215,6 +218,12 @@
                 if (action == MotionEvent.ACTION_UP) {
                     links[0].onClick(widget);
                 } else if (action == MotionEvent.ACTION_DOWN) {
+                    if (widget.getContext().getApplicationInfo().targetSdkVersion
+                            > Build.VERSION_CODES.O_MR1) {
+                        // Selection change will reposition the toolbar. Hide it for a few ms for a
+                        // smoother transition.
+                        widget.hideFloatingToolbar(HIDE_FLOATING_TOOLBAR_DELAY_MS);
+                    }
                     Selection.setSelection(buffer,
                         buffer.getSpanStart(links[0]),
                         buffer.getSpanEnd(links[0]));
diff --git a/core/java/android/util/DataUnit.java b/core/java/android/util/DataUnit.java
index ea4266e..cf045b8 100644
--- a/core/java/android/util/DataUnit.java
+++ b/core/java/android/util/DataUnit.java
@@ -29,6 +29,8 @@
  * "kibibyte" as an IEC unit of 1024 bytes.
  * <p>
  * This design is mirrored after {@link TimeUnit} and {@link ChronoUnit}.
+ *
+ * @hide
  */
 public enum DataUnit {
     KILOBYTES { @Override public long toBytes(long v) { return v * 1_000; } },
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 5bee87c..01fd090 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -274,6 +274,16 @@
     public static final int STATE_DISABLED_BY_SERVICE = 4;
 
     /**
+     * Same as {@link #STATE_UNKNOWN}, but used on
+     * {@link AutofillManagerClient#setSessionFinished(int)} when the session was finished because
+     * the URL bar changed on client mode
+     *
+     * @hide
+     */
+    public static final int STATE_UNKNOWN_COMPAT_MODE = 5;
+
+
+    /**
      * Timeout in ms for calls to the field classification service.
      * @hide
      */
@@ -1947,15 +1957,24 @@
      * Marks the state of the session as finished.
      *
      * @param newState {@link #STATE_FINISHED} (because the autofill service returned a {@code null}
-     *  FillResponse), {@link #STATE_UNKNOWN} (because the session was removed), or
-     *  {@link #STATE_DISABLED_BY_SERVICE} (because the autofill service disabled further autofill
-     *  requests for the activity).
+     *  FillResponse), {@link #STATE_UNKNOWN} (because the session was removed),
+     *  {@link #STATE_UNKNOWN_COMPAT_MODE} (beucase the session was finished when the URL bar
+     *  changed on compat mode), or {@link #STATE_DISABLED_BY_SERVICE} (because the autofill service
+     *  disabled further autofill requests for the activity).
      */
     private void setSessionFinished(int newState) {
         synchronized (mLock) {
-            if (sVerbose) Log.v(TAG, "setSessionFinished(): from " + mState + " to " + newState);
-            resetSessionLocked(/* resetEnteredIds= */ false);
-            mState = newState;
+            if (sVerbose) {
+                Log.v(TAG, "setSessionFinished(): from " + getStateAsStringLocked() + " to "
+                        + getStateAsString(newState));
+            }
+            if (newState == STATE_UNKNOWN_COMPAT_MODE) {
+                resetSessionLocked(/* resetEnteredIds= */ true);
+                mState = STATE_UNKNOWN;
+            } else {
+                resetSessionLocked(/* resetEnteredIds= */ false);
+                mState = newState;
+            }
         }
     }
 
@@ -2107,19 +2126,26 @@
 
     @GuardedBy("mLock")
     private String getStateAsStringLocked() {
-        switch (mState) {
+        return getStateAsString(mState);
+    }
+
+    @NonNull
+    private static String getStateAsString(int state) {
+        switch (state) {
             case STATE_UNKNOWN:
-                return "STATE_UNKNOWN";
+                return "UNKNOWN";
             case STATE_ACTIVE:
-                return "STATE_ACTIVE";
+                return "ACTIVE";
             case STATE_FINISHED:
-                return "STATE_FINISHED";
+                return "FINISHED";
             case STATE_SHOWING_SAVE_UI:
-                return "STATE_SHOWING_SAVE_UI";
+                return "SHOWING_SAVE_UI";
             case STATE_DISABLED_BY_SERVICE:
-                return "STATE_DISABLED_BY_SERVICE";
+                return "DISABLED_BY_SERVICE";
+            case STATE_UNKNOWN_COMPAT_MODE:
+                return "UNKNOWN_COMPAT_MODE";
             default:
-                return "INVALID:" + mState;
+                return "INVALID:" + state;
         }
     }
 
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 92285c7..3775835 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -289,6 +289,7 @@
     boolean mShowSoftInputOnFocus = true;
     private boolean mPreserveSelection;
     private boolean mRestartActionModeOnNextRefresh;
+    private boolean mRequestingLinkActionMode;
 
     private SelectionActionModeHelper mSelectionActionModeHelper;
 
@@ -2127,6 +2128,7 @@
             return;
         }
         stopTextActionMode();
+        mRequestingLinkActionMode = true;
         getSelectionActionModeHelper().startLinkActionModeAsync(start, end);
     }
 
@@ -2212,7 +2214,9 @@
         mTextActionMode = mTextView.startActionMode(actionModeCallback, ActionMode.TYPE_FLOATING);
 
         final boolean selectionStarted = mTextActionMode != null;
-        if (selectionStarted && !mTextView.isTextSelectable() && mShowSoftInputOnFocus) {
+        if (selectionStarted
+                && mTextView.isTextEditable() && !mTextView.isTextSelectable()
+                && mShowSoftInputOnFocus) {
             // Show the IME to be able to replace text, except when selecting non editable text.
             final InputMethodManager imm = InputMethodManager.peekInstance();
             if (imm != null) {
@@ -2322,10 +2326,14 @@
         if (!selectAllGotFocus && text.length() > 0) {
             // Move cursor
             final int offset = mTextView.getOffsetForPosition(event.getX(), event.getY());
-            Selection.setSelection((Spannable) text, offset);
-            if (mSpellChecker != null) {
-                // When the cursor moves, the word that was typed may need spell check
-                mSpellChecker.onSelectionChanged();
+
+            final boolean shouldInsertCursor = !mRequestingLinkActionMode;
+            if (shouldInsertCursor) {
+                Selection.setSelection((Spannable) text, offset);
+                if (mSpellChecker != null) {
+                    // When the cursor moves, the word that was typed may need spell check
+                    mSpellChecker.onSelectionChanged();
+                }
             }
 
             if (!extractedTextModeWillBeStarted()) {
@@ -2335,16 +2343,17 @@
                         mTextView.removeCallbacks(mInsertionActionModeRunnable);
                     }
 
-                    mShowSuggestionRunnable = new Runnable() {
-                        public void run() {
-                            replace();
-                        }
-                    };
+                    mShowSuggestionRunnable = this::replace;
+
                     // removeCallbacks is performed on every touch
                     mTextView.postDelayed(mShowSuggestionRunnable,
                             ViewConfiguration.getDoubleTapTimeout());
                 } else if (hasInsertionController()) {
-                    getInsertionController().show();
+                    if (shouldInsertCursor) {
+                        getInsertionController().show();
+                    } else {
+                        getInsertionController().hide();
+                    }
                 }
             }
         }
@@ -4170,6 +4179,7 @@
             }
 
             mAssistClickHandlers.clear();
+            mRequestingLinkActionMode = false;
         }
 
         @Override
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 6e855ba..05204d0 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -71,7 +71,7 @@
     private final TextClassificationHelper mTextClassificationHelper;
     private final TextClassificationConstants mTextClassificationSettings;
 
-    private TextClassification mTextClassification;
+    @Nullable private TextClassification mTextClassification;
     private AsyncTask mTextClassificationAsyncTask;
 
     private final SelectionTracker mSelectionTracker;
@@ -124,7 +124,8 @@
                             : mTextClassificationHelper::classifyText,
                     mSmartSelectSprite != null
                             ? this::startSelectionActionModeWithSmartSelectAnimation
-                            : this::startSelectionActionMode)
+                            : this::startSelectionActionMode,
+                    mTextClassificationHelper::getOriginalSelection)
                     .execute();
         }
     }
@@ -143,7 +144,8 @@
                     mTextView,
                     mTextClassificationHelper.getTimeoutDuration(),
                     mTextClassificationHelper::classifyText,
-                    this::startLinkActionMode)
+                    this::startLinkActionMode,
+                    mTextClassificationHelper::getOriginalSelection)
                     .execute();
         }
     }
@@ -158,7 +160,8 @@
                     mTextView,
                     mTextClassificationHelper.getTimeoutDuration(),
                     mTextClassificationHelper::classifyText,
-                    this::invalidateActionMode)
+                    this::invalidateActionMode,
+                    mTextClassificationHelper::getOriginalSelection)
                     .execute();
         }
     }
@@ -822,6 +825,7 @@
         private final int mTimeOutDuration;
         private final Supplier<SelectionResult> mSelectionResultSupplier;
         private final Consumer<SelectionResult> mSelectionResultCallback;
+        private final Supplier<SelectionResult> mTimeOutResultSupplier;
         private final TextView mTextView;
         private final String mOriginalText;
 
@@ -830,16 +834,19 @@
          * @param timeOut time in milliseconds to timeout the query if it has not completed
          * @param selectionResultSupplier fetches the selection results. Runs on a background thread
          * @param selectionResultCallback receives the selection results. Runs on the UiThread
+         * @param timeOutResultSupplier default result if the task times out
          */
         TextClassificationAsyncTask(
                 @NonNull TextView textView, int timeOut,
                 @NonNull Supplier<SelectionResult> selectionResultSupplier,
-                @NonNull Consumer<SelectionResult> selectionResultCallback) {
+                @NonNull Consumer<SelectionResult> selectionResultCallback,
+                @NonNull Supplier<SelectionResult> timeOutResultSupplier) {
             super(textView != null ? textView.getHandler() : null);
             mTextView = Preconditions.checkNotNull(textView);
             mTimeOutDuration = timeOut;
             mSelectionResultSupplier = Preconditions.checkNotNull(selectionResultSupplier);
             mSelectionResultCallback = Preconditions.checkNotNull(selectionResultCallback);
+            mTimeOutResultSupplier = Preconditions.checkNotNull(timeOutResultSupplier);
             // Make a copy of the original text.
             mOriginalText = getText(mTextView).toString();
         }
@@ -863,7 +870,7 @@
 
         private void onTimeOut() {
             if (getStatus() == Status.RUNNING) {
-                onPostExecute(null);
+                onPostExecute(mTimeOutResultSupplier.get());
             }
             cancel(true);
         }
@@ -963,6 +970,10 @@
             return performClassification(selection);
         }
 
+        public SelectionResult getOriginalSelection() {
+            return new SelectionResult(mSelectionStart, mSelectionEnd, null, null);
+        }
+
         /**
          * Maximum time (in milliseconds) to wait for a textclassifier result before timing out.
          */
@@ -1025,14 +1036,14 @@
     private static final class SelectionResult {
         private final int mStart;
         private final int mEnd;
-        private final TextClassification mClassification;
+        @Nullable private final TextClassification mClassification;
         @Nullable private final TextSelection mSelection;
 
         SelectionResult(int start, int end,
-                TextClassification classification, @Nullable TextSelection selection) {
+                @Nullable TextClassification classification, @Nullable TextSelection selection) {
             mStart = start;
             mEnd = end;
-            mClassification = Preconditions.checkNotNull(classification);
+            mClassification = classification;
             mSelection = selection;
         }
     }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index c366a91..7b1acb1 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -644,8 +644,12 @@
      */
     private Layout mSavedMarqueeModeLayout;
 
+    // Do not update following mText/mSpannable/mPrecomputed except for setTextInternal()
     @ViewDebug.ExportedProperty(category = "text")
-    private CharSequence mText;
+    private @Nullable CharSequence mText;
+    private @Nullable Spannable mSpannable;
+    private @Nullable PrecomputedText mPrecomputed;
+
     private CharSequence mTransformed;
     private BufferType mBufferType = BufferType.NORMAL;
 
@@ -874,7 +878,7 @@
             setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_YES);
         }
 
-        mText = "";
+        setTextInternal("");
 
         final Resources res = getResources();
         final CompatibilityInfo compat = res.getCompatibilityInfo();
@@ -1615,6 +1619,13 @@
         }
     }
 
+    // Update mText and mPrecomputed
+    private void setTextInternal(@Nullable CharSequence text) {
+        mText = text;
+        mSpannable = (text instanceof Spannable) ? (Spannable) text : null;
+        mPrecomputed = (text instanceof PrecomputedText) ? (PrecomputedText) text : null;
+    }
+
     /**
      * Specify whether this widget should automatically scale the text to try to perfectly fit
      * within the layout bounds by using the default auto-size configuration.
@@ -1973,9 +1984,9 @@
                         }
                     }
                 }
-            } else if (mText instanceof Spannable) {
+            } else if (mSpannable != null) {
                 // Reset the selection.
-                Selection.setSelection((Spannable) mText, getSelectionEnd());
+                Selection.setSelection(mSpannable, getSelectionEnd());
             }
         }
     }
@@ -2359,7 +2370,7 @@
         if (mMovement != movement) {
             mMovement = movement;
 
-            if (movement != null && !(mText instanceof Spannable)) {
+            if (movement != null && mSpannable == null) {
                 setText(mText);
             }
 
@@ -2409,8 +2420,8 @@
             return;
         }
         if (mTransformation != null) {
-            if (mText instanceof Spannable) {
-                ((Spannable) mText).removeSpan(mTransformation);
+            if (mSpannable != null) {
+                mSpannable.removeSpan(mTransformation);
             }
         }
 
@@ -5254,7 +5265,7 @@
         ((Editable) mText).append(text, start, end);
 
         if (mAutoLinkMask != 0) {
-            boolean linksWereAdded = Linkify.addLinks((Spannable) mText, mAutoLinkMask);
+            boolean linksWereAdded = Linkify.addLinks(mSpannable, mAutoLinkMask);
             // Do not change the movement method for text that support text selection as it
             // would prevent an arbitrary cursor displacement.
             if (linksWereAdded && mLinksClickable && !textCanBeSelected()) {
@@ -5413,7 +5424,7 @@
         }
 
         if (ss.selStart >= 0 && ss.selEnd >= 0) {
-            if (mText instanceof Spannable) {
+            if (mSpannable != null) {
                 int len = mText.length();
 
                 if (ss.selStart > len || ss.selEnd > len) {
@@ -5426,7 +5437,7 @@
                     Log.e(LOG_TAG, "Saved cursor position " + ss.selStart + "/" + ss.selEnd
                             + " out of range for " + restored + "text " + mText);
                 } else {
-                    Selection.setSelection((Spannable) mText, ss.selStart, ss.selEnd);
+                    Selection.setSelection(mSpannable, ss.selStart, ss.selEnd);
 
                     if (ss.frozenWithFocus) {
                         createEditorIfNeeded();
@@ -5688,7 +5699,7 @@
                  * movement method, because setMovementMethod() may call
                  * setText() again to try to upgrade the buffer type.
                  */
-                mText = text;
+                setTextInternal(text);
 
                 // Do not change the movement method for text that support text selection as it
                 // would prevent an arbitrary cursor displacement.
@@ -5699,7 +5710,7 @@
         }
 
         mBufferType = type;
-        mText = text;
+        setTextInternal(text);
 
         if (mTransformation == null) {
             mTransformed = text;
@@ -5825,8 +5836,8 @@
         setText(text, type);
 
         if (start >= 0 || end >= 0) {
-            if (mText instanceof Spannable) {
-                Selection.setSelection((Spannable) mText,
+            if (mSpannable != null) {
+                Selection.setSelection(mSpannable,
                                        Math.max(0, Math.min(start, len)),
                                        Math.max(0, Math.min(end, len)));
             }
@@ -6020,7 +6031,7 @@
         }
 
         if (!isSuggestionsEnabled()) {
-            mText = removeSuggestionSpans(mText);
+            setTextInternal(removeSuggestionSpans(mText));
         }
 
         InputMethodManager imm = InputMethodManager.peekInstance();
@@ -6948,8 +6959,7 @@
     public boolean hasOverlappingRendering() {
         // horizontal fading edge causes SaveLayerAlpha, which doesn't support alpha modulation
         return ((getBackground() != null && getBackground().getCurrent() != null)
-                || mText instanceof Spannable || hasSelection()
-                || isHorizontalFadingEdgeEnabled());
+                || mSpannable != null || hasSelection() || isHorizontalFadingEdgeEnabled());
     }
 
     /**
@@ -7399,11 +7409,11 @@
 
     @Override
     public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) {
-        if (mText instanceof Spannable && mLinksClickable) {
+        if (mSpannable != null && mLinksClickable) {
             final float x = event.getX(pointerIndex);
             final float y = event.getY(pointerIndex);
             final int offset = getOffsetForPosition(x, y);
-            final ClickableSpan[] clickables = ((Spannable) mText).getSpans(offset, offset,
+            final ClickableSpan[] clickables = mSpannable.getSpans(offset, offset,
                     ClickableSpan.class);
             if (clickables.length > 0) {
                 return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_HAND);
@@ -7496,10 +7506,10 @@
 
         } else if (which == KEY_DOWN_HANDLED_BY_MOVEMENT_METHOD) {
             // mMovement is not null from doKeyDown
-            mMovement.onKeyUp(this, (Spannable) mText, keyCode, up);
+            mMovement.onKeyUp(this, mSpannable, keyCode, up);
             while (--repeatCount > 0) {
-                mMovement.onKeyDown(this, (Spannable) mText, keyCode, down);
-                mMovement.onKeyUp(this, (Spannable) mText, keyCode, up);
+                mMovement.onKeyDown(this, mSpannable, keyCode, down);
+                mMovement.onKeyUp(this, mSpannable, keyCode, up);
             }
         }
 
@@ -7694,8 +7704,7 @@
             boolean doDown = true;
             if (otherEvent != null) {
                 try {
-                    boolean handled = mMovement.onKeyOther(this, (Spannable) mText,
-                            otherEvent);
+                    boolean handled = mMovement.onKeyOther(this, mSpannable, otherEvent);
                     doDown = false;
                     if (handled) {
                         return KEY_EVENT_HANDLED;
@@ -7706,7 +7715,7 @@
                 }
             }
             if (doDown) {
-                if (mMovement.onKeyDown(this, (Spannable) mText, keyCode, event)) {
+                if (mMovement.onKeyDown(this, mSpannable, keyCode, event)) {
                     if (event.getRepeatCount() == 0 && !KeyEvent.isModifierKey(keyCode)) {
                         mPreventDefaultMovement = true;
                     }
@@ -7848,7 +7857,7 @@
         }
 
         if (mMovement != null && mLayout != null) {
-            if (mMovement.onKeyUp(this, (Spannable) mText, keyCode, event)) {
+            if (mMovement.onKeyUp(this, mSpannable, keyCode, event)) {
                 return true;
             }
         }
@@ -8314,13 +8323,23 @@
     }
 
     /**
+     * Returns true if DynamicLayout is required
+     *
+     * @hide
+     */
+    @VisibleForTesting
+    public boolean useDynamicLayout() {
+        return isTextSelectable() || (mSpannable != null && mPrecomputed == null);
+    }
+
+    /**
      * @hide
      */
     protected Layout makeSingleLayout(int wantWidth, BoringLayout.Metrics boring, int ellipsisWidth,
             Layout.Alignment alignment, boolean shouldEllipsize, TruncateAt effectiveEllipsize,
             boolean useSaved) {
         Layout result = null;
-        if (mText instanceof Spannable) {
+        if (useDynamicLayout()) {
             final DynamicLayout.Builder builder = DynamicLayout.Builder.obtain(mText, mTextPaint,
                     wantWidth)
                     .setDisplayText(mTransformed)
@@ -9262,7 +9281,7 @@
         }
 
         if (newStart != start) {
-            Selection.setSelection((Spannable) mText, newStart);
+            Selection.setSelection(mSpannable, newStart);
             return true;
         }
 
@@ -9999,9 +10018,8 @@
         if (mEditor != null) mEditor.onFocusChanged(focused, direction);
 
         if (focused) {
-            if (mText instanceof Spannable) {
-                Spannable sp = (Spannable) mText;
-                MetaKeyKeyListener.resetMetaState(sp);
+            if (mSpannable != null) {
+                MetaKeyKeyListener.resetMetaState(mSpannable);
             }
         }
 
@@ -10039,7 +10057,7 @@
      */
     public void clearComposingText() {
         if (mText instanceof Spannable) {
-            BaseInputConnection.removeComposingSpans((Spannable) mText);
+            BaseInputConnection.removeComposingSpans(mSpannable);
         }
     }
 
@@ -10095,7 +10113,7 @@
             boolean handled = false;
 
             if (mMovement != null) {
-                handled |= mMovement.onTouchEvent(this, (Spannable) mText, event);
+                handled |= mMovement.onTouchEvent(this, mSpannable, event);
             }
 
             final boolean textIsSelectable = isTextSelectable();
@@ -10103,7 +10121,7 @@
                 // The LinkMovementMethod which should handle taps on links has not been installed
                 // on non editable text that support text selection.
                 // We reproduce its behavior here to open links for these.
-                ClickableSpan[] links = ((Spannable) mText).getSpans(getSelectionStart(),
+                ClickableSpan[] links = mSpannable.getSpans(getSelectionStart(),
                     getSelectionEnd(), ClickableSpan.class);
 
                 if (links.length > 0) {
@@ -10138,7 +10156,7 @@
     public boolean onGenericMotionEvent(MotionEvent event) {
         if (mMovement != null && mText instanceof Spannable && mLayout != null) {
             try {
-                if (mMovement.onGenericMotionEvent(this, (Spannable) mText, event)) {
+                if (mMovement.onGenericMotionEvent(this, mSpannable, event)) {
                     return true;
                 }
             } catch (AbstractMethodError ex) {
@@ -10199,8 +10217,8 @@
 
     @Override
     public boolean onTrackballEvent(MotionEvent event) {
-        if (mMovement != null && mText instanceof Spannable && mLayout != null) {
-            if (mMovement.onTrackballEvent(this, (Spannable) mText, event)) {
+        if (mMovement != null && mSpannable != null && mLayout != null) {
+            if (mMovement.onTrackballEvent(this, mSpannable, event)) {
                 return true;
             }
         }
@@ -11121,7 +11139,7 @@
                 if (mText != null) {
                     int updatedTextLength = mText.length();
                     if (updatedTextLength > 0) {
-                        Selection.setSelection((Spannable) mText, updatedTextLength);
+                        Selection.setSelection(mSpannable, updatedTextLength);
                     }
                 }
             } return true;
@@ -11593,6 +11611,13 @@
         }
     }
 
+    /** @hide */
+    public void hideFloatingToolbar(int durationMs) {
+        if (mEditor != null) {
+            mEditor.hideFloatingToolbar(durationMs);
+        }
+    }
+
     boolean canUndo() {
         return mEditor != null && mEditor.canUndo();
     }
@@ -11687,10 +11712,10 @@
     boolean selectAllText() {
         if (mEditor != null) {
             // Hide the toolbar before changing the selection to avoid flickering.
-            mEditor.hideFloatingToolbar(FLOATING_TOOLBAR_SELECT_ALL_REFRESH_DELAY);
+            hideFloatingToolbar(FLOATING_TOOLBAR_SELECT_ALL_REFRESH_DELAY);
         }
         final int length = mText.length();
-        Selection.setSelection((Spannable) mText, 0, length);
+        Selection.setSelection(mSpannable, 0, length);
         return length > 0;
     }
 
@@ -11718,7 +11743,7 @@
                 }
                 if (paste != null) {
                     if (!didFirst) {
-                        Selection.setSelection((Spannable) mText, max);
+                        Selection.setSelection(mSpannable, max);
                         ((Editable) mText).replace(min, max, paste);
                         didFirst = true;
                     } else {
@@ -11740,7 +11765,7 @@
             selectedText = TextUtils.trimToParcelableSize(selectedText);
             sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, selectedText);
             getContext().startActivity(Intent.createChooser(sharingIntent, null));
-            Selection.setSelection((Spannable) mText, getSelectionEnd());
+            Selection.setSelection(mSpannable, getSelectionEnd());
         }
     }
 
@@ -11815,7 +11840,7 @@
             case DragEvent.ACTION_DRAG_LOCATION:
                 if (mText instanceof Spannable) {
                     final int offset = getOffsetForPosition(event.getX(), event.getY());
-                    Selection.setSelection((Spannable) mText, offset);
+                    Selection.setSelection(mSpannable, offset);
                 }
                 return true;
 
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 28a7c12..cbd3ad5 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -53,10 +53,21 @@
     public static final int DISABLE_VERIFIER = 1 << 9;
     /** Only use oat files located in /system. Otherwise use dex/jar/apk . */
     public static final int ONLY_USE_SYSTEM_OAT_FILES = 1 << 10;
-    /** Do enfore hidden API access restrictions. */
-    public static final int ENABLE_HIDDEN_API_CHECKS = 1 << 11;
     /** Force generation of native debugging information for backtraces. */
-    public static final int DEBUG_GENERATE_MINI_DEBUG_INFO = 1 << 12;
+    public static final int DEBUG_GENERATE_MINI_DEBUG_INFO = 1 << 11;
+    /**
+     * Hidden API access restrictions. This is a mask for bits representing the API enforcement
+     * policy, defined by {@code @ApplicationInfo.HiddenApiEnforcementPolicy}.
+     */
+    public static final int API_ENFORCEMENT_POLICY_MASK = (1 << 12) | (1 << 13);
+    /**
+     * Bit shift for use with {@link #API_ENFORCEMENT_POLICY_MASK}.
+     *
+     * (flags & API_ENFORCEMENT_POLICY_MASK) >> API_ENFORCEMENT_POLICY_SHIFT gives
+     * @ApplicationInfo.ApiEnforcementPolicy values.
+     */
+    public static final int API_ENFORCEMENT_POLICY_SHIFT =
+            Integer.numberOfTrailingZeros(API_ENFORCEMENT_POLICY_MASK);
 
     /** No external storage should be mounted. */
     public static final int MOUNT_EXTERNAL_NONE = IVold.REMOUNT_MODE_NONE;
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 66035f4..9467ecc 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -652,7 +652,7 @@
         String args[] = {
             "--setuid=1000",
             "--setgid=1000",
-            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1032,1065,3001,3002,3003,3006,3007,3009,3010",
+            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1024,1032,1065,3001,3002,3003,3006,3007,3009,3010",
             "--capabilities=" + capabilities + "," + capabilities,
             "--nice-name=system_server",
             "--runtime-args",
diff --git a/core/java/com/android/server/NetworkManagementSocketTagger.java b/core/java/com/android/server/NetworkManagementSocketTagger.java
index 03f2bc1..2959667 100644
--- a/core/java/com/android/server/NetworkManagementSocketTagger.java
+++ b/core/java/com/android/server/NetworkManagementSocketTagger.java
@@ -67,6 +67,10 @@
         return old;
     }
 
+    public static int getThreadSocketStatsUid() {
+        return threadSocketTags.get().statsUid;
+    }
+
     @Override
     public void tag(FileDescriptor fd) throws SocketException {
         final SocketTags options = threadSocketTags.get();
diff --git a/core/proto/README.md b/core/proto/README.md
index d2b89a5..78809fa 100644
--- a/core/proto/README.md
+++ b/core/proto/README.md
@@ -8,7 +8,7 @@
 1. If the proto describes the top level output of dumpsys, it should contain
    `Dump`. This makes it easy to understand that the proto is the dumpsys output
    of a certain service, not the data structure of that service, e.g.
-   `WindowManagerServiceDumpProto` vs `WindowManagerServiceDumpProto`.
+   `WindowManagerServiceDumpProto` vs `WindowManagerServiceProto`.
 
    * Inner messages whose containing messages have the `Proto` suffix do not
      need to have a `Proto` suffix. E.g:
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index 89665db..7f8bed5 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -20,6 +20,8 @@
 option java_multiple_files = true;
 option java_outer_classname = "SettingsServiceProto";
 
+import "frameworks/base/core/proto/android/providers/settings/common.proto";
+import "frameworks/base/core/proto/android/providers/settings/global.proto";
 import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 message SettingsServiceDumpProto {
@@ -47,470 +49,6 @@
 
 // Note: it's a conscious decision to add each setting as a separate field. This
 // allows annotating each setting with its own privacy tag.
-message GlobalSettingsProto {
-    option (android.msg_privacy).dest = DEST_EXPLICIT;
-
-    repeated SettingsOperationProto historical_operations = 1;
-
-    optional SettingProto add_users_when_locked = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto enable_accessibility_global_gesture_enabled = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto airplane_mode_on = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto theater_mode_on = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    // A comma-separated list of radios that need to be disabled when airplane
-    // mode is on. This overrides wifi_on and bluetooth_on if wifi and bluetooth
-    // are included in the comma-separated list.
-    optional SettingProto airplane_mode_radios = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto airplane_mode_toggleable_radios = 7 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto bluetooth_class_of_device = 8 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto bluetooth_disabled_profiles = 9;
-    optional SettingProto bluetooth_interoperability_list = 10;
-    optional SettingProto wifi_sleep_policy = 11 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto auto_time = 12 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto auto_time_zone = 13 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto car_dock_sound = 14;
-    optional SettingProto car_undock_sound = 15;
-    optional SettingProto desk_dock_sound = 16;
-    optional SettingProto desk_undock_sound = 17;
-    optional SettingProto dock_sounds_enabled = 18 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto dock_sounds_enabled_when_accessibility = 19 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto lock_sound = 20;
-    optional SettingProto unlock_sound = 21;
-    optional SettingProto trusted_sound = 22;
-    optional SettingProto low_battery_sound = 23;
-    optional SettingProto power_sounds_enabled = 24 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wireless_charging_started_sound = 25;
-    optional SettingProto charging_sounds_enabled = 26 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto stay_on_while_plugged_in = 27 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto bugreport_in_power_menu = 28 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto adb_enabled = 29 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    // Whether views are allowed to save their attribute data.
-    optional SettingProto debug_view_attributes = 30 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto assisted_gps_enabled = 31 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto bluetooth_on = 32 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto cdma_cell_broadcast_sms = 33 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto cdma_roaming_mode = 34 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto cdma_subscription_mode = 35 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto data_activity_timeout_mobile = 36 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto data_activity_timeout_wifi = 37 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto data_roaming = 38 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto mdc_initial_max_retry = 39 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto force_allow_on_external = 40 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto euicc_provisioned = 41 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto development_force_resizable_activities = 42 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto development_enable_freeform_windows_support = 43 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto development_settings_enabled = 44 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto device_provisioned = 45 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto device_provisioning_mobile_data_enabled = 46 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto display_size_forced = 47 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto display_scaling_force = 48 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto download_max_bytes_over_mobile = 49 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto download_recommended_max_bytes_over_mobile = 50 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto hdmi_control_enabled = 51 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto hdmi_system_audio_control_enabled = 52 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto hdmi_control_auto_wakeup_enabled = 53 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto hdmi_control_auto_device_off_enabled = 54 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    // If true, out-of-the-box execution for priv apps is enabled.
-    optional SettingProto priv_app_oob_enabled = 55 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto location_background_throttle_interval_ms = 56 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto location_background_throttle_proximity_alert_interval_ms = 57 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    // Packages that are whitelisted for background throttling (throttling will
-    // not be applied).
-    optional SettingProto location_background_throttle_package_whitelist = 58 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_scan_background_throttle_interval_ms = 59 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_scan_background_throttle_package_whitelist = 60 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto mhl_input_switching_enabled = 61 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto mhl_power_charge_enabled = 62 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto mobile_data = 63 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto mobile_data_always_on = 64 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto connectivity_metrics_buffer_size = 65 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto netstats_enabled = 66 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto netstats_poll_interval = 67 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto netstats_time_cache_max_age = 68 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto netstats_global_alert_bytes = 69 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto netstats_sample_enabled = 70 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto netstats_augment_enabled = 71 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto netstats_dev_bucket_duration = 72 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto netstats_dev_persist_bytes = 73 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto netstats_dev_rotate_age = 74 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto netstats_dev_delete_age = 75 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto netstats_uid_bucket_duration = 76 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto netstats_uid_persist_bytes = 77 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto netstats_uid_rotate_age = 78 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto netstats_uid_delete_age = 79 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto netstats_uid_tag_bucket_duration = 80 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto netstats_uid_tag_persist_bytes = 81 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto netstats_uid_tag_rotate_age = 82 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto netstats_uid_tag_delete_age = 83 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    // User preference for which network(s) should be used.
-    optional SettingProto network_preference = 84;
-    optional SettingProto network_scorer_app = 85 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto night_display_forced_auto_mode_available = 86 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto nitz_update_diff = 87 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto nitz_update_spacing = 88 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto ntp_server = 89;
-    optional SettingProto ntp_timeout = 90 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto storage_benchmark_interval = 91 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto dns_resolver_sample_validity_seconds = 92 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto dns_resolver_success_threshold_percent = 93 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto dns_resolver_min_samples = 94 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto dns_resolver_max_samples = 95 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    // Whether to disable the automatic scheduling of system updates.
-    optional SettingProto ota_disable_automatic_update = 96 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto package_verifier_enable = 97 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto package_verifier_timeout = 98 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto package_verifier_default_response = 99;
-    optional SettingProto package_verifier_setting_visible = 100 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto package_verifier_include_adb = 101 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto fstrim_mandatory_interval = 102 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto pdp_watchdog_poll_interval_ms = 103 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto pdp_watchdog_long_poll_interval_ms = 104 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto pdp_watchdog_error_poll_interval_ms = 105 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto pdp_watchdog_trigger_packet_count = 106 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto pdp_watchdog_error_poll_count = 107 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto pdp_watchdog_max_pdp_reset_fail_count = 108 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto setup_prepaid_data_service_url = 109;
-    optional SettingProto setup_prepaid_detection_target_url = 110;
-    optional SettingProto setup_prepaid_detection_redir_host = 111;
-    optional SettingProto sms_outgoing_check_interval_ms = 112 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto sms_outgoing_check_max_count = 113 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    // Used to disable SMS short code confirmation. Defaults to true.
-    optional SettingProto sms_short_code_confirmation = 114 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto sms_short_code_rule = 115 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto tcp_default_init_rwnd = 116 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto tether_supported = 117 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto tether_dun_required = 118 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto tether_dun_apn = 119;
-    optional SettingProto tether_offload_disabled = 120 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    // List of carrier app certificate mapped to carrier app package id which are whitelisted to
-    // prompt the user for install when a SIM card with matching UICC carrier privilege rules is
-    // inserted.
-    optional SettingProto carrier_app_whitelist = 121 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto carrier_app_names = 122 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto usb_mass_storage_enabled = 123 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto use_google_mail = 124 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto webview_data_reduction_proxy_key = 125;
-    optional SettingProto webview_fallback_logic_enabled = 126 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    // Name of the package used as WebView provider.
-    optional SettingProto webview_provider = 127 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto webview_multiprocess = 128 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto network_switch_notification_daily_limit = 129 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto network_switch_notification_rate_limit_millis = 130 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto network_avoid_bad_wifi = 131 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto network_metered_multipath_preference = 132 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto network_watchlist_last_report_time = 133 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_badging_thresholds = 134 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_display_on = 135 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_display_certification_on = 136 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_display_wps_config = 137 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_networks_available_notification_on = 138 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_carrier_networks_available_notification_on = 139 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wimax_networks_available_notification_on = 140 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_networks_available_repeat_delay = 141 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_country_code = 142;
-    optional SettingProto wifi_framework_scan_interval_ms = 143 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_idle_ms = 144 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_num_open_networks_kept = 145 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_on = 146 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_scan_always_available = 147 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto soft_ap_timeout_enabled = 148 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_wakeup_enabled = 149 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto network_scoring_ui_enabled = 150 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto speed_label_cache_eviction_age_millis = 151 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto recommended_network_evaluator_cache_expiry_ms = 152 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto network_recommendations_enabled = 153 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto network_recommendations_package = 154 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto use_open_wifi_package = 155 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto network_recommendation_request_timeout_ms = 156 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto ble_scan_always_available = 157 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto ble_scan_low_power_window_ms = 158 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto ble_scan_balanced_window_ms = 159 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto ble_scan_low_latency_window_ms = 160 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto ble_scan_low_power_interval_ms = 161 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto ble_scan_balanced_interval_ms = 162 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto ble_scan_low_latency_interval_ms = 163 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto ble_scan_background_mode = 389 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_saved_state = 164 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_supplicant_scan_interval_ms = 165 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_enhanced_auto_join = 166 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_network_show_rssi = 167 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_scan_interval_when_p2p_connected_ms = 168 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_watchdog_on = 169 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_watchdog_poor_network_test_enabled = 170 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_suspend_optimizations_enabled = 171 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_verbose_logging_enabled = 172 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_connected_mac_randomization_enabled = 173 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_max_dhcp_retry_count = 174 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_mobile_data_transition_wakelock_timeout_ms = 175 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_device_owner_configs_lockdown = 176 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_frequency_band = 177 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_p2p_device_name = 178;
-    optional SettingProto wifi_reenable_delay_ms = 179 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_ephemeral_out_of_range_timeout_ms = 180 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto data_stall_alarm_non_aggressive_delay_in_ms = 181 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto data_stall_alarm_aggressive_delay_in_ms = 182 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto provisioning_apn_alarm_delay_in_ms = 183 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto gprs_register_check_period_ms = 184 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wtf_is_fatal = 185 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    // Ringer mode. A change in this value will not reflect as a change in the
-    // ringer mode.
-    optional SettingProto mode_ringer = 186 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    // Overlay display devices setting.
-    // The value is a specially formatted string that describes the size and
-    // density of simulated secondary devices.
-    // Format: {width}x{height}/dpi;...
-    optional SettingProto overlay_display_devices = 187 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto battery_discharge_duration_threshold = 188 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto battery_discharge_threshold = 189 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto send_action_app_error = 190 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto dropbox_age_seconds = 191 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto dropbox_max_files = 192 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto dropbox_quota_kb = 193 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto dropbox_quota_percent = 194 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto dropbox_reserve_percent = 195 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    repeated SettingProto dropbox_settings = 196;
-    repeated SettingProto error_logcat_lines = 197;
-    optional SettingProto sys_free_storage_log_interval = 198 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto disk_free_change_reporting_threshold = 199 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto sys_storage_threshold_percentage = 200 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto sys_storage_threshold_max_bytes = 201 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto sys_storage_full_threshold_bytes = 202 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto sys_storage_cache_percentage = 203 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto sys_storage_cache_max_bytes = 204 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto sync_max_retry_delay_in_seconds = 205 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto connectivity_change_delay = 206 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto connectivity_sampling_interval_in_seconds = 207 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto pac_change_delay = 208 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto captive_portal_mode = 209 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto captive_portal_detection_enabled = 210 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto captive_portal_server = 211;
-    optional SettingProto captive_portal_https_url = 212;
-    optional SettingProto captive_portal_http_url = 213;
-    optional SettingProto captive_portal_fallback_url = 214;
-    optional SettingProto captive_portal_other_fallback_urls = 215;
-    optional SettingProto captive_portal_use_https = 216 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto captive_portal_user_agent = 217;
-    optional SettingProto nsd_on = 218 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    // Let user pick default install location.
-    optional SettingProto set_install_location = 219 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto default_install_location = 220 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto inet_condition_debounce_up_delay = 221 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto inet_condition_debounce_down_delay = 222 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto read_external_storage_enforced_default = 223 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto http_proxy = 224;
-    optional SettingProto global_http_proxy_host = 225;
-    optional SettingProto global_http_proxy_port = 226;
-    optional SettingProto global_http_proxy_exclusion_list = 227;
-    optional SettingProto global_http_proxy_pac = 228;
-    // Enables the UI setting to allow the user to specify the global HTTP proxy
-    // and associated exclusion list.
-    optional SettingProto set_global_http_proxy = 229 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto default_dns_server = 230;
-    // The requested Private DNS mode and an accompanying specifier.
-    optional SettingProto private_dns_mode = 231;
-    optional SettingProto private_dns_specifier = 232;
-    repeated SettingProto bluetooth_headset_priorities = 233;
-    repeated SettingProto bluetooth_a2dp_sink_priorities = 234;
-    repeated SettingProto bluetooth_a2dp_src_priorities = 235;
-    repeated SettingProto bluetooth_a2dp_supports_optional_codecs = 236;
-    repeated SettingProto bluetooth_a2dp_optional_codecs_enabled = 237;
-    repeated SettingProto bluetooth_input_device_priorities = 238;
-    repeated SettingProto bluetooth_map_priorities = 239;
-    repeated SettingProto bluetooth_map_client_priorities = 240;
-    repeated SettingProto bluetooth_pbap_client_priorities = 241;
-    repeated SettingProto bluetooth_sap_priorities = 242;
-    repeated SettingProto bluetooth_pan_priorities = 243;
-    repeated SettingProto bluetooth_hearing_aid_priorities = 244;
-    // These are key=value lists, separated by commas.
-    optional SettingProto activity_manager_constants = 245;
-    optional SettingProto device_idle_constants = 246;
-    optional SettingProto battery_saver_constants = 247;
-    optional SettingProto battery_saver_device_specific_constants = 248;
-    optional SettingProto battery_tip_constants = 249;
-    optional SettingProto anomaly_detection_constants = 250;
-    // Version of the anomaly config.
-    optional SettingProto anomaly_config_version = 251 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    // A base64-encoded string represents anomaly stats config.
-    optional SettingProto anomaly_config = 252;
-    // This is a key=value list, separated by commas.
-    optional SettingProto always_on_display_constants = 253;
-    // System VDSO global setting. This links to the "sys.vdso" system property.
-    // The following values are supported:
-    // false  -> both 32 and 64 bit vdso disabled
-    // 32     -> 32 bit vdso enabled
-    // 64     -> 64 bit vdso enabled
-    // Any other value defaults to both 32 bit and 64 bit true.
-    optional SettingProto sys_vdso = 254 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    // UidCpuPower global setting. This links the sys.uidcpupower system property.
-    // The following values are supported:
-    // 0 -> /proc/uid_cpupower/* are disabled
-    // 1 -> /proc/uid_cpupower/* are enabled
-    // Any other value defaults to enabled.
-    optional SettingProto sys_uidcpupower = 255 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    // An integer to reduce the FPS by this factor. Only for experiments.
-    optional SettingProto fps_divisor = 256 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    // Flag to enable or disable display panel low power mode (lpm)
-    // false -> Display panel power saving mode is disabled.
-    // true  -> Display panel power saving mode is enabled.
-    optional SettingProto display_panel_lpm = 257 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    // These are key=value lists, separated by commas.
-    optional SettingProto app_idle_constants = 258;
-    optional SettingProto power_manager_constants = 259;
-    optional SettingProto alarm_manager_constants = 260;
-    optional SettingProto job_scheduler_constants = 261;
-    optional SettingProto shortcut_manager_constants = 262;
-    optional SettingProto device_policy_constants = 263;
-    optional SettingProto text_classifier_constants = 264;
-    optional SettingProto battery_stats_constants = 265;
-    optional SettingProto sync_manager_constants = 266;
-    optional SettingProto app_standby_enabled = 267 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto app_auto_restriction_enabled = 268 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto forced_app_standby_enabled = 269 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto forced_app_standby_for_small_battery_enabled = 270 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto off_body_radios_off_for_small_battery_enabled = 271 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto off_body_radios_off_delay_ms = 272 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_on_when_proxy_disconnected = 273 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto time_only_mode_constants = 274 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto network_watchlist_enabled = 275 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto keep_profile_in_background = 276 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto window_animation_scale = 277 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto transition_animation_scale = 278 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto animator_duration_scale = 279 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto fancy_ime_animations = 280 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto compatibility_mode = 281 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto emergency_tone = 282 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto call_auto_retry = 283 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto emergency_affordance_needed = 284 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto preferred_network_mode = 285 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    // Name of an application package to be debugged.
-    optional SettingProto debug_app = 286;
-    optional SettingProto wait_for_debugger = 287 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto enable_gpu_debug_layers = 288 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    // App allowed to load GPU debug layers.
-    optional SettingProto gpu_debug_app = 289;
-    optional SettingProto gpu_debug_layers = 290 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto low_power_mode = 291 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    // Battery level [1-100] at which low power mode automatically turns on. If
-    // 0, it will not automatically turn on.
-    optional SettingProto low_power_mode_trigger_level = 292 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    // The max value for {@link #LOW_POWER_MODE_TRIGGER_LEVEL}. If this setting
-    // is not set or the value is 0, the default max will be used.
-    optional SettingProto low_power_mode_trigger_level_max = 293 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto always_finish_activities = 294 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto dock_audio_media_enabled = 295 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto encoded_surround_output = 296 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto audio_safe_volume_state = 297 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto tzinfo_update_content_url = 298;
-    optional SettingProto tzinfo_update_metadata_url = 299;
-    optional SettingProto selinux_update_content_url = 300;
-    optional SettingProto selinux_update_metadata_url = 301;
-    optional SettingProto sms_short_codes_update_content_url = 302;
-    optional SettingProto sms_short_codes_update_metadata_url = 303;
-    optional SettingProto apn_db_update_content_url = 304;
-    optional SettingProto apn_db_update_metadata_url = 305;
-    optional SettingProto cert_pin_update_content_url = 306;
-    optional SettingProto cert_pin_update_metadata_url = 307;
-    optional SettingProto intent_firewall_update_content_url = 308;
-    optional SettingProto intent_firewall_update_metadata_url = 309;
-    optional SettingProto lang_id_update_content_url = 310;
-    optional SettingProto lang_id_update_metadata_url = 311;
-    optional SettingProto smart_selection_update_content_url = 312;
-    optional SettingProto smart_selection_update_metadata_url = 313;
-    optional SettingProto selinux_status = 314 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto development_force_rtl = 315 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto low_battery_sound_timeout = 316 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_bounce_delay_override_ms = 317 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto policy_control = 318 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto emulate_display_cutout = 319 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto zen_mode = 320 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto zen_mode_ringer_level = 321 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto zen_mode_config_etag = 322;
-    // If 0, turning on dnd manually will last indefinitely. Else if
-    // non-negative, turning on dnd manually will last for this many minutes.
-    // Else (if negative), turning on dnd manually will surface a dialog that
-    // prompts user to specify a duration.
-    optional SettingProto zen_duration = 323 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto heads_up_notifications_enabled = 324 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto device_name = 325;
-    optional SettingProto network_scoring_provisioned = 326 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto require_password_to_decrypt = 327 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto enhanced_4g_mode_enabled = 328 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto vt_ims_enabled = 329 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wfc_ims_enabled = 330 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wfc_ims_mode = 331 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wfc_ims_roaming_mode = 332 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wfc_ims_roaming_enabled = 333 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto lte_service_forced = 334 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto ephemeral_cookie_max_size_bytes = 335 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto enable_ephemeral_feature = 336 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto instant_app_dexopt_enabled = 337 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto installed_instant_app_min_cache_period = 338 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto installed_instant_app_max_cache_period = 339 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto uninstalled_instant_app_min_cache_period = 340 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto uninstalled_instant_app_max_cache_period = 341 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto unused_static_shared_lib_min_cache_period = 342 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto allow_user_switching_when_system_user_locked = 343 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto boot_count = 344 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto safe_boot_disallowed = 345 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto device_demo_mode = 346 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto network_access_timeout_ms = 347 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto database_downgrade_reason = 348;
-    optional SettingProto database_creation_buildid = 349 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto contacts_database_wal_enabled = 350 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto location_settings_link_to_permissions_enabled = 351 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto euicc_factory_reset_timeout_millis = 352 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto storage_settings_clobber_threshold = 353 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    // If set to 1, {@link Secure#LOCATION_MODE} will be set to {@link
-    // Secure#LOCATION_MODE_OFF} temporarily for all users.
-    optional SettingProto location_global_kill_switch = 354 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    // If set to 1, SettingsProvider's restoreAnyVersion="true" attribute will
-    // be ignored and restoring to lower version of platform API will be
-    // skipped.
-    optional SettingProto override_settings_provider_restore_any_version = 355 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto chained_battery_attribution_enabled = 356 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto autofill_compat_mode_allowed_packages = 357 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto hidden_api_blacklist_exemptions = 358 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto sound_trigger_detection_service_op_timeout = 387  [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto max_sound_trigger_detection_service_ops_per_day = 388  [ (android.privacy).dest = DEST_AUTOMATIC ];
-    // Subscription to be used for voice call on a multi sim device. The
-    // supported values are 0 = SUB1, 1 = SUB2 and etc.
-    optional SettingProto multi_sim_voice_call_subscription = 359 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto multi_sim_voice_prompt = 360 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto multi_sim_data_call_subscription = 361 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto multi_sim_sms_subscription = 362 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto multi_sim_sms_prompt = 363 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    // Whether to enable new contacts aggregator or not.
-    // 1 = enable, 0 = disable.
-    optional SettingProto new_contact_aggregator = 364 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto contact_metadata_sync_enabled = 365 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto enable_cellular_on_boot = 366 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto max_notification_enqueue_rate = 367 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto show_notification_channel_warnings = 368 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto cell_on = 369 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto show_temperature_warning = 370 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto warning_temperature = 371 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto enable_diskstats_logging = 372 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto enable_cache_quota_calculation = 373 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto enable_deletion_helper_no_threshold_toggle = 374 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto notification_snooze_options = 375 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    // Configuration flags for SQLite Compatibility WAL. Encoded as a key-value
-    // list, separated by commas.
-    // E.g.: compatibility_wal_supported=true, wal_syncmode=OFF
-    optional SettingProto sqlite_compatibility_wal_flags = 376 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto enable_gnss_raw_meas_full_tracking = 377 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto install_carrier_app_notification_persistent = 378 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto install_carrier_app_notification_sleep_millis = 379 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto zram_enabled = 380 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto smart_replies_in_notifications_flags = 381 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto show_first_crash_dialog = 382 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto show_restart_in_crash_dialog = 383 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto show_mute_in_crash_dialog = 384 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingsProto show_zen_upgrade_notification = 385  [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingsProto backup_agent_timeout_parameters = 386;
-    // Please insert fields in the same order as in
-    // frameworks/base/core/java/android/provider/Settings.java.
-    // Next tag = 390;
-}
-
 message SecureSettingsProto {
     option (android.msg_privacy).dest = DEST_EXPLICIT;
 
@@ -854,26 +392,6 @@
     // Next tag = 73;
 }
 
-message SettingProto {
-    // ID of the setting
-    optional string id = 1;
-
-    // Name of the setting
-    optional string name = 2;
-
-    // Package name of the setting
-    optional string pkg = 3;
-
-    // Value of this setting
-    optional string value = 4;
-
-    // Default value of this setting
-    optional string default_value = 5;
-
-    // Whether the default is set by the system
-    optional bool default_from_system = 6;
-}
-
 message SettingsProto {
     // Enum values gotten from Settings.java
     enum ScreenBrightnessMode {
@@ -881,14 +399,3 @@
         SCREEN_BRIGHTNESS_MODE_AUTOMATIC = 1;
     }
 }
-
-message SettingsOperationProto {
-    // When the operation happened
-    optional int64 timestamp = 1;
-
-    // Type of the operation
-    optional string operation = 2;
-
-    // Name of the setting that was affected (optional)
-    optional string setting = 3;
-}
diff --git a/core/proto/android/providers/settings/common.proto b/core/proto/android/providers/settings/common.proto
new file mode 100644
index 0000000..64ffefb6
--- /dev/null
+++ b/core/proto/android/providers/settings/common.proto
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+package android.providers.settings;
+
+option java_multiple_files = true;
+
+message SettingProto {
+    // ID of the setting
+    optional string id = 1;
+
+    // Name of the setting
+    optional string name = 2;
+
+    // Package name of the setting
+    optional string pkg = 3;
+
+    // Value of this setting
+    optional string value = 4;
+
+    // Default value of this setting
+    optional string default_value = 5;
+
+    // Whether the default is set by the system
+    optional bool default_from_system = 6;
+}
+
+message SettingsOperationProto {
+    // When the operation happened
+    optional int64 timestamp = 1;
+
+    // Type of the operation
+    optional string operation = 2;
+
+    // Name of the setting that was affected (optional)
+    optional string setting = 3;
+}
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
new file mode 100644
index 0000000..c7de947
--- /dev/null
+++ b/core/proto/android/providers/settings/global.proto
@@ -0,0 +1,942 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+package android.providers.settings;
+
+option java_multiple_files = true;
+
+import "frameworks/base/core/proto/android/providers/settings/common.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
+// Note: it's a conscious decision to add each setting as a separate field. This
+// allows annotating each setting with its own privacy tag.
+message GlobalSettingsProto {
+    option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+    repeated SettingsOperationProto historical_operations = 1;
+
+    // These are key=value lists, separated by commas.
+    optional SettingProto activity_manager_constants = 2;
+    optional SettingProto adb_enabled = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto add_users_when_locked = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+    message AirplaneMode {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        // "airplane_mode_on" in code.
+        optional SettingProto on = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        // A comma-separated list of radios that need to be disabled when airplane
+        // mode is on. This overrides wifi_on and bluetooth_on if wifi and bluetooth
+        // are included in the comma-separated list.
+        optional SettingProto radios = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto toggleable_radios = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional AirplaneMode airplane_mode = 5;
+
+    optional SettingProto alarm_manager_constants = 6;
+    optional SettingProto allow_user_switching_when_system_user_locked = 7 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // This is a key=value list, separated by commas.
+    optional SettingProto always_on_display_constants = 8;
+    optional SettingProto always_finish_activities = 9 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto animator_duration_scale = 10 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+    message Anomaly {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        // "anomaly_detection_constants" in code.
+        optional SettingProto detection_constants = 1;
+        // Version of the anomaly config.
+        optional SettingProto config_version = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        // A base64-encoded string represents anomaly stats config.
+        optional SettingProto config = 3;
+    }
+    optional Anomaly anomaly = 11;
+
+    message ApnDb {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto update_content_url = 1;
+        optional SettingProto update_metadata_url = 2;
+    }
+    optional ApnDb apn_db = 12;
+
+    message App {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        // These are key=value lists, separated by commas.
+        optional SettingProto idle_constants = 1;
+        optional SettingProto standby_enabled = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto auto_restriction_enabled = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto forced_app_standby_enabled = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto forced_app_standby_for_small_battery_enabled = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional App app = 13;
+
+    optional SettingProto assisted_gps_enabled = 14 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto audio_safe_volume_state = 15 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+    message Auto {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto time = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto time_zone = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Auto auto = 16;
+
+    optional SettingProto autofill_compat_mode_allowed_packages = 17 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto backup_agent_timeout_parameters = 18;
+
+    message Battery {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto discharge_duration_threshold = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto discharge_threshold = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto saver_constants = 3;
+        optional SettingProto saver_device_specific_constants = 4;
+        optional SettingProto stats_constants = 5;
+        optional SettingProto tip_constants = 6;
+    }
+    optional Battery battery = 19;
+
+    message BleScan {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto always_available = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto low_power_window_ms = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto balanced_window_ms = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto low_latency_window_ms = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto low_power_interval_ms = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto balanced_interval_ms = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto low_latency_interval_ms = 7 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto background_mode = 8 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional BleScan ble_scan = 20;
+
+    message Bluetooth {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto class_of_device = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto disabled_profiles = 2;
+        optional SettingProto interoperability_list = 3;
+        optional SettingProto on = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        repeated SettingProto headset_priorities = 5;
+        repeated SettingProto a2dp_sink_priorities = 6;
+        repeated SettingProto a2dp_src_priorities = 7;
+        repeated SettingProto a2dp_supports_optional_codecs = 8;
+        repeated SettingProto a2dp_optional_codecs_enabled = 9;
+        repeated SettingProto input_device_priorities = 10;
+        repeated SettingProto map_priorities = 11;
+        repeated SettingProto map_client_priorities = 12;
+        repeated SettingProto pbap_client_priorities = 13;
+        repeated SettingProto sap_priorities = 14;
+        repeated SettingProto pan_priorities = 15;
+        repeated SettingProto hearing_aid_priorities = 16;
+    }
+    optional Bluetooth bluetooth = 21;
+
+    optional SettingProto boot_count = 22 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto bugreport_in_power_menu = 23 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto call_auto_retry = 24 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+    message CaptivePortal {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto mode = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto detection_enabled = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto server = 3;
+        optional SettingProto https_url = 4;
+        optional SettingProto http_url = 5;
+        optional SettingProto fallback_url = 6;
+        optional SettingProto other_fallback_urls = 7;
+        optional SettingProto use_https = 8 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto user_agent = 9;
+    }
+    optional CaptivePortal captive_portal = 25;
+
+    message Carrier {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        // List of carrier app certificate mapped to carrier app package id which are whitelisted to
+        // prompt the user for install when a SIM card with matching UICC carrier privilege rules is
+        // inserted.
+        optional SettingProto app_whitelist = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto app_names = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto install_carrier_app_notification_persistent = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto install_carrier_app_notification_sleep_millis = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Carrier carrier = 26;
+
+    message Cdma {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto cell_broadcast_sms = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto roaming_mode = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto subscription_mode = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Cdma cdma = 27;
+
+    optional SettingProto cell_on = 28 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+    message CertPin {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto update_content_url = 1;
+        optional SettingProto update_metadata_url = 2;
+    }
+    optional CertPin cert_pin = 29;
+
+    optional SettingProto chained_battery_attribution_enabled = 30 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto compatibility_mode = 31 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+    message Connectivity {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto metrics_buffer_size = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto change_delay = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto sampling_interval_in_seconds = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Connectivity connectivity = 32;
+
+    optional SettingProto contact_metadata_sync_enabled = 33 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto contacts_database_wal_enabled = 34 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+    message Data {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto activity_timeout_mobile = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto activity_timeout_wifi = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto roaming = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto stall_alarm_non_aggressive_delay_in_ms = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto stall_alarm_aggressive_delay_in_ms = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Data data = 35;
+
+    message Database {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto downgrade_reason = 1;
+        optional SettingProto creation_buildid = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Database database = 36;
+
+    message Debug {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        // Name of an application package to be debugged.
+        optional SettingProto app = 1;
+        // Whether views are allowed to save their attribute data.
+        optional SettingProto view_attributes = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Debug debug = 37;
+
+    message Default {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto install_location = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto dns_server = 2;
+    }
+    optional Default default = 38;
+
+    message Development {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto settings_enabled = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto force_resizable_activities = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto enable_freeform_windows_support = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto force_rtl = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto emulate_display_cutout = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Development development = 39;
+
+    message Device {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto name = 1;
+        optional SettingProto provisioned = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto provisioning_mobile_data_enabled = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto idle_constants = 4;
+        optional SettingProto policy_constants = 5;
+        optional SettingProto demo_mode = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Device device = 40;
+
+    optional SettingProto disk_free_change_reporting_threshold = 41 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+    message Display {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto size_forced = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto scaling_force = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        // Flag to enable or disable display panel low power mode (lpm)
+        // false -> Display panel power saving mode is disabled.
+        // true  -> Display panel power saving mode is enabled.
+        optional SettingProto panel_lpm = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Display display = 42;
+
+    message DnsResolver {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto sample_validity_seconds = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto success_threshold_percent = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto min_samples = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto max_samples = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional DnsResolver dns_resolver = 43;
+
+    optional SettingProto dock_audio_media_enabled = 44 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+    message Download {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto max_bytes_over_mobile = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto recommended_max_bytes_over_mobile = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Download download = 45;
+
+    message Dropbox {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto age_seconds = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto max_files = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto quota_kb = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto quota_percent = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto reserve_percent = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        repeated SettingProto settings = 6;
+    }
+    optional Dropbox dropbox = 46;
+
+    message Emergency {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto tone = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto affordance_needed = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Emergency emergency = 47;
+
+    message Enable {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto accessibility_global_gesture_enabled = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto gpu_debug_layers = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto ephemeral_feature = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto cellular_on_boot = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto diskstats_logging = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto cache_quota_calculation = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto deletion_helper_no_threshold_toggle = 7 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto gnss_raw_meas_full_tracking = 8 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Enable enable = 48;
+
+    optional SettingProto encoded_surround_output = 49 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto enhanced_4g_mode_enabled = 50 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    repeated SettingProto error_logcat_lines = 51;
+
+    message Euicc {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto provisioned = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto factory_reset_timeout_millis = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Euicc euicc = 52;
+
+    optional SettingProto fancy_ime_animations = 53 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto force_allow_on_external = 54 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // An integer to reduce the FPS by this factor. Only for experiments.
+    optional SettingProto fps_divisor = 55 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto fstrim_mandatory_interval = 56 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+    message GlobalHttpProxy {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        // Including Global.HTTP_PROXY is redundant since the data is also
+        // encompassed in the host and port fields.
+
+        optional SettingProto host = 1;
+        optional SettingProto port = 2;
+        optional SettingProto exclusion_list = 3;
+        optional SettingProto pac = 4;
+        // Enables the UI setting to allow the user to specify the global HTTP proxy
+        // and associated exclusion list. Simply "set_global_http_proxy".
+        optional SettingProto setting_ui_enabled = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional GlobalHttpProxy global_http_proxy = 57;
+
+    optional SettingProto gprs_register_check_period_ms = 58 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+    message Gpu {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        // App allowed to load GPU debug layers.
+        optional SettingProto debug_app = 1;
+        optional SettingProto debug_layers = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Gpu gpu = 59;
+
+    message Hdmi {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto control_enabled = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto system_audio_control_enabled = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto control_auto_wakeup_enabled = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto control_auto_device_off_enabled = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Hdmi hdmi = 60;
+
+    optional SettingProto heads_up_notifications_enabled = 61 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto hidden_api_blacklist_exemptions = 62 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+    message InetCondition {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto debounce_up_delay = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto debounce_down_delay = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional InetCondition inet_condition = 63;
+
+    message InstantApp {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto dexopt_enabled = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto ephemeral_cookie_max_size_bytes = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto installed_min_cache_period = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto installed_max_cache_period = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto uninstalled_min_cache_period = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto uninstalled_max_cache_period = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional InstantApp instant_app = 64;
+
+    message IntentFirewall {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto update_content_url = 1;
+        optional SettingProto update_metadata_url = 2;
+    }
+    optional IntentFirewall intent_firewall = 65;
+
+    optional SettingProto job_scheduler_constants = 66;
+    optional SettingProto keep_profile_in_background = 67 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+    message LangId {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto update_content_url = 1;
+        optional SettingProto update_metadata_url = 2;
+    }
+    optional LangId lang_id = 68;
+
+    message Location {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto background_throttle_interval_ms = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto background_throttle_proximity_alert_interval_ms = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        // Packages that are whitelisted for background throttling (throttling will
+        // not be applied).
+        optional SettingProto background_throttle_package_whitelist = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto settings_link_to_permissions_enabled = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        // If set to 1, {@link Secure#LOCATION_MODE} will be set to {@link
+        // Secure#LOCATION_MODE_OFF} temporarily for all users.
+        optional SettingProto global_kill_switch = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Location location = 69;
+
+    message LowPowerMode {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        // Simply "low_power_mode" in code.
+        optional SettingProto enabled = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        // Battery level [1-100] at which low power mode automatically turns on. If
+        // 0, it will not automatically turn on.
+        optional SettingProto trigger_level = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        // The max value for {@link #LOW_POWER_MODE_TRIGGER_LEVEL}. If this setting
+        // is not set or the value is 0, the default max will be used.
+        optional SettingProto trigger_level_max = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional LowPowerMode low_power_mode = 70;
+
+    optional SettingProto lte_service_forced = 71 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto mdc_initial_max_retry = 72 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+    message Mhl {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto input_switching_enabled = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto power_charge_enabled = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Mhl mhl = 73;
+
+    message MobileData {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        // Whether mobile data connections are allowed by the user. Simply
+        // "mobile_data" in code.
+        optional SettingProto allowed = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        // Whether the mobile data connection should remain active even when higher
+        // priority networks like WiFi are active, to help make network switching
+        // faster.
+        optional SettingProto always_on = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional MobileData mobile_data = 74;
+
+    // Ringer mode. A change in this value will not reflect as a change in the
+    // ringer mode.
+    optional SettingProto mode_ringer = 75 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+    message MultiSim {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        // Subscription to be used for voice call on a multi sim device. The
+        // supported values are 0 = SUB1, 1 = SUB2 and etc.
+        optional SettingProto voice_call_subscription = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto voice_prompt = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto data_call_subscription = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto sms_subscription = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto sms_prompt = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional MultiSim multi_sim = 76;
+
+    message Netstats {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto enabled = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto poll_interval = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto time_cache_max_age = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto global_alert_bytes = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto sample_enabled = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto augment_enabled = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto dev_bucket_duration = 7 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto dev_persist_bytes = 8 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto dev_rotate_age = 9 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto dev_delete_age = 10 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto uid_bucket_duration = 11 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto uid_persist_bytes = 12 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto uid_rotate_age = 13 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto uid_delete_age = 14 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto uid_tag_bucket_duration = 15 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto uid_tag_persist_bytes = 16 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto uid_tag_rotate_age = 17 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto uid_tag_delete_age = 18 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Netstats netstats = 77;
+
+    message Network {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        // User preference for which network(s) should be used.
+        optional SettingProto preference = 1;
+        optional SettingProto preferred_network_mode = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto scorer_app = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto switch_notification_daily_limit = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto switch_notification_rate_limit_millis = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto avoid_bad_wifi = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto metered_multipath_preference = 7 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto watchlist_last_report_time = 8 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto scoring_ui_enabled = 9 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto recommendations_enabled = 10 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto recommendations_package = 11 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto recommendation_request_timeout_ms = 12 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto watchlist_enabled = 13 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto scoring_provisioned = 14 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto access_timeout_ms = 15 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto recommended_network_evaluator_cache_expiry_ms = 16 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Network network = 78;
+
+    // Whether to enable new contacts aggregator or not.
+    // 1 = enable, 0 = disable.
+    optional SettingProto new_contact_aggregator = 79 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto night_display_forced_auto_mode_available = 80 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+    message NitzUpdate {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        // If the NITZ_UPDATE_DIFF time is exceeded then an automatic adjustment to
+        // SystemClock will be allowed even if NITZ_UPDATE_SPACING has not been
+        // exceeded.
+        optional SettingProto diff = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        // The length of time in milli-seconds that automatic small adjustments to
+        // SystemClock are ignored if NITZ_UPDATE_DIFF is not exceeded.
+        optional SettingProto spacing = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional NitzUpdate nitz_update = 81;
+
+    message Notification {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto max_notification_enqueue_rate = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto show_notification_channel_warnings = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        // The list of snooze options for notifications. This is encoded as a key=value list,
+        // separated by commas.
+        optional SettingProto snooze_options = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto smart_replies_in_notifications_flags = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Notification notification = 82;
+
+    optional SettingProto nsd_on = 83 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+    message Ntp {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        // Preferred NTP server.
+        optional SettingProto server = 1;
+        // Timeout in milliseconds to wait for NTP server.
+        optional SettingProto timeout_ms = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Ntp ntp = 84;
+
+    // Details about the Off Body, Radios Off feature.
+    message OffBodyRadiosOff {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        // Whether or not to enable the Off Body, Radios Off feature on small battery devices.
+        optional SettingProto enabled_for_small_battery = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        // How long after the device goes off body to disable radios, in milliseconds.
+        optional SettingProto delay_ms = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional OffBodyRadiosOff off_body_radios_off = 85;
+
+    // Whether to disable the automatic scheduling of system updates.
+    optional SettingProto ota_disable_automatic_update = 86 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // Overlay display devices setting.
+    // The value is a specially formatted string that describes the size and
+    // density of simulated secondary devices.
+    // Format: {width}x{height}/dpi;...
+    optional SettingProto overlay_display_devices = 87 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // If set to 1, SettingsProvider's restoreAnyVersion="true" attribute will
+    // be ignored and restoring to lower version of platform API will be
+    // skipped.
+    optional SettingProto override_settings_provider_restore_any_version = 88 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // The series of successively longer delays used in retrying to download PAC file.
+    optional SettingProto pac_change_delay = 89 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+    message PackageVerifier {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        // Whether the package manager should send package verification broadcasts
+        // for verifiers to review apps prior to installation.
+        optional SettingProto enabled = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto timeout = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto default_response = 3;
+        optional SettingProto setting_visible = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto include_adb = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional PackageVerifier package_verifier = 90;
+
+    message PdpWatchdog {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto poll_interval_ms = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto long_poll_interval_ms = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto error_poll_interval_ms = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto trigger_packet_count = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto error_poll_count = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto max_pdp_reset_fail_count = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional PdpWatchdog pdp_watchdog = 91;
+
+    // Defines global runtime overrides to window policy.
+    optional SettingProto policy_control = 92;
+    optional SettingProto power_manager_constants = 93;
+    // If true, out-of-the-box execution for priv apps is enabled.
+    optional SettingProto priv_app_oob_enabled = 94 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+    message PrepaidSetup {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        // URL to open browser on to allow user to manage a prepay account.
+        optional SettingProto data_service_url = 1;
+        // URL to attempt a GET on to see if this is a prepay device.
+        optional SettingProto detection_target_url = 2;
+        // Host to check for a redirect to after an attempt to GET
+        // SETUP_PREPAID_DETECTION_TARGET_URL. (If we redirected there, this is a
+        // prepaid device with zero balance.)
+        optional SettingProto detection_redir_host = 3;
+    }
+    optional PrepaidSetup prepaid_setup = 95;
+
+    message Private {
+        option (android.msg_privacy).dest = DEST_LOCAL;
+
+        // The requested Private DNS mode and an accompanying specifier.
+        optional SettingProto dns_mode = 1;
+        optional SettingProto dns_specifier = 2;
+    }
+    optional Private private = 96;
+
+    // The number of milliseconds to allow the provisioning apn to remain active.
+    optional SettingProto provisioning_apn_alarm_delay_in_ms = 97 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto read_external_storage_enforced_default = 98 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto require_password_to_decrypt = 99 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto safe_boot_disallowed = 100 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+    message Selinux {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto update_content_url = 1;
+        optional SettingProto update_metadata_url = 2;
+        optional SettingProto status = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Selinux selinux = 101;
+
+    // Flag for allowing ActivityManagerService to send ACTION_APP_ERROR intents
+    // on application crashes and ANRs. If this is disabled, the crash/ANR
+    // dialog will never display the "Report" button.
+    optional SettingProto send_action_app_error = 102 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // Let user pick default install location.
+    optional SettingProto set_install_location = 103 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto shortcut_manager_constants = 104;
+    optional SettingProto show_first_crash_dialog = 105 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto show_restart_in_crash_dialog = 106 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto show_mute_in_crash_dialog = 107 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+    message SmartSelection {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto update_content_url = 1;
+        optional SettingProto update_metadata_url = 2;
+    }
+    optional SmartSelection smart_selection = 108;
+
+    message Sms {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto outgoing_check_interval_ms = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto outgoing_check_max_count = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        // Used to disable SMS short code confirmation. Defaults to true.
+        optional SettingProto short_code_confirmation = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto short_code_rule = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto short_codes_update_content_url = 5;
+        optional SettingProto short_codes_update_metadata_url = 6;
+    }
+    optional Sms sms = 109;
+
+    message Sounds {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto car_dock = 1;
+        optional SettingProto car_undock = 2;
+        optional SettingProto charging_sounds_enabled = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto charging_started = 4;
+        optional SettingProto desk_dock = 5;
+        optional SettingProto desk_undock = 6;
+        optional SettingProto dock_sounds_enabled = 7 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto dock_sounds_enabled_when_accessibility = 8 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto lock = 9;
+        optional SettingProto low_battery = 10;
+        optional SettingProto low_battery_sound_timeout = 11 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        // Called "power_sounds_enabled" in code.
+        optional SettingProto low_battery_sounds_enabled = 12 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto trusted = 13;
+        optional SettingProto unlock = 14;
+    }
+    optional Sounds sounds = 110;
+
+    message SoundTrigger {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        // Maximum number of SoundTriggerDetectionService operations per day.
+        optional SettingProto max_sound_trigger_detection_service_ops_per_day = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        // Timeout for a single SoundTriggerDetectionService operation (in ms).
+        optional SettingProto detection_service_op_timeout_ms = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional SoundTrigger sound_trigger = 111;
+
+    // Value to specify how long in milliseconds to retain seen score cache
+    // curves to be used when generating SSID only bases score curves.
+    optional SettingProto speed_label_cache_eviction_age_ms = 112 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // Configuration flags for SQLite Compatibility WAL. Encoded as a key-value
+    // list, separated by commas.
+    // E.g.: compatibility_wal_supported=true, wal_syncmode=OFF
+    optional SettingProto sqlite_compatibility_wal_flags = 113 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto stay_on_while_plugged_in = 114 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+    message Storage {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto benchmark_interval = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto settings_clobber_threshold = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Storage storage = 115;
+
+    message Sync {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        // The maximum reconnect delay for short network outages or when the network is suspended due to phone use.
+        optional SettingProto max_retry_delay_in_seconds = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        // Simply "sync_manager_constants" in code.
+        optional SettingProto manager_constants = 2;
+    }
+    optional Sync sync = 116;
+
+    message Sys {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        // The interval in minutes after which the amount of free storage left on
+        // the device is logged to the event log.
+        optional SettingProto free_storage_log_interval_mins = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto storage_threshold_percentage = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto storage_threshold_max_bytes = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto storage_full_threshold_bytes = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto storage_cache_percentage = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto storage_cache_max_bytes = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        // System VDSO global setting. This links to the "sys.vdso" system property.
+        // The following values are supported:
+        // false  -> both 32 and 64 bit vdso disabled
+        // 32     -> 32 bit vdso enabled
+        // 64     -> 64 bit vdso enabled
+        // Any other value defaults to both 32 bit and 64 bit true.
+        optional SettingProto vdso = 7 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        // UidCpuPower global setting. This links the sys.uidcpupower system property.
+        // The following values are supported:
+        // 0 -> /proc/uid_cpupower/* are disabled
+        // 1 -> /proc/uid_cpupower/* are enabled
+        // Any other value defaults to enabled.
+        optional SettingProto uidcpupower = 8 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Sys sys = 117;
+
+    optional SettingProto tcp_default_init_rwnd = 118 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+    message TemperatureWarning {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto show_temperature_warning = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        // Temperature at which the high temperature warning notification should
+        // be shown.
+        optional SettingProto warning_temperature_level = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional TemperatureWarning temperature_warning = 119;
+
+    message Tether {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto supported = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto dun_required = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto dun_apn = 3;
+        optional SettingProto offload_disabled = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        // Simply "soft_ap_timeout_enabled" in code.
+        optional SettingProto timeout_enabled = 112 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Tether tether = 120;
+
+    optional SettingProto text_classifier_constants = 121;
+    optional SettingProto theater_mode_on = 122 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto time_only_mode_constants = 123 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto transition_animation_scale = 124 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+    message Tzinfo {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto update_content_url = 1;
+        optional SettingProto update_metadata_url = 2;
+    }
+    optional Tzinfo tzinfo = 125;
+
+    // The min period for caching unused static shared libs in milliseconds.
+    optional SettingProto unused_static_shared_lib_min_cache_period_ms = 126 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto usb_mass_storage_enabled = 127 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto use_google_mail = 128 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto use_open_wifi_package = 129 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto vt_ims_enabled = 130 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wait_for_debugger = 131 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+    message Webview {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto data_reduction_proxy_key = 1;
+        optional SettingProto fallback_logic_enabled = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        // Name of the package used as WebView provider.
+        optional SettingProto provider = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto multiprocess = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Webview webview = 132;
+
+    message Wfc {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto ims_enabled = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto ims_mode = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto ims_roaming_mode = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto ims_roaming_enabled = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Wfc wfc = 133;
+
+    message Wifi {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto sleep_policy = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto badging_thresholds = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto display_on = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto display_certification_on = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto display_wps_config = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto networks_available_notification_on = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto carrier_networks_available_notification_on = 7 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto networks_available_repeat_delay = 8 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto country_code = 9;
+        optional SettingProto framework_scan_interval_ms = 10 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto idle_ms = 11 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto num_open_networks_kept = 12 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto on = 13 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto scan_always_available = 14 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto wakeup_enabled = 15 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto saved_state = 16 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto supplicant_scan_interval_ms = 17 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto enhanced_auto_join = 18 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto network_show_rssi = 19 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto scan_interval_when_p2p_connected_ms = 20 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto watchdog_on = 21 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto watchdog_poor_network_test_enabled = 22 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto suspend_optimizations_enabled = 23 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto verbose_logging_enabled = 24 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto connected_mac_randomization_enabled = 25 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto max_dhcp_retry_count = 26 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto mobile_data_transition_wakelock_timeout_ms = 27 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto device_owner_configs_lockdown = 28 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto frequency_band = 29 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto p2p_device_name = 30;
+        optional SettingProto reenable_delay_ms = 31 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto ephemeral_out_of_range_timeout_ms = 32 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto on_when_proxy_disconnected = 33 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto bounce_delay_override_ms = 34 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Wifi wifi = 134;
+
+    optional SettingProto wimax_networks_available_notification_on = 135 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto window_animation_scale = 136 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wtf_is_fatal = 137 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+    message Zen {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto mode = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto mode_ringer_level = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto mode_config_etag = 3;
+        // If 0, turning on dnd manually will last indefinitely. Else if
+        // non-negative, turning on dnd manually will last for this many minutes.
+        // Else (if negative), turning on dnd manually will surface a dialog that
+        // prompts user to specify a duration.
+        optional SettingProto duration = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto show_zen_upgrade_notification = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional Zen zen = 138;
+
+    optional SettingProto zram_enabled = 139 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+    // Please insert fields in alphabetical order and group them into messages
+    // if possible (to avoid reaching the method limit).
+    // Next tag = 140;
+}
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index 122e5c4..8d4b56c 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -514,7 +514,7 @@
         optional int32 uid = 3;
         // Job IDs can technically be negative.
         optional int32 job_id = 4;
-        optional string tag = 5 [ (.android.privacy).dest = DEST_EXPLICIT ];
+        optional string tag = 5;
         // Only valid for STOP_JOB or STOP_PERIODIC_JOB Events.
         optional .android.app.job.StopReasonEnum stop_reason = 6;
     }
@@ -538,7 +538,7 @@
 
     // The UID that scheduled the job.
     optional int32 calling_uid = 1;
-    optional string tag = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];
+    optional string tag = 2;
 
     // The UID for which the job is being run.
     optional int32 source_uid = 3;
diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto
index c58de56..eb60942 100644
--- a/core/proto/android/server/powermanagerservice.proto
+++ b/core/proto/android/server/powermanagerservice.proto
@@ -118,61 +118,60 @@
     // True if the sandman has just been summoned for the first time since entering
     // the dreaming or dozing state.  Indicates whether a new dream should begin.
     optional bool is_sandman_summoned = 23;
-    // If true, the device is in low power mode.
-    optional bool is_low_power_mode_enabled = 24;
     // True if the battery level is currently considered low.
-    optional bool is_battery_level_low = 25;
+    optional bool is_battery_level_low = 24;
     // True if we are currently in light device idle mode.
-    optional bool is_light_device_idle_mode = 26;
+    optional bool is_light_device_idle_mode = 25;
     // True if we are currently in device idle mode.
-    optional bool is_device_idle_mode = 27;
+    optional bool is_device_idle_mode = 26;
     // Set of app ids that we will always respect the wake locks for.
-    repeated int32 device_idle_whitelist = 28;
+    repeated int32 device_idle_whitelist = 27;
     // Set of app ids that are temporarily allowed to acquire wakelocks due to
     // high-pri message
-    repeated int32 device_idle_temp_whitelist = 29;
+    repeated int32 device_idle_temp_whitelist = 28;
     // Timestamp of the last time the device was awoken.
-    optional int64 last_wake_time_ms = 30;
+    optional int64 last_wake_time_ms = 29;
     // Timestamp of the last time the device was put to sleep.
-    optional int64 last_sleep_time_ms = 31;
+    optional int64 last_sleep_time_ms = 30;
     // Timestamp of the last call to user activity.
-    optional int64 last_user_activity_time_ms = 32;
-    optional int64 last_user_activity_time_no_change_lights_ms = 33;
+    optional int64 last_user_activity_time_ms = 31;
+    optional int64 last_user_activity_time_no_change_lights_ms = 32;
     // Timestamp of last interactive power hint.
-    optional int64 last_interactive_power_hint_time_ms = 34;
+    optional int64 last_interactive_power_hint_time_ms = 33;
     // Timestamp of the last screen brightness boost.
-    optional int64 last_screen_brightness_boost_time_ms = 35;
+    optional int64 last_screen_brightness_boost_time_ms = 34;
     // True if screen brightness boost is in progress.
-    optional bool is_screen_brightness_boost_in_progress = 36;
+    optional bool is_screen_brightness_boost_in_progress = 35;
     // True if the display power state has been fully applied, which means the
     // display is actually on or actually off or whatever was requested.
-    optional bool is_display_ready = 37;
+    optional bool is_display_ready = 36;
     // True if the wake lock suspend blocker has been acquired.
-    optional bool is_holding_wake_lock_suspend_blocker = 38;
+    optional bool is_holding_wake_lock_suspend_blocker = 37;
     // The suspend blocker used to keep the CPU alive when the display is on, the
     // display is getting ready or there is user activity (in which case the
     // display must be on).
-    optional bool is_holding_display_suspend_blocker = 39;
+    optional bool is_holding_display_suspend_blocker = 38;
     // Settings and configuration
-    optional PowerServiceSettingsAndConfigurationDumpProto settings_and_configuration = 40;
+    optional PowerServiceSettingsAndConfigurationDumpProto settings_and_configuration = 39;
     // Sleep timeout in ms. This can be -1.
-    optional sint32 sleep_timeout_ms = 41;
+    optional sint32 sleep_timeout_ms = 40;
     // Screen off timeout in ms
-    optional int32 screen_off_timeout_ms = 42;
+    optional int32 screen_off_timeout_ms = 41;
     // Screen dim duration in ms
-    optional int32 screen_dim_duration_ms = 43;
+    optional int32 screen_dim_duration_ms = 42;
     // We are currently in the middle of a batch change of uids.
-    optional bool are_uids_changing = 44;
+    optional bool are_uids_changing = 43;
     // Some uids have actually changed while mUidsChanging was true.
-    optional bool are_uids_changed = 45;
+    optional bool are_uids_changed = 44;
     // List of UIDs and their states
-    repeated UidStateProto uid_states = 46;
-    optional .android.os.LooperProto looper = 47;
+    repeated UidStateProto uid_states = 45;
+    optional .android.os.LooperProto looper = 46;
     // List of all wake locks acquired by applications.
-    repeated WakeLockProto wake_locks = 48;
+    repeated WakeLockProto wake_locks = 47;
     // List of all suspend blockers.
-    repeated SuspendBlockerProto suspend_blockers = 49;
-    optional WirelessChargerDetectorProto wireless_charger_detector = 50;
+    repeated SuspendBlockerProto suspend_blockers = 48;
+    optional WirelessChargerDetectorProto wireless_charger_detector = 49;
+    optional BatterySaverStateMachineProto battery_saver_state_machine = 50;
 }
 
 // A com.android.server.power.PowerManagerService.SuspendBlockerImpl object.
@@ -270,51 +269,80 @@
     optional bool are_dreams_activate_on_dock_setting = 17;
     // True if doze should not be started until after the screen off transition.
     optional bool is_doze_after_screen_off_config = 18;
-    // If true, the device is in low power mode.
-    optional bool is_low_power_mode_setting = 19;
-    // Current state of whether the settings are allowing auto low power mode.
-    optional bool is_auto_low_power_mode_configured = 20;
-    // The user turned off low power mode below the trigger level
-    optional bool is_auto_low_power_mode_snoozing = 21;
     // The minimum screen off timeout, in milliseconds.
-    optional int32 minimum_screen_off_timeout_config_ms = 22;
+    optional int32 minimum_screen_off_timeout_config_ms = 19;
     // The screen dim duration, in milliseconds.
-    optional int32 maximum_screen_dim_duration_config_ms = 23;
+    optional int32 maximum_screen_dim_duration_config_ms = 20;
     // The maximum screen dim time expressed as a ratio relative to the screen off timeout.
-    optional float maximum_screen_dim_ratio_config = 24;
+    optional float maximum_screen_dim_ratio_config = 21;
     // The screen off timeout setting value in milliseconds.
-    optional int32 screen_off_timeout_setting_ms = 25;
+    optional int32 screen_off_timeout_setting_ms = 22;
     // The sleep timeout setting value in milliseconds. Default value is -1.
-    optional sint32 sleep_timeout_setting_ms = 26;
+    optional sint32 sleep_timeout_setting_ms = 23;
     // The maximum allowable screen off timeout according to the device administration policy.
-    optional int32 maximum_screen_off_timeout_from_device_admin_ms = 27;
-    optional bool is_maximum_screen_off_timeout_from_device_admin_enforced_locked = 28;
+    optional int32 maximum_screen_off_timeout_from_device_admin_ms = 24;
+    optional bool is_maximum_screen_off_timeout_from_device_admin_enforced_locked = 25;
     // The stay on while plugged in setting.
     // A set of battery conditions under which to make the screen stay on.
-    optional StayOnWhilePluggedInProto stay_on_while_plugged_in = 29;
+    optional StayOnWhilePluggedInProto stay_on_while_plugged_in = 26;
     // The screen brightness mode.
-    optional .android.providers.settings.SettingsProto.ScreenBrightnessMode screen_brightness_mode_setting = 30;
+    optional .android.providers.settings.SettingsProto.ScreenBrightnessMode screen_brightness_mode_setting = 27;
     // The screen brightness setting override from the window manager
     // to allow the current foreground activity to override the brightness.
     // Use -1 to disable.
-    optional sint32 screen_brightness_override_from_window_manager = 31;
+    optional sint32 screen_brightness_override_from_window_manager = 28;
     // The user activity timeout override from the window manager
     // to allow the current foreground activity to override the user activity
     // timeout. Use -1 to disable.
-    optional sint64 user_activity_timeout_override_from_window_manager_ms = 32;
+    optional sint64 user_activity_timeout_override_from_window_manager_ms = 29;
     // The window manager has determined the user to be inactive via other means.
     // Set this to false to disable.
-    optional bool is_user_inactive_override_from_window_manager = 33;
+    optional bool is_user_inactive_override_from_window_manager = 30;
     // The screen state to use while dozing.
-    optional .android.view.DisplayStateEnum doze_screen_state_override_from_dream_manager = 34;
+    optional .android.view.DisplayStateEnum doze_screen_state_override_from_dream_manager = 31;
     // The screen brightness to use while dozing.
-    optional float dozed_screen_brightness_override_from_dream_manager = 35;
+    optional float dozed_screen_brightness_override_from_dream_manager = 32;
     // Screen brightness settings limits.
-    optional ScreenBrightnessSettingLimitsProto screen_brightness_setting_limits = 36;
+    optional ScreenBrightnessSettingLimitsProto screen_brightness_setting_limits = 33;
     // True if double tap to wake is enabled
-    optional bool is_double_tap_wake_enabled = 37;
+    optional bool is_double_tap_wake_enabled = 34;
     // True if we are currently in VR Mode.
-    optional bool is_vr_mode_enabled = 38;
+    optional bool is_vr_mode_enabled = 35;
     // True if Sidekick is controlling the display and we shouldn't change its power mode.
-    optional bool draw_wake_lock_override_from_sidekick = 39;
+    optional bool draw_wake_lock_override_from_sidekick = 36;
 }
+
+message BatterySaverStateMachineProto {
+   // Whether battery saver is enabled.
+   optional bool enabled = 1;
+
+   // Whether system has booted.
+   optional bool boot_completed = 2;
+
+   // Whether settings have been loaded already.
+   optional bool settings_loaded = 3;
+
+   // Whether battery status has been set at least once.
+   optional bool battery_status_set = 4;
+
+   // Whether automatic battery saver has been canceled by the user.
+   optional bool battery_saver_snoozing = 5;
+
+   // Whether the device is connected to any power source.
+   optional bool is_powered = 6;
+
+   // Current battery level in %, 0-100.
+   optional int32 battery_level = 7;
+
+   // Whether battery level is low or not.
+   optional bool is_battery_level_low = 8;
+
+   // The value of Global.LOW_POWER_MODE.
+   optional bool setting_battery_saver_enabled = 9;
+
+   // The value of Global.LOW_POWER_MODE_STICKY.
+   optional bool setting_battery_saver_enabled_sticky = 10;
+
+   // The value of Global.LOW_POWER_MODE_TRIGGER_LEVEL.
+   optional int32 setting_battery_saver_trigger_threshold = 11;
+}
\ No newline at end of file
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 55c17b9..b5e223c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1340,6 +1340,30 @@
     <integer-array name="config_autoBrightnessKeyboardBacklightValues">
     </integer-array>
 
+    <!-- Array of light sensor lux values to define the minimum brightness curve, which guarantees
+         that any curve that dips below it is rejected by the system.
+         This prevents auto-brightness from setting the screen so dark as to prevent the user from
+         disabling auto-brightness or reseting the brightness curve via ADB.
+
+         The control points must be strictly increasing. Each control point corresponds to an entry
+         in the minimum brightness nits array. -->
+    <integer-array name="config_autoBrightnessMinimumBrightnessCurveLux">
+        <item>2000</item>
+        <item>4000</item>
+    </integer-array>
+
+    <!-- Array of desired screen brightness in nits corresponding to the lux values
+         in the config_autoBrightnessMinimumBrightnessCurveLux array.
+
+         This array should have size one greater than the size of the
+         config_autoBrightnessMinimumBrightnessCurveLux array. The values must be non-negative and
+         non-decreasing. -->
+    <array name="config_autoBrightnessMinimumBrightnessCurveNits">
+        <item>1.0</item>
+        <item>50.0</item>
+        <item>90.0</item>
+    </array>
+
     <!-- Array of hysteresis constraint values for brightening, represented as tenths of a
          percent. The length of this array is assumed to be one greater than
          config_dynamicHysteresisLuxLevels. The brightening threshold is calculated as
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 75f8013..5eeb418 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1794,6 +1794,8 @@
   <java-symbol type="array" name="config_autoBrightnessKeyboardBacklightValues" />
   <java-symbol type="array" name="config_autoBrightnessLcdBacklightValues" />
   <java-symbol type="array" name="config_autoBrightnessLevels" />
+  <java-symbol type="array" name="config_autoBrightnessMinimumBrightnessCurveLux" />
+  <java-symbol type="array" name="config_autoBrightnessMinimumBrightnessCurveNits" />
   <java-symbol type="array" name="config_dynamicHysteresisBrightLevels" />
   <java-symbol type="array" name="config_dynamicHysteresisDarkLevels" />
   <java-symbol type="array" name="config_dynamicHysteresisLuxLevels" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index a504ab9..6ef773a 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -266,6 +266,7 @@
                     Settings.Global.LOW_BATTERY_SOUND_TIMEOUT,
                     Settings.Global.LOW_POWER_MODE,
                     Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL_MAX,
+                    Settings.Global.LOW_POWER_MODE_STICKY,
                     Settings.Global.LTE_SERVICE_FORCED,
                     Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
                     Settings.Global.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY,
diff --git a/core/tests/coretests/src/android/widget/TextViewTest.java b/core/tests/coretests/src/android/widget/TextViewTest.java
index 2b5b27b..4f1efbf 100644
--- a/core/tests/coretests/src/android/widget/TextViewTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewTest.java
@@ -17,6 +17,7 @@
 package android.widget;
 
 import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertTrue;
 
@@ -32,9 +33,11 @@
 import android.support.test.runner.AndroidJUnit4;
 import android.text.GetChars;
 import android.text.Layout;
+import android.text.PrecomputedText;
 import android.text.Selection;
 import android.text.Spannable;
 import android.view.View;
+import android.widget.TextView.BufferType;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -241,6 +244,82 @@
         mTextView.onTextContextMenuItem(TextView.ID_CUT);
     }
 
+    @Test
+    public void testUseDynamicLayout() {
+        mTextView = new TextView(mActivity);
+        mTextView.setTextIsSelectable(true);
+        String text = "HelloWorld";
+        PrecomputedText precomputed =
+                PrecomputedText.create(text, mTextView.getTextMetricsParams());
+
+        mTextView.setTextIsSelectable(false);
+        mTextView.setText(text);
+        assertFalse(mTextView.useDynamicLayout());
+
+        mTextView.setTextIsSelectable(true);
+        mTextView.setText(text);
+        assertTrue(mTextView.useDynamicLayout());
+
+        mTextView.setTextIsSelectable(false);
+        mTextView.setText(precomputed);
+        assertFalse(mTextView.useDynamicLayout());
+
+        mTextView.setTextIsSelectable(true);
+        mTextView.setText(precomputed);
+        assertTrue(mTextView.useDynamicLayout());
+    }
+
+    @Test
+    public void testUseDynamicLayout_SPANNABLE() {
+        mTextView = new TextView(mActivity);
+        mTextView.setTextIsSelectable(true);
+        String text = "HelloWorld";
+        PrecomputedText precomputed =
+                PrecomputedText.create(text, mTextView.getTextMetricsParams());
+
+        mTextView.setTextIsSelectable(false);
+        mTextView.setText(text, BufferType.SPANNABLE);
+        android.util.Log.e("TextViewTest", "Text:" + mTextView.getText().getClass().getName());
+        assertTrue(mTextView.useDynamicLayout());
+
+        mTextView.setTextIsSelectable(true);
+        mTextView.setText(text, BufferType.SPANNABLE);
+        assertTrue(mTextView.useDynamicLayout());
+
+        mTextView.setTextIsSelectable(false);
+        mTextView.setText(precomputed, BufferType.SPANNABLE);
+        assertFalse(mTextView.useDynamicLayout());
+
+        mTextView.setTextIsSelectable(true);
+        mTextView.setText(precomputed, BufferType.SPANNABLE);
+        assertTrue(mTextView.useDynamicLayout());
+    }
+
+    @Test
+    public void testUseDynamicLayout_EDITABLE() {
+        mTextView = new TextView(mActivity);
+        mTextView.setTextIsSelectable(true);
+        String text = "HelloWorld";
+        PrecomputedText precomputed =
+                PrecomputedText.create(text, mTextView.getTextMetricsParams());
+
+        mTextView.setTextIsSelectable(false);
+        mTextView.setText(text, BufferType.EDITABLE);
+        assertTrue(mTextView.useDynamicLayout());
+
+        mTextView.setTextIsSelectable(true);
+        mTextView.setText(text, BufferType.EDITABLE);
+        assertTrue(mTextView.useDynamicLayout());
+
+        mTextView.setTextIsSelectable(false);
+        mTextView.setText(precomputed, BufferType.EDITABLE);
+        assertTrue(mTextView.useDynamicLayout());
+
+        mTextView.setTextIsSelectable(true);
+        mTextView.setText(precomputed, BufferType.EDITABLE);
+        assertTrue(mTextView.useDynamicLayout());
+    }
+
     private String createLongText() {
         int size = 600 * 1000;
         final StringBuilder builder = new StringBuilder(size);
diff --git a/data/etc/hiddenapi-package-whitelist.xml b/data/etc/hiddenapi-package-whitelist.xml
index bacddf14..a4a1b94 100644
--- a/data/etc/hiddenapi-package-whitelist.xml
+++ b/data/etc/hiddenapi-package-whitelist.xml
@@ -64,6 +64,7 @@
   <hidden-api-whitelisted-app package="com.android.gallery" />
   <hidden-api-whitelisted-app package="com.android.hotspot2" />
   <hidden-api-whitelisted-app package="com.android.keychain" />
+  <hidden-api-whitelisted-app package="com.android.launcher3" />
   <hidden-api-whitelisted-app package="com.android.location.fused" />
   <hidden-api-whitelisted-app package="com.android.managedprovisioning" />
   <hidden-api-whitelisted-app package="com.android.mms.service" />
diff --git a/data/keyboards/Android.mk b/data/keyboards/Android.mk
index 2daef0c..7949c77 100644
--- a/data/keyboards/Android.mk
+++ b/data/keyboards/Android.mk
@@ -28,7 +28,7 @@
 validatekeymaps := $(HOST_OUT_EXECUTABLES)/validatekeymaps$(HOST_EXECUTABLE_SUFFIX)
 $(LOCAL_BUILT_MODULE): PRIVATE_VALIDATEKEYMAPS := $(validatekeymaps)
 $(LOCAL_BUILT_MODULE) : $(framework_keylayouts) $(framework_keycharmaps) $(framework_keyconfigs) | $(validatekeymaps)
-	$(hide) -q $(PRIVATE_VALIDATEKEYMAPS) $^
+	$(hide) $(PRIVATE_VALIDATEKEYMAPS) -q $^
 	$(hide) mkdir -p $(dir $@) && touch $@
 
 # Run validatekeymaps uncondionally for platform build.
diff --git a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
index 457e4aa..898939e 100644
--- a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
@@ -52,8 +52,20 @@
 /**
  * {@link Drawable} for drawing animated images (like GIF).
  *
+ * <p>The framework handles decoding subsequent frames in another thread and
+ * updating when necessary. The drawable will only animate while it is being
+ * displayed.</p>
+ *
  * <p>Created by {@link ImageDecoder#decodeDrawable}. A user needs to call
  * {@link #start} to start the animation.</p>
+ *
+ * <p>It can also be defined in XML using the <code>&lt;animated-image></code>
+ * element.</p>
+ *
+ * @attr ref android.R.styleable#AnimatedImageDrawable_src
+ * @attr ref android.R.styleable#AnimatedImageDrawable_autoStart
+ * @attr ref android.R.styleable#AnimatedImageDrawable_repeatCount
+ * @attr ref android.R.styleable#AnimatedImageDrawable_autoMirrored
  */
 public class AnimatedImageDrawable extends Drawable implements Animatable2 {
     private int mIntrinsicWidth;
@@ -456,8 +468,8 @@
      *  <p>Does nothing if the animation is already running. If the animation is stopped,
      *  this will reset it.</p>
      *
-     *  <p>If the animation starts, this will call
-     *  {@link Animatable2.AnimationCallback#onAnimationStart}.</p>
+     *  <p>When the drawable is drawn, starting the animation,
+     *  {@link Animatable2.AnimationCallback#onAnimationStart} will be called.</p>
      */
     @Override
     public void start() {
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index acab8bb..aaba1e3 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -759,6 +759,7 @@
             case FOR_SYSTEM: return "FOR_SYSTEM";
             case FOR_HDMI_SYSTEM_AUDIO: return "FOR_HDMI_SYSTEM_AUDIO";
             case FOR_ENCODED_SURROUND: return "FOR_ENCODED_SURROUND";
+            case FOR_VIBRATE_RINGING: return "FOR_VIBRATE_RINGING";
             default: return "unknown usage (" + usage + ")" ;
         }
     }
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 9175416..bc0e43b 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -3226,9 +3226,18 @@
 
         if (stripOffsetsAttribute != null && stripByteCountsAttribute != null) {
             long[] stripOffsets =
-                    (long[]) stripOffsetsAttribute.getValue(mExifByteOrder);
+                    convertToLongArray(stripOffsetsAttribute.getValue(mExifByteOrder));
             long[] stripByteCounts =
-                    (long[]) stripByteCountsAttribute.getValue(mExifByteOrder);
+                    convertToLongArray(stripByteCountsAttribute.getValue(mExifByteOrder));
+
+            if (stripOffsets == null) {
+                Log.w(TAG, "stripOffsets should not be null.");
+                return;
+            }
+            if (stripByteCounts == null) {
+                Log.w(TAG, "stripByteCounts should not be null.");
+                return;
+            }
 
             // Set thumbnail byte array data for non-consecutive strip bytes
             byte[] totalStripBytes =
@@ -4025,4 +4034,22 @@
         }
         return false;
     }
+
+    /**
+     * Convert given int[] to long[]. If long[] is given, just return it.
+     * Return null for other types of input.
+     */
+    private static long[] convertToLongArray(Object inputObj) {
+        if (inputObj instanceof int[]) {
+            int[] input = (int[]) inputObj;
+            long[] result = new long[input.length];
+            for (int i = 0; i < input.length; i++) {
+                result[i] = input[i];
+            }
+            return result;
+        } else if (inputObj instanceof long[]) {
+            return (long[]) inputObj;
+        }
+        return null;
+    }
 }
diff --git a/media/java/android/media/MediaController2.java b/media/java/android/media/MediaController2.java
index 17002aa..591f33f 100644
--- a/media/java/android/media/MediaController2.java
+++ b/media/java/android/media/MediaController2.java
@@ -25,9 +25,7 @@
 import android.content.Context;
 import android.media.MediaPlaylistAgent.RepeatMode;
 import android.media.MediaPlaylistAgent.ShuffleMode;
-import android.media.MediaSession2.Command;
 import android.media.MediaSession2.CommandButton;
-import android.media.MediaSession2.CommandGroup;
 import android.media.MediaSession2.ControllerInfo;
 import android.media.MediaSession2.ErrorCode;
 import android.media.session.MediaSessionManager;
@@ -56,7 +54,7 @@
  * When controlling {@link MediaSessionService2}, the {@link MediaController2} would be
  * available only if the session service allows this controller by
  * {@link MediaSession2.SessionCallback#onConnect(MediaSession2, ControllerInfo)} for the service.
- * Wait {@link ControllerCallback#onConnected(MediaController2, CommandGroup)} or
+ * Wait {@link ControllerCallback#onConnected(MediaController2, SessionCommandGroup2)} or
  * {@link ControllerCallback#onDisconnected(MediaController2)} for the result.
  * <p>
  * A controller can be created through token from {@link MediaSessionManager} if you hold the
@@ -83,7 +81,7 @@
          * @param allowedCommands commands that's allowed by the session.
          */
         public void onConnected(@NonNull MediaController2 controller,
-                @NonNull CommandGroup allowedCommands) { }
+                @NonNull SessionCommandGroup2 allowedCommands) { }
 
         /**
          * Called when the session refuses the controller or the controller is disconnected from
@@ -102,7 +100,8 @@
          * Called when the session set the custom layout through the
          * {@link MediaSession2#setCustomLayout(ControllerInfo, List)}.
          * <p>
-         * Can be called before {@link #onConnected(MediaController2, CommandGroup)} is called.
+         * Can be called before {@link #onConnected(MediaController2, SessionCommandGroup2)} is
+         * called.
          *
          * @param controller the controller for this event
          * @param layout
@@ -126,7 +125,7 @@
          * @param commands newly allowed commands
          */
         public void onAllowedCommandsChanged(@NonNull MediaController2 controller,
-                @NonNull CommandGroup commands) { }
+                @NonNull SessionCommandGroup2 commands) { }
 
         /**
          * Called when the session sent a custom command.
@@ -137,7 +136,7 @@
          * @param receiver
          */
         public void onCustomCommand(@NonNull MediaController2 controller,
-                @NonNull Command command, @Nullable Bundle args,
+                @NonNull SessionCommand2 command, @Nullable Bundle args,
                 @Nullable ResultReceiver receiver) { }
 
         /**
@@ -149,16 +148,6 @@
         public void onPlayerStateChanged(@NonNull MediaController2 controller, int state) { }
 
         /**
-         * Called when the player's position is changed
-         *
-         * @param controller the controller for this event
-         * @param eventTimeMs timestamp when the position information is sent from the session
-         * @param positionMs position in millis
-         */
-        public void onPositionChanged(@NonNull MediaController2 controller,
-                long eventTimeMs, long positionMs) { }
-
-        /**
          * Called when playback speed is changed.
          *
          * @param controller the controller for this event
@@ -180,6 +169,14 @@
                 @NonNull MediaItem2 item, @MediaPlayerBase.BuffState int state) { }
 
         /**
+         * Called to indicate that seeking is completed.
+         *
+         * @param controller the controller for this event.
+         * @param position the previous seeking request.
+         */
+        public void onSeekCompleted(@NonNull MediaController2 controller, long position) { }
+
+        /**
          * Called when a error from
          *
          * @param controller the controller for this event
@@ -197,7 +194,6 @@
          *
          * @param controller the controller for this event
          * @param item new item
-         * @see #onPositionChanged(MediaController2, long, long)
          * @see #onBufferingStateChanged(MediaController2, MediaItem2, int)
          */
         // TODO(jaewan): Use this (b/74316764)
@@ -423,16 +419,14 @@
     }
 
     /**
-     * Start fast forwarding. If playback is already fast forwarding this
-     * may increase the rate.
+     * Fast forwards playback. If playback is already fast forwarding this may increase the rate.
      */
     public void fastForward() {
         mProvider.fastForward_impl();
     }
 
     /**
-     * Start rewinding. If playback is already rewinding this may increase
-     * the rate.
+     * Rewinds playback. If playback is already rewinding this may increase the rate.
      */
     public void rewind() {
         mProvider.rewind_impl();
@@ -689,7 +683,7 @@
      * @param args optional argument
      * @param cb optional result receiver
      */
-    public void sendCustomCommand(@NonNull Command command, @Nullable Bundle args,
+    public void sendCustomCommand(@NonNull SessionCommand2 command, @Nullable Bundle args,
             @Nullable ResultReceiver cb) {
         mProvider.sendCustomCommand_impl(command, args, cb);
     }
diff --git a/media/java/android/media/MediaItem2.java b/media/java/android/media/MediaItem2.java
index 1967a1c..423a1fd 100644
--- a/media/java/android/media/MediaItem2.java
+++ b/media/java/android/media/MediaItem2.java
@@ -19,7 +19,6 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.Context;
 import android.media.update.ApiLoader;
 import android.media.update.MediaItem2Provider;
 import android.os.Bundle;
@@ -81,8 +80,8 @@
         return mProvider.toBundle_impl();
     }
 
-    public static MediaItem2 fromBundle(Context context, Bundle bundle) {
-        return ApiLoader.getProvider().fromBundle_MediaItem2(context, bundle);
+    public static MediaItem2 fromBundle(Bundle bundle) {
+        return ApiLoader.getProvider().fromBundle_MediaItem2(bundle);
     }
 
     public String toString() {
@@ -161,11 +160,10 @@
         /**
          * Constructor for {@link Builder}
          *
-         * @param context
          * @param flags
          */
-        public Builder(@NonNull Context context, @Flags int flags) {
-            mProvider = ApiLoader.getProvider().createMediaItem2Builder(context, this, flags);
+        public Builder(@Flags int flags) {
+            mProvider = ApiLoader.getProvider().createMediaItem2Builder(this, flags);
         }
 
         /**
diff --git a/media/java/android/media/MediaLibraryService2.java b/media/java/android/media/MediaLibraryService2.java
index 034d17e..f29d386 100644
--- a/media/java/android/media/MediaLibraryService2.java
+++ b/media/java/android/media/MediaLibraryService2.java
@@ -20,7 +20,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.PendingIntent;
-import android.content.Context;
 import android.media.MediaLibraryService2.MediaLibrarySession.Builder;
 import android.media.MediaLibraryService2.MediaLibrarySession.MediaLibrarySessionCallback;
 import android.media.MediaSession2.ControllerInfo;
@@ -74,8 +73,8 @@
          * Callback for the {@link MediaLibrarySession}.
          */
         public static class MediaLibrarySessionCallback extends MediaSession2.SessionCallback {
-            public MediaLibrarySessionCallback(@NonNull Context context) {
-                super(context);
+            public MediaLibrarySessionCallback() {
+                super();
             }
 
             /**
@@ -401,10 +400,9 @@
          * @param rootId The root id for browsing.
          * @param extras Any extras about the library service.
          */
-        public LibraryRoot(@NonNull Context context,
-                @NonNull String rootId, @Nullable Bundle extras) {
+        public LibraryRoot(@NonNull String rootId, @Nullable Bundle extras) {
             mProvider = ApiLoader.getProvider().createMediaLibraryService2LibraryRoot(
-                    context, this, rootId, extras);
+                    this, rootId, extras);
         }
 
         /**
diff --git a/media/java/android/media/MediaMetadata2.java b/media/java/android/media/MediaMetadata2.java
index 59dd8cb..7b03ae0 100644
--- a/media/java/android/media/MediaMetadata2.java
+++ b/media/java/android/media/MediaMetadata2.java
@@ -19,7 +19,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StringDef;
-import android.content.Context;
 import android.graphics.Bitmap;
 import android.media.update.ApiLoader;
 import android.media.update.MediaMetadata2Provider;
@@ -657,13 +656,11 @@
      * Creates the {@link MediaMetadata2} from the bundle that previously returned by
      * {@link #toBundle()}.
      *
-     * @param context context
      * @param bundle bundle for the metadata
      * @return a new MediaMetadata2
      */
-    public static @NonNull MediaMetadata2 fromBundle(@NonNull Context context,
-            @Nullable Bundle bundle) {
-        return ApiLoader.getProvider().fromBundle_MediaMetadata2(context, bundle);
+    public static @NonNull MediaMetadata2 fromBundle(@Nullable Bundle bundle) {
+        return ApiLoader.getProvider().fromBundle_MediaMetadata2(bundle);
     }
 
     /**
@@ -677,8 +674,8 @@
          * Create an empty Builder. Any field that should be included in the
          * {@link MediaMetadata2} must be added.
          */
-        public Builder(@NonNull Context context) {
-            mProvider = ApiLoader.getProvider().createMediaMetadata2Builder(context, this);
+        public Builder() {
+            mProvider = ApiLoader.getProvider().createMediaMetadata2Builder(this);
         }
 
         /**
@@ -688,8 +685,8 @@
          *
          * @param source
          */
-        public Builder(@NonNull Context context, @NonNull MediaMetadata2 source) {
-            mProvider = ApiLoader.getProvider().createMediaMetadata2Builder(context, this, source);
+        public Builder(@NonNull MediaMetadata2 source) {
+            mProvider = ApiLoader.getProvider().createMediaMetadata2Builder(this, source);
         }
 
         /**
diff --git a/media/java/android/media/MediaPlayerBase.java b/media/java/android/media/MediaPlayerBase.java
index 5c08f19..a426552 100644
--- a/media/java/android/media/MediaPlayerBase.java
+++ b/media/java/android/media/MediaPlayerBase.java
@@ -130,33 +130,6 @@
      */
     public abstract void seekTo(long pos);
 
-    /**
-     * Fast forwards playback. If playback is already fast forwarding this may increase the rate.
-     * <p>
-     * Default implementation sets the playback speed to the 2.0f
-     * @see #setPlaybackSpeed(float)
-     * @hide
-     */
-    // TODO(jaewan): Unhide (b/74724709)
-    public void fastForward() {
-        setPlaybackSpeed(2.0f);
-    }
-
-    /**
-     * Rewinds playback. If playback is already rewinding this may increase the rate.
-     * <p>
-     * Default implementation sets the playback speed to the -1.0f if
-     * {@link #isReversePlaybackSupported()} returns {@code true}.
-     * @see #setPlaybackSpeed(float)
-     * @hide
-     */
-    // TODO(jaewan): Unhide (b/74724709)
-    public void rewind() {
-        if (isReversePlaybackSupported()) {
-            setPlaybackSpeed(-1.0f);
-        }
-    }
-
     public static final long UNKNOWN_TIME = -1;
 
     /**
@@ -340,10 +313,19 @@
 
         /**
          * Called to indicate that the playback speed has changed.
-         * @param mpb the player that is buffering
+         * @param mpb the player that has changed the playback speed.
          * @param speed the new playback speed.
          */
         public void onPlaybackSpeedChanged(@NonNull MediaPlayerBase mpb, float speed) { }
+
+        /**
+         * Called to indicate that {@link #seekTo(long)} is completed.
+         *
+         * @param mpb the player that has completed seeking.
+         * @param position the previous seeking request.
+         * @see #seekTo(long)
+         */
+        public void onSeekCompleted(@NonNull MediaPlayerBase mpb, long position) { }
     }
 
 }
diff --git a/media/java/android/media/MediaPlaylistAgent.java b/media/java/android/media/MediaPlaylistAgent.java
index f339229..88f37e7 100644
--- a/media/java/android/media/MediaPlaylistAgent.java
+++ b/media/java/android/media/MediaPlaylistAgent.java
@@ -20,7 +20,6 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.Context;
 import android.media.update.ApiLoader;
 import android.media.update.MediaPlaylistAgentProvider;
 
@@ -148,8 +147,8 @@
                 @RepeatMode int repeatMode) { }
     }
 
-    public MediaPlaylistAgent(@NonNull Context context) {
-        mProvider = ApiLoader.getProvider().createMediaPlaylistAgent(context, this);
+    public MediaPlaylistAgent() {
+        mProvider = ApiLoader.getProvider().createMediaPlaylistAgent(this);
     }
 
     /**
diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java
index 2033c59..2b3c2b4 100644
--- a/media/java/android/media/MediaSession2.java
+++ b/media/java/android/media/MediaSession2.java
@@ -33,8 +33,6 @@
 import android.media.update.MediaSession2Provider;
 import android.media.update.MediaSession2Provider.BuilderBaseProvider;
 import android.media.update.MediaSession2Provider.CommandButtonProvider;
-import android.media.update.MediaSession2Provider.CommandGroupProvider;
-import android.media.update.MediaSession2Provider.CommandProvider;
 import android.media.update.MediaSession2Provider.ControllerInfoProvider;
 import android.media.update.ProviderCreator;
 import android.net.Uri;
@@ -45,7 +43,6 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.List;
-import java.util.Set;
 import java.util.concurrent.Executor;
 
 /**
@@ -85,255 +82,6 @@
     private final MediaSession2Provider mProvider;
 
     /**
-     * Command code for the custom command which can be defined by string action in the
-     * {@link Command}.
-     */
-    public static final int COMMAND_CODE_CUSTOM = 0;
-
-    /**
-     * Command code for {@link MediaController2#play()}.
-     * <p>
-     * Command would be sent directly to the player if the session doesn't reject the request
-     * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
-     */
-    public static final int COMMAND_CODE_PLAYBACK_PLAY = 1;
-
-    /**
-     * Command code for {@link MediaController2#pause()}.
-     * <p>
-     * Command would be sent directly to the player if the session doesn't reject the request
-     * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
-     */
-    public static final int COMMAND_CODE_PLAYBACK_PAUSE = 2;
-
-    /**
-     * Command code for {@link MediaController2#stop()}.
-     * <p>
-     * Command would be sent directly to the player if the session doesn't reject the request
-     * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
-     */
-    public static final int COMMAND_CODE_PLAYBACK_STOP = 3;
-
-    /**
-     * Command code for {@link MediaController2#skipToNextItem()}.
-     * <p>
-     * Command would be sent directly to the playlist agent if the session doesn't reject the
-     * request through the {@link SessionCallback#onCommandRequest(
-     * MediaSession2, ControllerInfo, Command)}.
-     */
-    public static final int COMMAND_CODE_PLAYLIST_SKIP_NEXT_ITEM = 4;
-
-    /**
-     * Command code for {@link MediaController2#skipToPreviousItem()}.
-     * <p>
-     * Command would be sent directly to the playlist agent if the session doesn't reject the
-     * request through the {@link SessionCallback#onCommandRequest(
-     * MediaSession2, ControllerInfo, Command)}.
-     */
-    public static final int COMMAND_CODE_PLAYLIST_SKIP_PREV_ITEM = 5;
-
-    /**
-     * Command code for {@link MediaController2#prepare()}.
-     * <p>
-     * Command would be sent directly to the player if the session doesn't reject the request
-     * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
-     */
-    public static final int COMMAND_CODE_PLAYBACK_PREPARE = 6;
-
-    /**
-     * Command code for {@link MediaController2#fastForward()}.
-     * <p>
-     * This is transport control command. Command would be sent directly to the player if the
-     * session doesn't reject the request through the
-     * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
-     */
-    public static final int COMMAND_CODE_PLAYBACK_FAST_FORWARD = 7;
-
-    /**
-     * Command code for {@link MediaController2#rewind()}.
-     * <p>
-     * Command would be sent directly to the player if the session doesn't reject the request
-     * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
-     */
-    public static final int COMMAND_CODE_PLAYBACK_REWIND = 8;
-
-    /**
-     * Command code for {@link MediaController2#seekTo(long)}.
-     * <p>
-     * Command would be sent directly to the player if the session doesn't reject the request
-     * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
-     */
-    public static final int COMMAND_CODE_PLAYBACK_SEEK_TO = 9;
-
-    /**
-     * Command code for both {@link MediaController2#setVolumeTo(int, int)}.
-     * <p>
-     * Command would set the device volume or send to the volume provider directly if the session
-     * doesn't reject the request through the
-     * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
-     */
-    public static final int COMMAND_CODE_PLAYBACK_SET_VOLUME = 10;
-
-    /**
-     * Command code for both {@link MediaController2#adjustVolume(int, int)}.
-     * <p>
-     * Command would adjust the device volume or send to the volume provider directly if the session
-     * doesn't reject the request through the
-     * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
-     */
-    public static final int COMMAND_CODE_PLAYBACK_ADJUST_VOLUME = 11;
-
-    /**
-     * Command code for {@link MediaController2#skipToPlaylistItem(MediaItem2)}.
-     * <p>
-     * Command would be sent directly to the playlist agent if the session doesn't reject the
-     * request through the
-     * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
-     */
-    public static final int COMMAND_CODE_PLAYLIST_SKIP_TO_PLAYLIST_ITEM = 12;
-
-    /**
-     * Command code for {@link MediaController2#setShuffleMode(int)}.
-     * <p>
-     * Command would be sent directly to the playlist agent if the session doesn't reject the
-     * request through the
-     * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
-     */
-    public static final int COMMAND_CODE_PLAYLIST_SET_SHUFFLE_MODE = 13;
-
-    /**
-     * Command code for {@link MediaController2#setRepeatMode(int)}.
-     * <p>
-     * Command would be sent directly to the playlist agent if the session doesn't reject the
-     * request through the
-     * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
-     */
-    public static final int COMMAND_CODE_PLAYLIST_SET_REPEAT_MODE = 14;
-
-    /**
-     * Command code for {@link MediaController2#addPlaylistItem(int, MediaItem2)}.
-     * <p>
-     * Command would be sent directly to the playlist agent if the session doesn't reject the
-     * request through the
-     * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
-     */
-    public static final int COMMAND_CODE_PLAYLIST_ADD_ITEM = 15;
-
-    /**
-     * Command code for {@link MediaController2#addPlaylistItem(int, MediaItem2)}.
-     * <p>
-     * Command would be sent directly to the playlist agent if the session doesn't reject the
-     * request through the
-     * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
-     */
-    public static final int COMMAND_CODE_PLAYLIST_REMOVE_ITEM = 16;
-
-    /**
-     * Command code for {@link MediaController2#replacePlaylistItem(int, MediaItem2)}.
-     * <p>
-     * Command would be sent directly to the playlist agent if the session doesn't reject the
-     * request through the
-     * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
-     */
-    public static final int COMMAND_CODE_PLAYLIST_REPLACE_ITEM = 17;
-
-    /**
-     * Command code for {@link MediaController2#getPlaylist()}. This will expose metadata
-     * information to the controller.
-     * <p>
-     * Command would be sent directly to the playlist agent if the session doesn't reject the
-     * request through the
-     * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
-     */
-    public static final int COMMAND_CODE_PLAYLIST_GET_LIST = 18;
-
-    /**
-     * Command code for {@link MediaController2#setPlaylist(List, MediaMetadata2)}.
-     * <p>
-     * Command would be sent directly to the playlist agent if the session doesn't reject the
-     * request through the
-     * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
-     */
-    public static final int COMMAND_CODE_PLAYLIST_SET_LIST = 19;
-
-    /**
-     * Command code for {@link MediaController2#getPlaylistMetadata()}. This will expose
-     * metadata information to the controller.
-     * <p>
-     * Command would be sent directly to the playlist agent if the session doesn't reject the
-     * request through the
-     * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
-     */
-    public static final int COMMAND_CODE_PLAYLIST_GET_LIST_METADATA = 20;
-
-    /**
-     * Command code for {@link MediaController2#updatePlaylistMetadata(MediaMetadata2)}.
-     * <p>
-     * Command would be sent directly to the playlist agent if the session doesn't reject the
-     * request through the
-     * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
-     */
-    public static final int COMMAND_CODE_PLAYLIST_SET_LIST_METADATA = 21;
-
-    /**
-     * Command code for {@link MediaController2#playFromMediaId(String, Bundle)}.
-     */
-    public static final int COMMAND_CODE_SESSION_PLAY_FROM_MEDIA_ID = 22;
-
-    /**
-     * Command code for {@link MediaController2#playFromUri(Uri, Bundle)}.
-     */
-    public static final int COMMAND_CODE_SESSION_PLAY_FROM_URI = 23;
-
-    /**
-     * Command code for {@link MediaController2#playFromSearch(String, Bundle)}.
-     */
-    public static final int COMMAND_CODE_SESSION_PLAY_FROM_SEARCH = 24;
-
-    /**
-     * Command code for {@link MediaController2#prepareFromMediaId(String, Bundle)}.
-     */
-    public static final int COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID = 25;
-
-    /**
-     * Command code for {@link MediaController2#prepareFromUri(Uri, Bundle)}.
-     */
-    public static final int COMMAND_CODE_SESSION_PREPARE_FROM_URI = 26;
-
-    /**
-     * Command code for {@link MediaController2#prepareFromSearch(String, Bundle)}.
-     */
-    public static final int COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH = 27;
-
-    /**
-     * Command code for {@link MediaController2#setRating(String, Rating2)}.
-     * @hide
-     */
-    public static final int COMMAND_CODE_SESSION_SET_RATING = 28;
-
-    /**
-     * Command code for {@link android.media.MediaLibraryService2.MediaLibrarySession} specific
-     * functions. With or without this, a {@link MediaSession2} that isn't
-     * {@link android.media.MediaLibraryService2.MediaLibrarySession} would automatically reject
-     * the calls.
-     *
-     * @see android.media.MediaLibraryService2.MediaLibrarySession
-     * @see MediaBrowser2
-     * @hide
-     */
-    // TODO(jaewan): Remove
-    public static final int COMMAND_CODE_BROWSER = 29;
-
-    // TODO(jaewan): Add javadoc
-    public static final int COMMAND_CODE_LIBRARY_GET_CHILDREN = 29;
-    public static final int COMMAND_CODE_LIBRARY_GET_ITEM = 30;
-    public static final int COMMAND_CODE_LIBRARY_GET_LIBRARY_ROOT = 31;
-    public static final int COMMAND_CODE_LIBRARY_GET_SEARCH_RESULT = 32;
-    public static final int COMMAND_CODE_LIBRARY_SEARCH = 33;
-    public static final int COMMAND_CODE_LIBRARY_SUBSCRIBE = 34;
-    public static final int COMMAND_CODE_LIBRARY_UNSUBSCRIBE = 35;
-
-    /**
      * @hide
      */
     @IntDef({ERROR_CODE_UNKNOWN_ERROR, ERROR_CODE_APP_ERROR, ERROR_CODE_NOT_SUPPORTED,
@@ -436,157 +184,6 @@
     }
 
     /**
-     * Define a command that a {@link MediaController2} can send to a {@link MediaSession2}.
-     * <p>
-     * If {@link #getCommandCode()} isn't {@link #COMMAND_CODE_CUSTOM}), it's predefined command.
-     * If {@link #getCommandCode()} is {@link #COMMAND_CODE_CUSTOM}), it's custom command and
-     * {@link #getCustomCommand()} shouldn't be {@code null}.
-     */
-    public static final class Command {
-        private final CommandProvider mProvider;
-
-        public Command(@NonNull Context context, int commandCode) {
-            mProvider = ApiLoader.getProvider().createMediaSession2Command(
-                    this, commandCode, null, null);
-        }
-
-        public Command(@NonNull Context context, @NonNull String action, @Nullable Bundle extras) {
-            if (action == null) {
-                throw new IllegalArgumentException("action shouldn't be null");
-            }
-            mProvider = ApiLoader.getProvider().createMediaSession2Command(
-                    this, COMMAND_CODE_CUSTOM, action, extras);
-        }
-
-        /**
-         * @hide
-         */
-        public CommandProvider getProvider() {
-            return mProvider;
-        }
-
-        public int getCommandCode() {
-            return mProvider.getCommandCode_impl();
-        }
-
-        public @Nullable String getCustomCommand() {
-            return mProvider.getCustomCommand_impl();
-        }
-
-        public @Nullable Bundle getExtras() {
-            return mProvider.getExtras_impl();
-        }
-
-        /**
-         * @return a new Bundle instance from the Command
-         * @hide
-         */
-        public Bundle toBundle() {
-            return mProvider.toBundle_impl();
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (!(obj instanceof Command)) {
-                return false;
-            }
-            return mProvider.equals_impl(((Command) obj).mProvider);
-        }
-
-        @Override
-        public int hashCode() {
-            return mProvider.hashCode_impl();
-        }
-
-        /**
-         * @return a new Command instance from the Bundle
-         * @hide
-         */
-        public static Command fromBundle(@NonNull Context context, @NonNull Bundle command) {
-            return ApiLoader.getProvider().fromBundle_MediaSession2Command(context, command);
-        }
-    }
-
-    /**
-     * Represent set of {@link Command}.
-     */
-    public static final class CommandGroup {
-        private final CommandGroupProvider mProvider;
-
-        public CommandGroup(@NonNull Context context) {
-            mProvider = ApiLoader.getProvider().createMediaSession2CommandGroup(
-                    context, this, null);
-        }
-
-        public CommandGroup(@NonNull Context context, @Nullable CommandGroup others) {
-            mProvider = ApiLoader.getProvider().createMediaSession2CommandGroup(
-                    context, this, others);
-        }
-
-        /**
-         * @hide
-         */
-        public CommandGroup(@NonNull CommandGroupProvider provider) {
-            mProvider = provider;
-        }
-
-        public void addCommand(@NonNull Command command) {
-            mProvider.addCommand_impl(command);
-        }
-
-        public void addCommand(int commandCode) {
-            // TODO(jaewna): Implement
-        }
-
-        public void addAllPredefinedCommands() {
-            mProvider.addAllPredefinedCommands_impl();
-        }
-
-        public void removeCommand(@NonNull Command command) {
-            mProvider.removeCommand_impl(command);
-        }
-
-        public void removeCommand(int commandCode) {
-            // TODO(jaewan): Implement.
-        }
-
-        public boolean hasCommand(@NonNull Command command) {
-            return mProvider.hasCommand_impl(command);
-        }
-
-        public boolean hasCommand(int code) {
-            return mProvider.hasCommand_impl(code);
-        }
-
-        public @NonNull Set<Command> getCommands() {
-            return mProvider.getCommands_impl();
-        }
-
-        /**
-         * @hide
-         */
-        public @NonNull CommandGroupProvider getProvider() {
-            return mProvider;
-        }
-
-        /**
-         * @return new bundle from the CommandGroup
-         * @hide
-         */
-        public @NonNull Bundle toBundle() {
-            return mProvider.toBundle_impl();
-        }
-
-        /**
-         * @return new instance of CommandGroup from the bundle
-         * @hide
-         */
-        public static @Nullable CommandGroup fromBundle(Context context, Bundle commands) {
-            return ApiLoader.getProvider().fromBundle_MediaSession2CommandGroup(context, commands);
-        }
-    }
-
-    /**
      * Callback to be called for all incoming commands from {@link MediaController2}s.
      * <p>
      * If it's not set, the session will accept all controllers and all incoming commands by
@@ -594,15 +191,6 @@
      */
     // TODO(jaewan): Move this to updatable for default implementation (b/74091963)
     public static abstract class SessionCallback {
-        private final Context mContext;
-
-        public SessionCallback(@NonNull Context context) {
-            if (context == null) {
-                throw new IllegalArgumentException("context shouldn't be null");
-            }
-            mContext = context;
-        }
-
         /**
          * Called when a controller is created for this session. Return allowed commands for
          * controller. By default it allows all connection requests and commands.
@@ -615,9 +203,9 @@
          * @param controller controller information.
          * @return allowed commands. Can be {@code null} to reject connection.
          */
-        public @Nullable CommandGroup onConnect(@NonNull MediaSession2 session,
+        public @Nullable SessionCommandGroup2 onConnect(@NonNull MediaSession2 session,
                 @NonNull ControllerInfo controller) {
-            CommandGroup commands = new CommandGroup(mContext);
+            SessionCommandGroup2 commands = new SessionCommandGroup2();
             commands.addAllPredefinedCommands();
             return commands;
         }
@@ -639,23 +227,23 @@
          * @param controller controller information.
          * @param command a command. This method will be called for every single command.
          * @return {@code true} if you want to accept incoming command. {@code false} otherwise.
-         * @see #COMMAND_CODE_PLAYBACK_PLAY
-         * @see #COMMAND_CODE_PLAYBACK_PAUSE
-         * @see #COMMAND_CODE_PLAYBACK_STOP
-         * @see #COMMAND_CODE_PLAYLIST_SKIP_NEXT_ITEM
-         * @see #COMMAND_CODE_PLAYLIST_SKIP_PREV_ITEM
-         * @see #COMMAND_CODE_PLAYBACK_PREPARE
-         * @see #COMMAND_CODE_PLAYBACK_FAST_FORWARD
-         * @see #COMMAND_CODE_PLAYBACK_REWIND
-         * @see #COMMAND_CODE_PLAYBACK_SEEK_TO
-         * @see #COMMAND_CODE_PLAYLIST_SKIP_TO_PLAYLIST_ITEM
-         * @see #COMMAND_CODE_PLAYLIST_ADD_ITEM
-         * @see #COMMAND_CODE_PLAYLIST_REMOVE_ITEM
-         * @see #COMMAND_CODE_PLAYLIST_GET_LIST
-         * @see #COMMAND_CODE_PLAYBACK_SET_VOLUME
+         * @see SessionCommand2#COMMAND_CODE_PLAYBACK_PLAY
+         * @see SessionCommand2#COMMAND_CODE_PLAYBACK_PAUSE
+         * @see SessionCommand2#COMMAND_CODE_PLAYBACK_STOP
+         * @see SessionCommand2#COMMAND_CODE_PLAYLIST_SKIP_NEXT_ITEM
+         * @see SessionCommand2#COMMAND_CODE_PLAYLIST_SKIP_PREV_ITEM
+         * @see SessionCommand2#COMMAND_CODE_PLAYBACK_PREPARE
+         * @see SessionCommand2#COMMAND_CODE_SESSION_FAST_FORWARD
+         * @see SessionCommand2#COMMAND_CODE_SESSION_REWIND
+         * @see SessionCommand2#COMMAND_CODE_PLAYBACK_SEEK_TO
+         * @see SessionCommand2#COMMAND_CODE_PLAYLIST_SKIP_TO_PLAYLIST_ITEM
+         * @see SessionCommand2#COMMAND_CODE_PLAYLIST_ADD_ITEM
+         * @see SessionCommand2#COMMAND_CODE_PLAYLIST_REMOVE_ITEM
+         * @see SessionCommand2#COMMAND_CODE_PLAYLIST_GET_LIST
+         * @see SessionCommand2#COMMAND_CODE_SET_VOLUME
          */
         public boolean onCommandRequest(@NonNull MediaSession2 session,
-                @NonNull ControllerInfo controller, @NonNull Command command) {
+                @NonNull ControllerInfo controller, @NonNull SessionCommand2 command) {
             return true;
         }
 
@@ -678,7 +266,7 @@
 
         /**
          * Called when a controller sent a custom command through
-         * {@link MediaController2#sendCustomCommand(Command, Bundle, ResultReceiver)}.
+         * {@link MediaController2#sendCustomCommand(SessionCommand2, Bundle, ResultReceiver)}.
          *
          * @param session the session for this event
          * @param controller controller information
@@ -687,7 +275,7 @@
          * @param cb optional result receiver
          */
         public void onCustomCommand(@NonNull MediaSession2 session,
-                @NonNull ControllerInfo controller, @NonNull Command customCommand,
+                @NonNull ControllerInfo controller, @NonNull SessionCommand2 customCommand,
                 @Nullable Bundle args, @Nullable ResultReceiver cb) { }
 
         /**
@@ -698,7 +286,7 @@
          * @param controller controller information
          * @param mediaId media id
          * @param extras optional extra bundle
-         * @see #COMMAND_CODE_SESSION_PLAY_FROM_MEDIA_ID
+         * @see SessionCommand2#COMMAND_CODE_SESSION_PLAY_FROM_MEDIA_ID
          */
         public void onPlayFromMediaId(@NonNull MediaSession2 session,
                 @NonNull ControllerInfo controller, @NonNull String mediaId,
@@ -715,7 +303,7 @@
          * @param controller controller information
          * @param query query string. Can be empty to indicate any suggested media
          * @param extras optional extra bundle
-         * @see #COMMAND_CODE_SESSION_PLAY_FROM_SEARCH
+         * @see SessionCommand2#COMMAND_CODE_SESSION_PLAY_FROM_SEARCH
          */
         public void onPlayFromSearch(@NonNull MediaSession2 session,
                 @NonNull ControllerInfo controller, @NonNull String query,
@@ -729,7 +317,7 @@
          * @param controller controller information
          * @param uri uri
          * @param extras optional extra bundle
-         * @see #COMMAND_CODE_SESSION_PLAY_FROM_URI
+         * @see SessionCommand2#COMMAND_CODE_SESSION_PLAY_FROM_URI
          */
         public void onPlayFromUri(@NonNull MediaSession2 session,
                 @NonNull ControllerInfo controller, @NonNull Uri uri,
@@ -753,7 +341,7 @@
          * @param controller controller information
          * @param mediaId media id to prepare
          * @param extras optional extra bundle
-         * @see #COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID
+         * @see SessionCommand2#COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID
          */
         public void onPrepareFromMediaId(@NonNull MediaSession2 session,
                 @NonNull ControllerInfo controller, @NonNull String mediaId,
@@ -777,7 +365,7 @@
          * @param controller controller information
          * @param query query string. Can be empty to indicate any suggested media
          * @param extras optional extra bundle
-         * @see #COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH
+         * @see SessionCommand2#COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH
          */
         public void onPrepareFromSearch(@NonNull MediaSession2 session,
                 @NonNull ControllerInfo controller, @NonNull String query,
@@ -801,12 +389,26 @@
          * @param controller controller information
          * @param uri uri
          * @param extras optional extra bundle
-         * @see #COMMAND_CODE_SESSION_PREPARE_FROM_URI
+         * @see SessionCommand2#COMMAND_CODE_SESSION_PREPARE_FROM_URI
          */
         public void onPrepareFromUri(@NonNull MediaSession2 session,
                 @NonNull ControllerInfo controller, @NonNull Uri uri, @Nullable Bundle extras) { }
 
         /**
+         * Called when a controller called {@link MediaController2#fastForward()}
+         *
+         * @param session the session for this event
+         */
+        public void onFastForward(@NonNull MediaSession2 session) { }
+
+        /**
+         * Called when a controller called {@link MediaController2#rewind()}
+         *
+         * @param session the session for this event
+         */
+        public void onRewind(@NonNull MediaSession2 session) { }
+
+        /**
          * Called when the player's current playing item is changed
          * <p>
          * When it's called, you should invalidate previous playback information and wait for later
@@ -861,6 +463,17 @@
                 @NonNull MediaPlayerBase player, float speed) { }
 
         /**
+         * Called to indicate that {@link #seekTo(long)} is completed.
+         *
+         * @param session the session for this event.
+         * @param mpb the player that has completed seeking.
+         * @param position the previous seeking request.
+         * @see #seekTo(long)
+         */
+        public void onSeekCompleted(@NonNull MediaSession2 session, @NonNull MediaPlayerBase mpb,
+                long position) { }
+
+        /**
          * Called when a playlist is changed from the {@link MediaPlaylistAgent}.
          * <p>
          * This is called when the underlying agent has called
@@ -1146,7 +759,7 @@
     }
 
     /**
-     * Button for a {@link Command} that will be shown by the controller.
+     * Button for a {@link SessionCommand2} that will be shown by the controller.
      * <p>
      * It's up to the controller's decision to respect or ignore this customization request.
      */
@@ -1166,7 +779,8 @@
          *
          * @return command or {@code null}
          */
-        public @Nullable Command getCommand() {
+        public @Nullable
+        SessionCommand2 getCommand() {
             return mProvider.getCommand_impl();
         }
 
@@ -1221,12 +835,11 @@
         public static final class Builder {
             private final CommandButtonProvider.BuilderProvider mProvider;
 
-            public Builder(@NonNull Context context) {
-                mProvider = ApiLoader.getProvider().createMediaSession2CommandButtonBuilder(
-                        context, this);
+            public Builder() {
+                mProvider = ApiLoader.getProvider().createMediaSession2CommandButtonBuilder(this);
             }
 
-            public @NonNull Builder setCommand(@Nullable Command command) {
+            public @NonNull Builder setCommand(@Nullable SessionCommand2 command) {
                 return mProvider.setCommand_impl(command);
             }
 
@@ -1363,7 +976,8 @@
      *      expanded row:   layout[5] layout[6] layout[7] layout[8] layout[9]
      *      main row:       layout[3] layout[1] layout[0] layout[2] layout[4]
      * <p>
-     * This API can be called in the {@link SessionCallback#onConnect(MediaSession2, ControllerInfo)}.
+     * This API can be called in the {@link SessionCallback#onConnect(
+     * MediaSession2, ControllerInfo)}.
      *
      * @param controller controller to specify layout.
      * @param layout ordered list of layout.
@@ -1380,7 +994,7 @@
      * @param commands new allowed commands
      */
     public void setAllowedCommands(@NonNull ControllerInfo controller,
-            @NonNull CommandGroup commands) {
+            @NonNull SessionCommandGroup2 commands) {
         mProvider.setAllowedCommands_impl(controller, commands);
     }
 
@@ -1390,7 +1004,7 @@
      * @param command a command
      * @param args optional argument
      */
-    public void sendCustomCommand(@NonNull Command command, @Nullable Bundle args) {
+    public void sendCustomCommand(@NonNull SessionCommand2 command, @Nullable Bundle args) {
         mProvider.sendCustomCommand_impl(command, args);
     }
 
@@ -1401,8 +1015,9 @@
      * @param args optional argument
      * @param receiver result receiver for the session
      */
-    public void sendCustomCommand(@NonNull ControllerInfo controller, @NonNull Command command,
-            @Nullable Bundle args, @Nullable ResultReceiver receiver) {
+    public void sendCustomCommand(@NonNull ControllerInfo controller,
+            @NonNull SessionCommand2 command, @Nullable Bundle args,
+            @Nullable ResultReceiver receiver) {
         // Equivalent to the MediaController.sendCustomCommand(Action action, ResultReceiver r);
         mProvider.sendCustomCommand_impl(controller, command, args, receiver);
     }
@@ -1448,20 +1063,6 @@
     }
 
     /**
-     * Fast forwards playback. If playback is already fast forwarding this may increase the rate.
-     */
-    public void fastForward() {
-        mProvider.fastForward_impl();
-    }
-
-    /**
-     * Rewinds playback. If playback is already rewinding this may increase the rate.
-     */
-    public void rewind() {
-        mProvider.rewind_impl();
-    }
-
-    /**
      * Move to a new location in the media stream.
      *
      * @param pos Position to move to, in milliseconds.
@@ -1562,7 +1163,8 @@
      *      <li>{@link MediaItem2} specified by {@link #setPlaylist(List, MediaMetadata2)} doesn't
      *          have {@link DataSourceDesc}</li>
      *      <li>{@link MediaController2#addPlaylistItem(int, MediaItem2)} is called and accepted
-     *          by {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
+     *          by {@link SessionCallback#onCommandRequest(
+     *          MediaSession2, ControllerInfo, SessionCommand2)}.
      *          In that case, an item would be added automatically without the data source.</li>
      * </ul>
      * <p>
@@ -1574,9 +1176,9 @@
      * @param helper a data source missing helper.
      * @throws IllegalStateException when the helper is set when the playlist agent is set
      * @see #setPlaylist(List, MediaMetadata2)
-     * @see SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)
-     * @see #COMMAND_CODE_PLAYLIST_ADD_ITEM
-     * @see #COMMAND_CODE_PLAYLIST_REPLACE_ITEM
+     * @see SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2)
+     * @see SessionCommand2#COMMAND_CODE_PLAYLIST_ADD_ITEM
+     * @see SessionCommand2#COMMAND_CODE_PLAYLIST_REPLACE_ITEM
      */
     public void setOnDataSourceMissingHelper(@NonNull OnDataSourceMissingHelper helper) {
         mProvider.setOnDataSourceMissingHelper_impl(helper);
diff --git a/media/java/android/media/MediaSessionService2.java b/media/java/android/media/MediaSessionService2.java
index 85ac9b2..6c3a4bf 100644
--- a/media/java/android/media/MediaSessionService2.java
+++ b/media/java/android/media/MediaSessionService2.java
@@ -21,7 +21,6 @@
 import android.annotation.Nullable;
 import android.app.Notification;
 import android.app.Service;
-import android.content.Context;
 import android.content.Intent;
 import android.media.MediaSession2.ControllerInfo;
 import android.media.update.ApiLoader;
@@ -213,16 +212,14 @@
         /**
          * Default constructor
          *
-         * @param context context
          * @param notificationId notification id to be used for
          *      {@link android.app.NotificationManager#notify(int, Notification)}.
          * @param notification a notification to make session service foreground service. Media
          *      style notification is recommended here.
          */
-        public MediaNotification(@NonNull Context context,
-                int notificationId, @NonNull Notification notification) {
+        public MediaNotification(int notificationId, @NonNull Notification notification) {
             mProvider = ApiLoader.getProvider().createMediaSessionService2MediaNotification(
-                    context, this, notificationId, notification);
+                    this, notificationId, notification);
         }
 
         public int getNotificationId() {
diff --git a/media/java/android/media/Rating2.java b/media/java/android/media/Rating2.java
index 5f7a334..9213190 100644
--- a/media/java/android/media/Rating2.java
+++ b/media/java/android/media/Rating2.java
@@ -19,7 +19,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.IntDef;
-import android.content.Context;
 import android.media.update.ApiLoader;
 import android.media.update.Rating2Provider;
 import android.os.Bundle;
@@ -29,6 +28,7 @@
 import java.lang.annotation.RetentionPolicy;
 
 /**
+ * @hide
  * A class to encapsulate rating information used as content metadata.
  * A rating is defined by its rating style (see {@link #RATING_HEART},
  * {@link #RATING_THUMB_UP_DOWN}, {@link #RATING_3_STARS}, {@link #RATING_4_STARS},
@@ -126,12 +126,11 @@
     /**
      * Create an instance from bundle object, previoulsy created by {@link #toBundle()}
      *
-     * @param context context
      * @param bundle bundle
      * @return new Rating2 instance or {@code null} for error
      */
-    public static Rating2 fromBundle(@NonNull Context context, @Nullable Bundle bundle) {
-        return ApiLoader.getProvider().fromBundle_Rating2(context, bundle);
+    public static Rating2 fromBundle(@Nullable Bundle bundle) {
+        return ApiLoader.getProvider().fromBundle_Rating2(bundle);
     }
 
     /**
@@ -146,39 +145,35 @@
      * Return a Rating2 instance with no rating.
      * Create and return a new Rating2 instance with no rating known for the given
      * rating style.
-     * @param context context
      * @param ratingStyle one of {@link #RATING_HEART}, {@link #RATING_THUMB_UP_DOWN},
      *    {@link #RATING_3_STARS}, {@link #RATING_4_STARS}, {@link #RATING_5_STARS},
      *    or {@link #RATING_PERCENTAGE}.
      * @return null if an invalid rating style is passed, a new Rating2 instance otherwise.
      */
-    public static @Nullable Rating2 newUnratedRating(@NonNull Context context,
-            @Style int ratingStyle) {
-        return ApiLoader.getProvider().newUnratedRating_Rating2(context, ratingStyle);
+    public static @Nullable Rating2 newUnratedRating(@Style int ratingStyle) {
+        return ApiLoader.getProvider().newUnratedRating_Rating2(ratingStyle);
     }
 
     /**
      * Return a Rating2 instance with a heart-based rating.
      * Create and return a new Rating2 instance with a rating style of {@link #RATING_HEART},
      * and a heart-based rating.
-     * @param context context
      * @param hasHeart true for a "heart selected" rating, false for "heart unselected".
      * @return a new Rating2 instance.
      */
-    public static @Nullable Rating2 newHeartRating(@NonNull Context context, boolean hasHeart) {
-        return ApiLoader.getProvider().newHeartRating_Rating2(context, hasHeart);
+    public static @Nullable Rating2 newHeartRating(boolean hasHeart) {
+        return ApiLoader.getProvider().newHeartRating_Rating2(hasHeart);
     }
 
     /**
      * Return a Rating2 instance with a thumb-based rating.
      * Create and return a new Rating2 instance with a {@link #RATING_THUMB_UP_DOWN}
      * rating style, and a "thumb up" or "thumb down" rating.
-     * @param context context
      * @param thumbIsUp true for a "thumb up" rating, false for "thumb down".
      * @return a new Rating2 instance.
      */
-    public static @Nullable Rating2 newThumbRating(@NonNull Context context, boolean thumbIsUp) {
-        return ApiLoader.getProvider().newThumbRating_Rating2(context, thumbIsUp);
+    public static @Nullable Rating2 newThumbRating(boolean thumbIsUp) {
+        return ApiLoader.getProvider().newThumbRating_Rating2(thumbIsUp);
     }
 
     /**
@@ -186,7 +181,6 @@
      * Create and return a new Rating2 instance with one of the star-base rating styles
      * and the given integer or fractional number of stars. Non integer values can for instance
      * be used to represent an average rating value, which might not be an integer number of stars.
-     * @param context context
      * @param starRatingStyle one of {@link #RATING_3_STARS}, {@link #RATING_4_STARS},
      *     {@link #RATING_5_STARS}.
      * @param starRating a number ranging from 0.0f to 3.0f, 4.0f or 5.0f according to
@@ -194,26 +188,25 @@
      * @return null if the rating style is invalid, or the rating is out of range,
      *     a new Rating2 instance otherwise.
      */
-    public static @Nullable Rating2 newStarRating(@NonNull Context context,
+    public static @Nullable Rating2 newStarRating(
             @StarStyle int starRatingStyle, float starRating) {
-        return ApiLoader.getProvider().newStarRating_Rating2(context, starRatingStyle, starRating);
+        return ApiLoader.getProvider().newStarRating_Rating2(starRatingStyle, starRating);
     }
 
     /**
      * Return a Rating2 instance with a percentage-based rating.
      * Create and return a new Rating2 instance with a {@link #RATING_PERCENTAGE}
      * rating style, and a rating of the given percentage.
-     * @param context context
      * @param percent the value of the rating
      * @return null if the rating is out of range, a new Rating2 instance otherwise.
      */
-    public static @Nullable Rating2 newPercentageRating(@NonNull Context context, float percent) {
-        return ApiLoader.getProvider().newPercentageRating_Rating2(context, percent);
+    public static @Nullable Rating2 newPercentageRating(float percent) {
+        return ApiLoader.getProvider().newPercentageRating_Rating2(percent);
     }
 
     /**
      * Return whether there is a rating value available.
-     * @return true if the instance was not created with {@link #newUnratedRating(Context, int)}.
+     * @return true if the instance was not created with {@link #newUnratedRating(int)}.
      */
     public boolean isRated() {
         return mProvider.isRated_impl();
diff --git a/media/java/android/media/SessionCommand2.java b/media/java/android/media/SessionCommand2.java
new file mode 100644
index 0000000..fe86a3a
--- /dev/null
+++ b/media/java/android/media/SessionCommand2.java
@@ -0,0 +1,336 @@
+/*
+ * Copyright 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.media;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.media.update.ApiLoader;
+import android.media.update.MediaSession2Provider;
+import android.media.MediaSession2.ControllerInfo;
+import android.media.MediaSession2.SessionCallback;
+import android.net.Uri;
+import android.os.Bundle;
+
+import java.util.List;
+
+/**
+ * @hide
+ * Define a command that a {@link MediaController2} can send to a {@link MediaSession2}.
+ * <p>
+ * If {@link #getCommandCode()} isn't {@link #COMMAND_CODE_CUSTOM}), it's predefined command.
+ * If {@link #getCommandCode()} is {@link #COMMAND_CODE_CUSTOM}), it's custom command and
+ * {@link #getCustomCommand()} shouldn't be {@code null}.
+ */
+public final class SessionCommand2 {
+    /**
+     * Command code for the custom command which can be defined by string action in the
+     * {@link SessionCommand2}.
+     */
+    public static final int COMMAND_CODE_CUSTOM = 0;
+
+    /**
+     * Command code for {@link MediaController2#play()}.
+     * <p>
+     * Command would be sent directly to the player if the session doesn't reject the request
+     * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo,
+     * SessionCommand2)}.
+     */
+    public static final int COMMAND_CODE_PLAYBACK_PLAY = 1;
+
+    /**
+     * Command code for {@link MediaController2#pause()}.
+     * <p>
+     * Command would be sent directly to the player if the session doesn't reject the request
+     * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo,
+     * SessionCommand2)}.
+     */
+    public static final int COMMAND_CODE_PLAYBACK_PAUSE = 2;
+
+    /**
+     * Command code for {@link MediaController2#stop()}.
+     * <p>
+     * Command would be sent directly to the player if the session doesn't reject the request
+     * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo,
+     * SessionCommand2)}.
+     */
+    public static final int COMMAND_CODE_PLAYBACK_STOP = 3;
+
+    /**
+     * Command code for {@link MediaController2#skipToNextItem()}.
+     * <p>
+     * Command would be sent directly to the playlist agent if the session doesn't reject the
+     * request through the {@link SessionCallback#onCommandRequest(
+     * MediaSession2, ControllerInfo, SessionCommand2)}.
+     */
+    public static final int COMMAND_CODE_PLAYLIST_SKIP_NEXT_ITEM = 4;
+
+    /**
+     * Command code for {@link MediaController2#skipToPreviousItem()}.
+     * <p>
+     * Command would be sent directly to the playlist agent if the session doesn't reject the
+     * request through the {@link SessionCallback#onCommandRequest(
+     * MediaSession2, ControllerInfo, SessionCommand2)}.
+     */
+    public static final int COMMAND_CODE_PLAYLIST_SKIP_PREV_ITEM = 5;
+
+    /**
+     * Command code for {@link MediaController2#prepare()}.
+     * <p>
+     * Command would be sent directly to the player if the session doesn't reject the request
+     * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo,
+     * SessionCommand2)}.
+     */
+    public static final int COMMAND_CODE_PLAYBACK_PREPARE = 6;
+
+    /**
+     * Command code for {@link MediaController2#fastForward()}.
+     */
+    public static final int COMMAND_CODE_SESSION_FAST_FORWARD = 7;
+
+    /**
+     * Command code for {@link MediaController2#rewind()}.
+     */
+    public static final int COMMAND_CODE_SESSION_REWIND = 8;
+
+    /**
+     * Command code for {@link MediaController2#seekTo(long)}.
+     * <p>
+     * Command would be sent directly to the player if the session doesn't reject the request
+     * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo,
+     * SessionCommand2)}.
+     */
+    public static final int COMMAND_CODE_PLAYBACK_SEEK_TO = 9;
+
+    /**
+     * Command code for both {@link MediaController2#setVolumeTo(int, int)}.
+     * <p>
+     * Command would set the device volume or send to the volume provider directly if the session
+     * doesn't reject the request through the
+     * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2)}.
+     */
+    public static final int COMMAND_CODE_SET_VOLUME = 10;
+
+    /**
+     * Command code for both {@link MediaController2#adjustVolume(int, int)}.
+     * <p>
+     * Command would adjust the device volume or send to the volume provider directly if the session
+     * doesn't reject the request through the
+     * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2)}.
+     */
+    public static final int COMMAND_CODE_ADJUST_VOLUME = 11;
+
+    /**
+     * Command code for {@link MediaController2#skipToPlaylistItem(MediaItem2)}.
+     * <p>
+     * Command would be sent directly to the playlist agent if the session doesn't reject the
+     * request through the
+     * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2)}.
+     */
+    public static final int COMMAND_CODE_PLAYLIST_SKIP_TO_PLAYLIST_ITEM = 12;
+
+    /**
+     * Command code for {@link MediaController2#setShuffleMode(int)}.
+     * <p>
+     * Command would be sent directly to the playlist agent if the session doesn't reject the
+     * request through the
+     * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2)}.
+     */
+    public static final int COMMAND_CODE_PLAYLIST_SET_SHUFFLE_MODE = 13;
+
+    /**
+     * Command code for {@link MediaController2#setRepeatMode(int)}.
+     * <p>
+     * Command would be sent directly to the playlist agent if the session doesn't reject the
+     * request through the
+     * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2)}.
+     */
+    public static final int COMMAND_CODE_PLAYLIST_SET_REPEAT_MODE = 14;
+
+    /**
+     * Command code for {@link MediaController2#addPlaylistItem(int, MediaItem2)}.
+     * <p>
+     * Command would be sent directly to the playlist agent if the session doesn't reject the
+     * request through the
+     * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2)}.
+     */
+    public static final int COMMAND_CODE_PLAYLIST_ADD_ITEM = 15;
+
+    /**
+     * Command code for {@link MediaController2#addPlaylistItem(int, MediaItem2)}.
+     * <p>
+     * Command would be sent directly to the playlist agent if the session doesn't reject the
+     * request through the
+     * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2)}.
+     */
+    public static final int COMMAND_CODE_PLAYLIST_REMOVE_ITEM = 16;
+
+    /**
+     * Command code for {@link MediaController2#replacePlaylistItem(int, MediaItem2)}.
+     * <p>
+     * Command would be sent directly to the playlist agent if the session doesn't reject the
+     * request through the
+     * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2)}.
+     */
+    public static final int COMMAND_CODE_PLAYLIST_REPLACE_ITEM = 17;
+
+    /**
+     * Command code for {@link MediaController2#getPlaylist()}. This will expose metadata
+     * information to the controller.
+     * <p>
+     * Command would be sent directly to the playlist agent if the session doesn't reject the
+     * request through the
+     * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2)}.
+     */
+    public static final int COMMAND_CODE_PLAYLIST_GET_LIST = 18;
+
+    /**
+     * Command code for {@link MediaController2#setPlaylist(List, MediaMetadata2)}.
+     * <p>
+     * Command would be sent directly to the playlist agent if the session doesn't reject the
+     * request through the
+     * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2)}.
+     */
+    public static final int COMMAND_CODE_PLAYLIST_SET_LIST = 19;
+
+    /**
+     * Command code for {@link MediaController2#getPlaylistMetadata()}. This will expose
+     * metadata information to the controller.
+     * <p>
+     * Command would be sent directly to the playlist agent if the session doesn't reject the
+     * request through the
+     * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2)}.
+     */
+    public static final int COMMAND_CODE_PLAYLIST_GET_LIST_METADATA = 20;
+
+    /**
+     * Command code for {@link MediaController2#updatePlaylistMetadata(MediaMetadata2)}.
+     * <p>
+     * Command would be sent directly to the playlist agent if the session doesn't reject the
+     * request through the
+     * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2)}.
+     */
+    public static final int COMMAND_CODE_PLAYLIST_SET_LIST_METADATA = 21;
+
+    /**
+     * Command code for {@link MediaController2#playFromMediaId(String, Bundle)}.
+     */
+    public static final int COMMAND_CODE_SESSION_PLAY_FROM_MEDIA_ID = 22;
+
+    /**
+     * Command code for {@link MediaController2#playFromUri(Uri, Bundle)}.
+     */
+    public static final int COMMAND_CODE_SESSION_PLAY_FROM_URI = 23;
+
+    /**
+     * Command code for {@link MediaController2#playFromSearch(String, Bundle)}.
+     */
+    public static final int COMMAND_CODE_SESSION_PLAY_FROM_SEARCH = 24;
+
+    /**
+     * Command code for {@link MediaController2#prepareFromMediaId(String, Bundle)}.
+     */
+    public static final int COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID = 25;
+
+    /**
+     * Command code for {@link MediaController2#prepareFromUri(Uri, Bundle)}.
+     */
+    public static final int COMMAND_CODE_SESSION_PREPARE_FROM_URI = 26;
+
+    /**
+     * Command code for {@link MediaController2#prepareFromSearch(String, Bundle)}.
+     */
+    public static final int COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH = 27;
+
+    /**
+     * Command code for {@link MediaController2#setRating(String, Rating2)}.
+     */
+    public static final int COMMAND_CODE_SESSION_SET_RATING = 28;
+
+    // TODO(jaewan): Add javadoc
+    public static final int COMMAND_CODE_LIBRARY_GET_CHILDREN = 29;
+    public static final int COMMAND_CODE_LIBRARY_GET_ITEM = 30;
+    public static final int COMMAND_CODE_LIBRARY_GET_LIBRARY_ROOT = 31;
+    public static final int COMMAND_CODE_LIBRARY_GET_SEARCH_RESULT = 32;
+    public static final int COMMAND_CODE_LIBRARY_SEARCH = 33;
+    public static final int COMMAND_CODE_LIBRARY_SUBSCRIBE = 34;
+    public static final int COMMAND_CODE_LIBRARY_UNSUBSCRIBE = 35;
+
+    // TODO(jaewan): Rename and move provider
+    private final MediaSession2Provider.CommandProvider mProvider;
+
+    public SessionCommand2(int commandCode) {
+        mProvider = ApiLoader.getProvider().createMediaSession2Command(
+                this, commandCode, null, null);
+    }
+
+    public SessionCommand2(@NonNull String action, @Nullable Bundle extras) {
+        if (action == null) {
+            throw new IllegalArgumentException("action shouldn't be null");
+        }
+        mProvider = ApiLoader.getProvider().createMediaSession2Command(
+                this, COMMAND_CODE_CUSTOM, action, extras);
+    }
+
+    /**
+     * @hide
+     */
+    public MediaSession2Provider.CommandProvider getProvider() {
+        return mProvider;
+    }
+
+    public int getCommandCode() {
+        return mProvider.getCommandCode_impl();
+    }
+
+    public @Nullable String getCustomCommand() {
+        return mProvider.getCustomCommand_impl();
+    }
+
+    public @Nullable Bundle getExtras() {
+        return mProvider.getExtras_impl();
+    }
+
+    /**
+     * @return a new Bundle instance from the Command
+     * @hide
+     */
+    public Bundle toBundle() {
+        return mProvider.toBundle_impl();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof SessionCommand2)) {
+            return false;
+        }
+        return mProvider.equals_impl(((SessionCommand2) obj).mProvider);
+    }
+
+    @Override
+    public int hashCode() {
+        return mProvider.hashCode_impl();
+    }
+
+    /**
+     * @return a new Command instance from the Bundle
+     * @hide
+     */
+    public static SessionCommand2 fromBundle(@NonNull Bundle command) {
+        return ApiLoader.getProvider().fromBundle_MediaSession2Command(command);
+    }
+}
diff --git a/media/java/android/media/SessionCommandGroup2.java b/media/java/android/media/SessionCommandGroup2.java
new file mode 100644
index 0000000..399765e
--- /dev/null
+++ b/media/java/android/media/SessionCommandGroup2.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 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.media;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.media.update.ApiLoader;
+import android.media.update.MediaSession2Provider;
+import android.os.Bundle;
+
+import java.util.Set;
+
+/**
+ * @hide
+ * Represent set of {@link SessionCommand2}.
+ */
+public final class SessionCommandGroup2 {
+    // TODO(jaewan): Rename and move provider
+    private final MediaSession2Provider.CommandGroupProvider mProvider;
+
+    public SessionCommandGroup2() {
+        mProvider = ApiLoader.getProvider().createMediaSession2CommandGroup(this, null);
+    }
+
+    public SessionCommandGroup2(@Nullable SessionCommandGroup2 others) {
+        mProvider = ApiLoader.getProvider().createMediaSession2CommandGroup(this, others);
+    }
+
+    /**
+     * @hide
+     */
+    public SessionCommandGroup2(@NonNull MediaSession2Provider.CommandGroupProvider provider) {
+        mProvider = provider;
+    }
+
+    public void addCommand(@NonNull SessionCommand2 command) {
+        mProvider.addCommand_impl(command);
+    }
+
+    public void addCommand(int commandCode) {
+        // TODO(jaewna): Implement
+    }
+
+    public void addAllPredefinedCommands() {
+        mProvider.addAllPredefinedCommands_impl();
+    }
+
+    public void removeCommand(@NonNull SessionCommand2 command) {
+        mProvider.removeCommand_impl(command);
+    }
+
+    public void removeCommand(int commandCode) {
+        // TODO(jaewan): Implement.
+    }
+
+    public boolean hasCommand(@NonNull SessionCommand2 command) {
+        return mProvider.hasCommand_impl(command);
+    }
+
+    public boolean hasCommand(int code) {
+        return mProvider.hasCommand_impl(code);
+    }
+
+    public @NonNull
+    Set<SessionCommand2> getCommands() {
+        return mProvider.getCommands_impl();
+    }
+
+    /**
+     * @hide
+     */
+    public @NonNull MediaSession2Provider.CommandGroupProvider getProvider() {
+        return mProvider;
+    }
+
+    /**
+     * @return new bundle from the CommandGroup
+     * @hide
+     */
+    public @NonNull Bundle toBundle() {
+        return mProvider.toBundle_impl();
+    }
+
+    /**
+     * @return new instance of CommandGroup from the bundle
+     * @hide
+     */
+    public static @Nullable SessionCommandGroup2 fromBundle(Bundle commands) {
+        return ApiLoader.getProvider().fromBundle_MediaSession2CommandGroup(commands);
+    }
+}
diff --git a/media/java/android/media/SessionToken2.java b/media/java/android/media/SessionToken2.java
index f088be3..bf2d445 100644
--- a/media/java/android/media/SessionToken2.java
+++ b/media/java/android/media/SessionToken2.java
@@ -150,8 +150,8 @@
      * @param bundle
      * @return
      */
-    public static SessionToken2 fromBundle(@NonNull Context context, @NonNull Bundle bundle) {
-        return ApiLoader.getProvider().fromBundle_SessionToken2(context, bundle);
+    public static SessionToken2 fromBundle(@NonNull Bundle bundle) {
+        return ApiLoader.getProvider().fromBundle_SessionToken2(bundle);
     }
 
     /**
diff --git a/media/java/android/media/VolumeProvider2.java b/media/java/android/media/VolumeProvider2.java
index 2d96d096..1a4608f 100644
--- a/media/java/android/media/VolumeProvider2.java
+++ b/media/java/android/media/VolumeProvider2.java
@@ -18,7 +18,6 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.content.Context;
 import android.media.update.ApiLoader;
 import android.media.update.VolumeProvider2Provider;
 
@@ -75,10 +74,9 @@
      * @param maxVolume The maximum allowed volume.
      * @param currentVolume The current volume on the output.
      */
-    public VolumeProvider2(@NonNull Context context, @ControlType int controlType,
-            int maxVolume, int currentVolume) {
+    public VolumeProvider2(@ControlType int controlType, int maxVolume, int currentVolume) {
         mProvider = ApiLoader.getProvider().createVolumeProvider2(
-                context, this, controlType, maxVolume, currentVolume);
+                this, controlType, maxVolume, currentVolume);
     }
 
     /**
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index b7f4998..3b12fca 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -407,7 +407,7 @@
             List<Bundle> bundles = mService.getSessionTokens(
                     /* activeSessionOnly */ true, /* sessionServiceOnly */ false,
                     mContext.getPackageName());
-            return toTokenList(mContext, bundles);
+            return toTokenList(bundles);
         } catch (RemoteException e) {
             Log.wtf(TAG, "Cannot communicate with the service.", e);
             return Collections.emptyList();
@@ -430,7 +430,7 @@
             List<Bundle> bundles = mService.getSessionTokens(
                     /* activeSessionOnly */ false, /* sessionServiceOnly */ true,
                     mContext.getPackageName());
-            return toTokenList(mContext, bundles);
+            return toTokenList(bundles);
         } catch (RemoteException e) {
             Log.wtf(TAG, "Cannot communicate with the service.", e);
             return Collections.emptyList();
@@ -455,7 +455,7 @@
             List<Bundle> bundles = mService.getSessionTokens(
                     /* activeSessionOnly */ false, /* sessionServiceOnly */ false,
                     mContext.getPackageName());
-            return toTokenList(mContext, bundles);
+            return toTokenList(bundles);
         } catch (RemoteException e) {
             Log.wtf(TAG, "Cannot communicate with the service.", e);
             return Collections.emptyList();
@@ -540,11 +540,11 @@
         }
     }
 
-    private static List<SessionToken2> toTokenList(Context context, List<Bundle> bundles) {
+    private static List<SessionToken2> toTokenList(List<Bundle> bundles) {
         List<SessionToken2> tokens = new ArrayList<>();
         if (bundles != null) {
             for (int i = 0; i < bundles.size(); i++) {
-                SessionToken2 token = SessionToken2.fromBundle(context, bundles.get(i));
+                SessionToken2 token = SessionToken2.fromBundle(bundles.get(i));
                 if (token != null) {
                     tokens.add(token);
                 }
@@ -829,7 +829,7 @@
                         final Context context = mContext;
                         final OnSessionTokensChangedListener listener = mListener;
                         if (context != null && listener != null) {
-                            listener.onSessionTokensChanged(toTokenList(context, bundles));
+                            listener.onSessionTokensChanged(toTokenList(bundles));
                         }
                     });
                 }
diff --git a/media/java/android/media/update/MediaController2Provider.java b/media/java/android/media/update/MediaController2Provider.java
index 213897d..7234f7b 100644
--- a/media/java/android/media/update/MediaController2Provider.java
+++ b/media/java/android/media/update/MediaController2Provider.java
@@ -21,7 +21,7 @@
 import android.media.MediaController2.PlaybackInfo;
 import android.media.MediaItem2;
 import android.media.MediaMetadata2;
-import android.media.MediaSession2.Command;
+import android.media.SessionCommand2;
 import android.media.Rating2;
 import android.media.SessionToken2;
 import android.net.Uri;
@@ -52,9 +52,11 @@
     void playFromSearch_impl(String query, Bundle extras);
     void playFromUri_impl(Uri uri, Bundle extras);
     void playFromMediaId_impl(String mediaId, Bundle extras);
+    void fastForward_impl();
+    void rewind_impl();
 
     void setRating_impl(String mediaId, Rating2 rating);
-    void sendCustomCommand_impl(Command command, Bundle args, ResultReceiver cb);
+    void sendCustomCommand_impl(SessionCommand2 command, Bundle args, ResultReceiver cb);
     List<MediaItem2> getPlaylist_impl();
     void setPlaylist_impl(List<MediaItem2> list, MediaMetadata2 metadata);
     MediaMetadata2 getPlaylistMetadata_impl();
diff --git a/media/java/android/media/update/MediaSession2Provider.java b/media/java/android/media/update/MediaSession2Provider.java
index 5a1db3e..4751348 100644
--- a/media/java/android/media/update/MediaSession2Provider.java
+++ b/media/java/android/media/update/MediaSession2Provider.java
@@ -23,10 +23,10 @@
 import android.media.MediaPlayerBase;
 import android.media.MediaPlaylistAgent;
 import android.media.MediaSession2;
-import android.media.MediaSession2.Command;
+import android.media.SessionCommand2;
 import android.media.MediaSession2.CommandButton;
 import android.media.MediaSession2.CommandButton.Builder;
-import android.media.MediaSession2.CommandGroup;
+import android.media.SessionCommandGroup2;
 import android.media.MediaSession2.ControllerInfo;
 import android.media.MediaSession2.OnDataSourceMissingHelper;
 import android.media.MediaSession2.SessionCallback;
@@ -55,10 +55,10 @@
     List<ControllerInfo> getConnectedControllers_impl();
     void setCustomLayout_impl(ControllerInfo controller, List<CommandButton> layout);
     void setAudioFocusRequest_impl(AudioFocusRequest afr);
-    void setAllowedCommands_impl(ControllerInfo controller, CommandGroup commands);
-    void sendCustomCommand_impl(ControllerInfo controller, Command command, Bundle args,
+    void setAllowedCommands_impl(ControllerInfo controller, SessionCommandGroup2 commands);
+    void sendCustomCommand_impl(ControllerInfo controller, SessionCommand2 command, Bundle args,
             ResultReceiver receiver);
-    void sendCustomCommand_impl(Command command, Bundle args);
+    void sendCustomCommand_impl(SessionCommand2 command, Bundle args);
     void addPlaylistItem_impl(int index, MediaItem2 item);
     void removePlaylistItem_impl(MediaItem2 item);
     void replacePlaylistItem_impl(int index, MediaItem2 item);
@@ -72,6 +72,7 @@
     void setOnDataSourceMissingHelper_impl(OnDataSourceMissingHelper helper);
     void clearOnDataSourceMissingHelper_impl();
 
+    // TODO(jaewan): Rename and move provider
     interface CommandProvider {
         int getCommandCode_impl();
         String getCustomCommand_impl();
@@ -82,25 +83,26 @@
         int hashCode_impl();
     }
 
+    // TODO(jaewan): Rename and move provider
     interface CommandGroupProvider {
-        void addCommand_impl(Command command);
+        void addCommand_impl(SessionCommand2 command);
         void addAllPredefinedCommands_impl();
-        void removeCommand_impl(Command command);
-        boolean hasCommand_impl(Command command);
+        void removeCommand_impl(SessionCommand2 command);
+        boolean hasCommand_impl(SessionCommand2 command);
         boolean hasCommand_impl(int code);
-        Set<Command> getCommands_impl();
+        Set<SessionCommand2> getCommands_impl();
         Bundle toBundle_impl();
     }
 
     interface CommandButtonProvider {
-        Command getCommand_impl();
+        SessionCommand2 getCommand_impl();
         int getIconResId_impl();
         String getDisplayName_impl();
         Bundle getExtras_impl();
         boolean isEnabled_impl();
 
         interface BuilderProvider {
-            Builder setCommand_impl(Command command);
+            Builder setCommand_impl(SessionCommand2 command);
             Builder setIconResId_impl(int resId);
             Builder setDisplayName_impl(String displayName);
             Builder setEnabled_impl(boolean enabled);
diff --git a/media/java/android/media/update/StaticProvider.java b/media/java/android/media/update/StaticProvider.java
index 1c0e255..8687b80 100644
--- a/media/java/android/media/update/StaticProvider.java
+++ b/media/java/android/media/update/StaticProvider.java
@@ -35,6 +35,8 @@
 import android.media.MediaSessionService2;
 import android.media.MediaSessionService2.MediaNotification;
 import android.media.Rating2;
+import android.media.SessionCommand2;
+import android.media.SessionCommandGroup2;
 import android.media.SessionToken2;
 import android.media.VolumeProvider2;
 import android.media.update.MediaLibraryService2Provider.LibraryRootProvider;
@@ -67,16 +69,16 @@
             ViewGroupProvider superProvider, ViewGroupProvider privateProvider,
             @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes);
 
-    CommandProvider createMediaSession2Command(MediaSession2.Command instance,
+    CommandProvider createMediaSession2Command(SessionCommand2 instance,
             int commandCode, String action, Bundle extra);
-    MediaSession2.Command fromBundle_MediaSession2Command(Context context, Bundle bundle);
-    CommandGroupProvider createMediaSession2CommandGroup(Context context,
-            MediaSession2.CommandGroup instance, MediaSession2.CommandGroup others);
-    MediaSession2.CommandGroup fromBundle_MediaSession2CommandGroup(Context context, Bundle bundle);
+    SessionCommand2 fromBundle_MediaSession2Command(Bundle bundle);
+    CommandGroupProvider createMediaSession2CommandGroup(SessionCommandGroup2 instance,
+            SessionCommandGroup2 others);
+    SessionCommandGroup2 fromBundle_MediaSession2CommandGroup(Bundle bundle);
     ControllerInfoProvider createMediaSession2ControllerInfo(Context context,
             MediaSession2.ControllerInfo instance, int uid, int pid,
             String packageName, IInterface callback);
-    CommandButtonProvider.BuilderProvider createMediaSession2CommandButtonBuilder(Context context,
+    CommandButtonProvider.BuilderProvider createMediaSession2CommandButtonBuilder(
             MediaSession2.CommandButton.Builder instance);
     BuilderBaseProvider<MediaSession2, SessionCallback> createMediaSession2Builder(
             Context context, MediaSession2.Builder instance);
@@ -88,7 +90,7 @@
             SessionToken2 token, Executor executor, BrowserCallback callback);
 
     MediaSessionService2Provider createMediaSessionService2(MediaSessionService2 instance);
-    MediaNotificationProvider createMediaSessionService2MediaNotification(Context context,
+    MediaNotificationProvider createMediaSessionService2MediaNotification(
             MediaNotification mediaNotification, int notificationId, Notification notification);
 
     MediaSessionService2Provider createMediaLibraryService2(MediaLibraryService2 instance);
@@ -96,33 +98,32 @@
         createMediaLibraryService2Builder(
             MediaLibraryService2 service, MediaLibrarySession.Builder instance,
             Executor callbackExecutor, MediaLibrarySessionCallback callback);
-    LibraryRootProvider createMediaLibraryService2LibraryRoot(Context context, LibraryRoot instance,
-            String rootId, Bundle extras);
+    LibraryRootProvider createMediaLibraryService2LibraryRoot(LibraryRoot instance, String rootId,
+            Bundle extras);
 
     SessionToken2Provider createSessionToken2(Context context, SessionToken2 instance,
             String packageName, String serviceName, int uid);
-    SessionToken2 fromBundle_SessionToken2(Context context, Bundle bundle);
+    SessionToken2 fromBundle_SessionToken2(Bundle bundle);
 
-    MediaItem2Provider.BuilderProvider createMediaItem2Builder(
-            Context context, MediaItem2.Builder instance, int flags);
-    MediaItem2 fromBundle_MediaItem2(Context context, Bundle bundle);
+    MediaItem2Provider.BuilderProvider createMediaItem2Builder(MediaItem2.Builder instance,
+            int flags);
+    MediaItem2 fromBundle_MediaItem2(Bundle bundle);
 
-    VolumeProvider2Provider createVolumeProvider2(Context context, VolumeProvider2 instance,
-            int controlType, int maxVolume, int currentVolume);
+    VolumeProvider2Provider createVolumeProvider2(VolumeProvider2 instance, int controlType,
+            int maxVolume, int currentVolume);
 
-    MediaMetadata2 fromBundle_MediaMetadata2(Context context, Bundle bundle);
+    MediaMetadata2 fromBundle_MediaMetadata2(Bundle bundle);
     MediaMetadata2Provider.BuilderProvider createMediaMetadata2Builder(
-            Context context, MediaMetadata2.Builder instance);
+            MediaMetadata2.Builder instance);
     MediaMetadata2Provider.BuilderProvider createMediaMetadata2Builder(
-            Context context, MediaMetadata2.Builder instance, MediaMetadata2 source);
+            MediaMetadata2.Builder instance, MediaMetadata2 source);
 
-    Rating2 newUnratedRating_Rating2(Context context, int ratingStyle);
-    Rating2 fromBundle_Rating2(Context context, Bundle bundle);
-    Rating2 newHeartRating_Rating2(Context context, boolean hasHeart);
-    Rating2 newThumbRating_Rating2(Context context, boolean thumbIsUp);
-    Rating2 newStarRating_Rating2(Context context, int starRatingStyle, float starRating);
-    Rating2 newPercentageRating_Rating2(Context context, float percent);
+    Rating2 newUnratedRating_Rating2(int ratingStyle);
+    Rating2 fromBundle_Rating2(Bundle bundle);
+    Rating2 newHeartRating_Rating2(boolean hasHeart);
+    Rating2 newThumbRating_Rating2(boolean thumbIsUp);
+    Rating2 newStarRating_Rating2(int starRatingStyle, float starRating);
+    Rating2 newPercentageRating_Rating2(float percent);
 
-    MediaPlaylistAgentProvider createMediaPlaylistAgent(Context context,
-            MediaPlaylistAgent instance);
+    MediaPlaylistAgentProvider createMediaPlaylistAgent(MediaPlaylistAgent instance);
 }
diff --git a/media/java/android/media/update/TransportControlProvider.java b/media/java/android/media/update/TransportControlProvider.java
index 03944d2..d89a88a 100644
--- a/media/java/android/media/update/TransportControlProvider.java
+++ b/media/java/android/media/update/TransportControlProvider.java
@@ -29,8 +29,6 @@
     void skipToNextItem_impl();
 
     void prepare_impl();
-    void fastForward_impl();
-    void rewind_impl();
     void seekTo_impl(long pos);
     void skipToPlaylistItem_impl(MediaItem2 item);
 
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 32a00d5..1244d7f 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -243,11 +243,11 @@
         }
     };
 
-    public MtpDatabase(Context context, Context userContext, String volumeName,
+    public MtpDatabase(Context context, String volumeName,
             String[] subDirectories) {
         native_setup();
         mContext = context;
-        mMediaProvider = userContext.getContentResolver()
+        mMediaProvider = context.getContentResolver()
                 .acquireContentProviderClient(MediaStore.AUTHORITY);
         mVolumeName = volumeName;
         mObjectsUri = Files.getMtpObjectsUri(volumeName);
diff --git a/media/java/android/mtp/MtpServer.java b/media/java/android/mtp/MtpServer.java
index f2b1106..8af5ff7 100644
--- a/media/java/android/mtp/MtpServer.java
+++ b/media/java/android/mtp/MtpServer.java
@@ -18,6 +18,8 @@
 
 import com.android.internal.util.Preconditions;
 
+import java.io.FileDescriptor;
+
 /**
  * Java wrapper for MTP/PTP support as USB responder.
  * {@hide}
@@ -34,6 +36,7 @@
 
     public MtpServer(
             MtpDatabase database,
+            FileDescriptor controlFd,
             boolean usePtp,
             Runnable onTerminate,
             String deviceInfoManufacturer,
@@ -44,6 +47,7 @@
         mOnTerminate = Preconditions.checkNotNull(onTerminate);
         native_setup(
                 database,
+                controlFd,
                 usePtp,
                 deviceInfoManufacturer,
                 deviceInfoModel,
@@ -92,6 +96,7 @@
     public static native final void native_configure(boolean usePtp);
     private native final void native_setup(
             MtpDatabase database,
+            FileDescriptor controlFd,
             boolean usePtp,
             String deviceInfoManufacturer,
             String deviceInfoModel,
diff --git a/media/jni/android_mtp_MtpServer.cpp b/media/jni/android_mtp_MtpServer.cpp
index c76cebe..8730e06 100644
--- a/media/jni/android_mtp_MtpServer.cpp
+++ b/media/jni/android_mtp_MtpServer.cpp
@@ -55,22 +55,17 @@
     return (MtpServer*)env->GetLongField(thiz, field_MtpServer_nativeContext);
 }
 
-static void android_mtp_configure(JNIEnv *, jobject, jboolean usePtp) {
-    MtpServer::configure(usePtp);
-}
-
 static void
-android_mtp_MtpServer_setup(JNIEnv *env, jobject thiz, jobject javaDatabase, jboolean usePtp,
-        jstring deviceInfoManufacturer,
-        jstring deviceInfoModel,
-        jstring deviceInfoDeviceVersion,
-        jstring deviceInfoSerialNumber)
+android_mtp_MtpServer_setup(JNIEnv *env, jobject thiz, jobject javaDatabase, jobject jControlFd,
+        jboolean usePtp, jstring deviceInfoManufacturer, jstring deviceInfoModel,
+        jstring deviceInfoDeviceVersion, jstring deviceInfoSerialNumber)
 {
     const char *deviceInfoManufacturerStr = env->GetStringUTFChars(deviceInfoManufacturer, NULL);
     const char *deviceInfoModelStr = env->GetStringUTFChars(deviceInfoModel, NULL);
     const char *deviceInfoDeviceVersionStr = env->GetStringUTFChars(deviceInfoDeviceVersion, NULL);
     const char *deviceInfoSerialNumberStr = env->GetStringUTFChars(deviceInfoSerialNumber, NULL);
-    MtpServer* server = new MtpServer(getMtpDatabase(env, javaDatabase),
+    int controlFd = dup(jniGetFDFromFileDescriptor(env, jControlFd));
+    MtpServer* server = new MtpServer(getMtpDatabase(env, javaDatabase), controlFd,
             usePtp,
             MtpString((deviceInfoManufacturerStr != NULL) ? deviceInfoManufacturerStr : ""),
             MtpString((deviceInfoModelStr != NULL) ? deviceInfoModelStr : ""),
@@ -201,8 +196,7 @@
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod gMethods[] = {
-    {"native_configure",              "(Z)V",  (void *)android_mtp_configure},
-    {"native_setup",                "(Landroid/mtp/MtpDatabase;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
+    {"native_setup",                "(Landroid/mtp/MtpDatabase;Ljava/io/FileDescriptor;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
                                             (void *)android_mtp_MtpServer_setup},
     {"native_run",                  "()V",  (void *)android_mtp_MtpServer_run},
     {"native_cleanup",              "()V",  (void *)android_mtp_MtpServer_cleanup},
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index 4db0034..7828c4c 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -42,6 +42,7 @@
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
+import android.webkit.CookieManager;
 import android.webkit.SslErrorHandler;
 import android.webkit.WebChromeClient;
 import android.webkit.WebSettings;
@@ -147,6 +148,7 @@
 
         final WebView webview = getWebview();
         webview.clearCache(true);
+        CookieManager.getInstance().setAcceptThirdPartyCookies(webview, true);
         WebSettings webSettings = webview.getSettings();
         webSettings.setJavaScriptEnabled(true);
         webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 24a6804..584fc34 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -97,6 +97,12 @@
     <!-- Summary for Connected wifi network without internet -->
     <string name="wifi_connected_no_internet">Connected, no internet</string>
 
+    <!-- Wi-Fi status indicating that the current network is connected, but has no internet access. -->
+    <string name="wifi_status_no_internet">No internet</string>
+
+    <!-- Wi-Fi status indicating that the current network is connected requires sign in to access the internet. -->
+    <string name="wifi_status_sign_in_required">Sign in required</string>
+
     <!-- Summary for networks failing to connect due to association rejection status 17, AP full -->
     <string name="wifi_ap_unable_to_handle_new_sta">Access point temporarily full</string>
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index c5c1169..78045f9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -1154,7 +1154,7 @@
 
     @Nullable
     @Speed
-    private int roundToClosestSpeedEnum(int speed) {
+    private static int roundToClosestSpeedEnum(int speed) {
         if (speed < Speed.SLOW) {
             return Speed.NONE;
         } else if (speed < (Speed.SLOW + Speed.MODERATE) / 2) {
@@ -1170,21 +1170,31 @@
 
     @Nullable
     String getSpeedLabel(@Speed int speed) {
+        return getSpeedLabel(mContext, speed);
+    }
+
+    private static String getSpeedLabel(Context context, int speed) {
         switch (speed) {
             case Speed.VERY_FAST:
-                return mContext.getString(R.string.speed_label_very_fast);
+                return context.getString(R.string.speed_label_very_fast);
             case Speed.FAST:
-                return mContext.getString(R.string.speed_label_fast);
+                return context.getString(R.string.speed_label_fast);
             case Speed.MODERATE:
-                return mContext.getString(R.string.speed_label_okay);
+                return context.getString(R.string.speed_label_okay);
             case Speed.SLOW:
-                return mContext.getString(R.string.speed_label_slow);
+                return context.getString(R.string.speed_label_slow);
             case Speed.NONE:
             default:
                 return null;
         }
     }
 
+    /** Return the speed label for a {@link ScoredNetwork} at the specified {@code rssi} level. */
+    @Nullable
+    public static String getSpeedLabel(Context context, ScoredNetwork scoredNetwork, int rssi) {
+        return getSpeedLabel(context, roundToClosestSpeedEnum(scoredNetwork.calculateBadge(rssi)));
+    }
+
     /** Return true if the current RSSI is reachable, and false otherwise. */
     public boolean isReachable() {
         return mRssi != UNREACHABLE_RSSI;
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index 6e12e20..4cd23f9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -10,28 +10,90 @@
 
 package com.android.settingslib.wifi;
 
+import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+
+import android.content.Context;
 import android.content.Intent;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
+import android.net.NetworkKey;
+import android.net.NetworkRequest;
+import android.net.NetworkScoreManager;
+import android.net.ScoredNetwork;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
+import android.net.wifi.WifiNetworkScoreCache;
 import android.net.wifi.WifiSsid;
+import android.os.Handler;
+import android.os.Looper;
+
+import com.android.settingslib.R;
 
 import java.util.List;
 
-public class WifiStatusTracker {
-
+public class WifiStatusTracker extends ConnectivityManager.NetworkCallback {
+    private final Context mContext;
+    private final WifiNetworkScoreCache mWifiNetworkScoreCache;
     private final WifiManager mWifiManager;
+    private final NetworkScoreManager mNetworkScoreManager;
+    private final ConnectivityManager mConnectivityManager;
+    private final WifiNetworkScoreCache.CacheListener mCacheListener =
+            new WifiNetworkScoreCache.CacheListener(new Handler(Looper.getMainLooper())) {
+                @Override
+                public void networkCacheUpdated(List<ScoredNetwork> updatedNetworks) {
+                    updateStatusLabel();
+                    mCallback.run();
+                }
+            };
+    private final NetworkRequest mNetworkRequest = new NetworkRequest.Builder()
+            .clearCapabilities().addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build();
+    private final ConnectivityManager.NetworkCallback mNetworkCallback = new ConnectivityManager
+            .NetworkCallback() {
+        @Override
+        public void onCapabilitiesChanged(
+                Network network, NetworkCapabilities networkCapabilities) {
+            updateStatusLabel();
+            mCallback.run();
+        }
+    };
+    private final Runnable mCallback;
+
+    private WifiInfo mWifiInfo;
     public boolean enabled;
     public int state;
     public boolean connected;
-    public boolean connecting;
     public String ssid;
     public int rssi;
     public int level;
+    public String statusLabel;
 
-    public WifiStatusTracker(WifiManager wifiManager) {
+    public WifiStatusTracker(Context context, WifiManager wifiManager,
+            NetworkScoreManager networkScoreManager, ConnectivityManager connectivityManager,
+            Runnable callback) {
+        mContext = context;
         mWifiManager = wifiManager;
+        mWifiNetworkScoreCache = new WifiNetworkScoreCache(context);
+        mNetworkScoreManager = networkScoreManager;
+        mConnectivityManager = connectivityManager;
+        mCallback = callback;
+    }
+
+    public void setListening(boolean listening) {
+        if (listening) {
+            mNetworkScoreManager.registerNetworkScoreCache(NetworkKey.TYPE_WIFI,
+                    mWifiNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_CURRENT_NETWORK);
+            mWifiNetworkScoreCache.registerListener(mCacheListener);
+            mConnectivityManager.registerNetworkCallback(mNetworkRequest, mNetworkCallback);
+        } else {
+            mNetworkScoreManager.unregisterNetworkScoreCache(NetworkKey.TYPE_WIFI,
+                    mWifiNetworkScoreCache);
+            mWifiNetworkScoreCache.unregisterListener();
+            mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
+        }
     }
 
     public void handleBroadcast(Intent intent) {
@@ -40,34 +102,59 @@
             state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
                     WifiManager.WIFI_STATE_UNKNOWN);
             enabled = state == WifiManager.WIFI_STATE_ENABLED;
-
-
-            enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
-                    WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
         } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
-            final NetworkInfo networkInfo = (NetworkInfo)
+            final NetworkInfo networkInfo =
                     intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
-            connecting = networkInfo != null && !networkInfo.isConnected()
-                    && networkInfo.isConnectedOrConnecting();
             connected = networkInfo != null && networkInfo.isConnected();
-            // If Connected grab the signal strength and ssid.
+            mWifiInfo = null;
+            ssid = null;
             if (connected) {
-                WifiInfo info = mWifiManager.getConnectionInfo();
-                if (info != null) {
-                    ssid = getValidSsid(info);
-                } else {
-                    ssid = null;
+                mWifiInfo = mWifiManager.getConnectionInfo();
+                if (mWifiInfo != null) {
+                    ssid = getValidSsid(mWifiInfo);
+                    updateRssi(mWifiInfo.getRssi());
+                    maybeRequestNetworkScore();
                 }
-            } else if (!connected) {
-                ssid = null;
             }
+            updateStatusLabel();
         } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
             // Default to -200 as its below WifiManager.MIN_RSSI.
-            rssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
-            level = WifiManager.calculateSignalLevel(rssi, 5);
+            updateRssi(intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200));
+            updateStatusLabel();
         }
     }
 
+    private void updateRssi(int newRssi) {
+        rssi = newRssi;
+        level = WifiManager.calculateSignalLevel(rssi, WifiManager.RSSI_LEVELS);
+    }
+
+    private void maybeRequestNetworkScore() {
+        NetworkKey networkKey = NetworkKey.createFromWifiInfo(mWifiInfo);
+        if (mWifiNetworkScoreCache.getScoredNetwork(networkKey) == null) {
+            mNetworkScoreManager.requestScores(new NetworkKey[]{ networkKey });
+        }
+    }
+
+    private void updateStatusLabel() {
+        final NetworkCapabilities networkCapabilities
+                = mConnectivityManager.getNetworkCapabilities(mWifiManager.getCurrentNetwork());
+        if (networkCapabilities != null) {
+            if (networkCapabilities.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)) {
+                statusLabel = mContext.getString(R.string.wifi_status_sign_in_required);
+                return;
+            } else if (!networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
+                statusLabel = mContext.getString(R.string.wifi_status_no_internet);
+                return;
+            }
+        }
+
+        ScoredNetwork scoredNetwork =
+                mWifiNetworkScoreCache.getScoredNetwork(NetworkKey.createFromWifiInfo(mWifiInfo));
+        statusLabel = scoredNetwork == null
+                ? null : AccessPoint.getSpeedLabel(mContext, scoredNetwork, rssi);
+    }
+
     private String getValidSsid(WifiInfo info) {
         String ssid = info.getSSID();
         if (ssid != null && !WifiSsid.NONE.equals(ssid)) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 2047f58..6d9da9b 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -85,22 +85,23 @@
     private static void dumpProtoGlobalSettingsLocked(
             @NonNull ProtoOutputStream p, long fieldId, @NonNull SettingsState s) {
         final long token = p.start(fieldId);
-
         s.dumpHistoricalOperations(p, GlobalSettingsProto.HISTORICAL_OPERATIONS);
 
-        // This uses the same order as in Settings.Global.
+        // This uses the same order as in GlobalSettingsProto.
+        dumpSetting(s, p,
+                Settings.Global.ACTIVITY_MANAGER_CONSTANTS,
+                GlobalSettingsProto.ACTIVITY_MANAGER_CONSTANTS);
+        dumpSetting(s, p,
+                Settings.Global.ADB_ENABLED,
+                GlobalSettingsProto.ADB_ENABLED);
         dumpSetting(s, p,
                 Settings.Global.ADD_USERS_WHEN_LOCKED,
                 GlobalSettingsProto.ADD_USERS_WHEN_LOCKED);
-        dumpSetting(s, p,
-                Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED,
-                GlobalSettingsProto.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED);
+
+        final long airplaneModeToken = p.start(GlobalSettingsProto.AIRPLANE_MODE);
         dumpSetting(s, p,
                 Settings.Global.AIRPLANE_MODE_ON,
-                GlobalSettingsProto.AIRPLANE_MODE_ON);
-        dumpSetting(s, p,
-                Settings.Global.THEATER_MODE_ON,
-                GlobalSettingsProto.THEATER_MODE_ON);
+                GlobalSettingsProto.AirplaneMode.ON);
         // RADIO_BLUETOOTH is just a constant and not an actual setting.
         // RADIO_WIFI is just a constant and not an actual setting.
         // RADIO_WIMAX is just a constant and not an actual setting.
@@ -108,352 +109,1186 @@
         // RADIO_NFC is just a constant and not an actual setting.
         dumpSetting(s, p,
                 Settings.Global.AIRPLANE_MODE_RADIOS,
-                GlobalSettingsProto.AIRPLANE_MODE_RADIOS);
+                GlobalSettingsProto.AirplaneMode.RADIOS);
         dumpSetting(s, p,
                 Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS,
-                GlobalSettingsProto.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
+                GlobalSettingsProto.AirplaneMode.TOGGLEABLE_RADIOS);
+        p.end(airplaneModeToken);
+
         dumpSetting(s, p,
-                Settings.Global.BLUETOOTH_CLASS_OF_DEVICE,
-                GlobalSettingsProto.BLUETOOTH_CLASS_OF_DEVICE);
+                Settings.Global.ALARM_MANAGER_CONSTANTS,
+                GlobalSettingsProto.ALARM_MANAGER_CONSTANTS);
         dumpSetting(s, p,
-                Settings.Global.BLUETOOTH_DISABLED_PROFILES,
-                GlobalSettingsProto.BLUETOOTH_DISABLED_PROFILES);
+                Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED,
+                GlobalSettingsProto.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED);
         dumpSetting(s, p,
-                Settings.Global.BLUETOOTH_INTEROPERABILITY_LIST,
-                GlobalSettingsProto.BLUETOOTH_INTEROPERABILITY_LIST);
+                Settings.Global.ALWAYS_ON_DISPLAY_CONSTANTS,
+                GlobalSettingsProto.ALWAYS_ON_DISPLAY_CONSTANTS);
         dumpSetting(s, p,
-                Settings.Global.WIFI_SLEEP_POLICY,
-                GlobalSettingsProto.WIFI_SLEEP_POLICY);
+                Settings.Global.ALWAYS_FINISH_ACTIVITIES,
+                GlobalSettingsProto.ALWAYS_FINISH_ACTIVITIES);
         dumpSetting(s, p,
-                Settings.Global.AUTO_TIME,
-                GlobalSettingsProto.AUTO_TIME);
+                Settings.Global.ANIMATOR_DURATION_SCALE,
+                GlobalSettingsProto.ANIMATOR_DURATION_SCALE);
+
+        final long anomalyToken = p.start(GlobalSettingsProto.ANOMALY);
         dumpSetting(s, p,
-                Settings.Global.AUTO_TIME_ZONE,
-                GlobalSettingsProto.AUTO_TIME_ZONE);
+                Settings.Global.ANOMALY_DETECTION_CONSTANTS,
+                GlobalSettingsProto.Anomaly.DETECTION_CONSTANTS);
         dumpSetting(s, p,
-                Settings.Global.CAR_DOCK_SOUND,
-                GlobalSettingsProto.CAR_DOCK_SOUND);
+                Settings.Global.ANOMALY_CONFIG_VERSION,
+                GlobalSettingsProto.Anomaly.CONFIG_VERSION);
         dumpSetting(s, p,
-                Settings.Global.CAR_UNDOCK_SOUND,
-                GlobalSettingsProto.CAR_UNDOCK_SOUND);
+                Settings.Global.ANOMALY_CONFIG,
+                GlobalSettingsProto.Anomaly.CONFIG);
+        p.end(anomalyToken);
+
+        final long apnDbToken = p.start(GlobalSettingsProto.APN_DB);
         dumpSetting(s, p,
-                Settings.Global.DESK_DOCK_SOUND,
-                GlobalSettingsProto.DESK_DOCK_SOUND);
+                Settings.Global.APN_DB_UPDATE_CONTENT_URL,
+                GlobalSettingsProto.ApnDb.UPDATE_CONTENT_URL);
         dumpSetting(s, p,
-                Settings.Global.DESK_UNDOCK_SOUND,
-                GlobalSettingsProto.DESK_UNDOCK_SOUND);
+                Settings.Global.APN_DB_UPDATE_METADATA_URL,
+                GlobalSettingsProto.ApnDb.UPDATE_METADATA_URL);
+        p.end(apnDbToken);
+
+        final long appToken = p.start(GlobalSettingsProto.APP);
         dumpSetting(s, p,
-                Settings.Global.DOCK_SOUNDS_ENABLED,
-                GlobalSettingsProto.DOCK_SOUNDS_ENABLED);
+                Settings.Global.APP_IDLE_CONSTANTS,
+                GlobalSettingsProto.App.IDLE_CONSTANTS);
         dumpSetting(s, p,
-                Settings.Global.DOCK_SOUNDS_ENABLED_WHEN_ACCESSIBILITY,
-                GlobalSettingsProto.DOCK_SOUNDS_ENABLED_WHEN_ACCESSIBILITY);
+                Settings.Global.APP_STANDBY_ENABLED,
+                GlobalSettingsProto.App.STANDBY_ENABLED);
         dumpSetting(s, p,
-                Settings.Global.LOCK_SOUND,
-                GlobalSettingsProto.LOCK_SOUND);
+                Settings.Global.APP_AUTO_RESTRICTION_ENABLED,
+                GlobalSettingsProto.App.AUTO_RESTRICTION_ENABLED);
         dumpSetting(s, p,
-                Settings.Global.UNLOCK_SOUND,
-                GlobalSettingsProto.UNLOCK_SOUND);
+                Settings.Global.FORCED_APP_STANDBY_ENABLED,
+                GlobalSettingsProto.App.FORCED_APP_STANDBY_ENABLED);
         dumpSetting(s, p,
-                Settings.Global.TRUSTED_SOUND,
-                GlobalSettingsProto.TRUSTED_SOUND);
-        dumpSetting(s, p,
-                Settings.Global.LOW_BATTERY_SOUND,
-                GlobalSettingsProto.LOW_BATTERY_SOUND);
-        dumpSetting(s, p,
-                Settings.Global.POWER_SOUNDS_ENABLED,
-                GlobalSettingsProto.POWER_SOUNDS_ENABLED);
-        dumpSetting(s, p,
-                Settings.Global.CHARGING_STARTED_SOUND,
-                GlobalSettingsProto.WIRELESS_CHARGING_STARTED_SOUND);
-        dumpSetting(s, p,
-                Settings.Global.CHARGING_SOUNDS_ENABLED,
-                GlobalSettingsProto.CHARGING_SOUNDS_ENABLED);
-        dumpSetting(s, p,
-                Settings.Global.STAY_ON_WHILE_PLUGGED_IN,
-                GlobalSettingsProto.STAY_ON_WHILE_PLUGGED_IN);
-        dumpSetting(s, p,
-                Settings.Global.BUGREPORT_IN_POWER_MENU,
-                GlobalSettingsProto.BUGREPORT_IN_POWER_MENU);
-        dumpSetting(s, p,
-                Settings.Global.ADB_ENABLED,
-                GlobalSettingsProto.ADB_ENABLED);
-        dumpSetting(s, p,
-                Settings.Global.DEBUG_VIEW_ATTRIBUTES,
-                GlobalSettingsProto.DEBUG_VIEW_ATTRIBUTES);
+                Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED,
+                GlobalSettingsProto.App.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED);
+        p.end(appToken);
+
         dumpSetting(s, p,
                 Settings.Global.ASSISTED_GPS_ENABLED,
                 GlobalSettingsProto.ASSISTED_GPS_ENABLED);
         dumpSetting(s, p,
+                Settings.Global.AUDIO_SAFE_VOLUME_STATE,
+                GlobalSettingsProto.AUDIO_SAFE_VOLUME_STATE);
+
+        final long autoToken = p.start(GlobalSettingsProto.AUTO);
+        dumpSetting(s, p,
+                Settings.Global.AUTO_TIME,
+                GlobalSettingsProto.Auto.TIME);
+        dumpSetting(s, p,
+                Settings.Global.AUTO_TIME_ZONE,
+                GlobalSettingsProto.Auto.TIME_ZONE);
+        p.end(autoToken);
+
+        dumpSetting(s, p,
+                Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES,
+                GlobalSettingsProto.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES);
+        dumpSetting(s, p,
+                Settings.Global.BACKUP_AGENT_TIMEOUT_PARAMETERS,
+                GlobalSettingsProto.BACKUP_AGENT_TIMEOUT_PARAMETERS);
+
+        final long batteryToken = p.start(GlobalSettingsProto.BATTERY);
+        dumpSetting(s, p,
+                Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD,
+                GlobalSettingsProto.Battery.DISCHARGE_DURATION_THRESHOLD);
+        dumpSetting(s, p,
+                Settings.Global.BATTERY_DISCHARGE_THRESHOLD,
+                GlobalSettingsProto.Battery.DISCHARGE_THRESHOLD);
+        dumpSetting(s, p,
+                Settings.Global.BATTERY_SAVER_CONSTANTS,
+                GlobalSettingsProto.Battery.SAVER_CONSTANTS);
+        dumpSetting(s, p,
+                Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS,
+                GlobalSettingsProto.Battery.SAVER_DEVICE_SPECIFIC_CONSTANTS);
+        dumpSetting(s, p,
+                Settings.Global.BATTERY_STATS_CONSTANTS,
+                GlobalSettingsProto.Battery.STATS_CONSTANTS);
+        dumpSetting(s, p,
+                Settings.Global.BATTERY_TIP_CONSTANTS,
+                GlobalSettingsProto.Battery.TIP_CONSTANTS);
+        p.end(batteryToken);
+
+        final long bleScanToken = p.start(GlobalSettingsProto.BLE_SCAN);
+        dumpSetting(s, p,
+                Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE,
+                GlobalSettingsProto.BleScan.ALWAYS_AVAILABLE);
+        dumpSetting(s, p,
+                Settings.Global.BLE_SCAN_LOW_POWER_WINDOW_MS,
+                GlobalSettingsProto.BleScan.LOW_POWER_WINDOW_MS);
+        dumpSetting(s, p,
+                Settings.Global.BLE_SCAN_BALANCED_WINDOW_MS,
+                GlobalSettingsProto.BleScan.BALANCED_WINDOW_MS);
+        dumpSetting(s, p,
+                Settings.Global.BLE_SCAN_LOW_LATENCY_WINDOW_MS,
+                GlobalSettingsProto.BleScan.LOW_LATENCY_WINDOW_MS);
+        dumpSetting(s, p,
+                Settings.Global.BLE_SCAN_LOW_POWER_INTERVAL_MS,
+                GlobalSettingsProto.BleScan.LOW_POWER_INTERVAL_MS);
+        dumpSetting(s, p,
+                Settings.Global.BLE_SCAN_BALANCED_INTERVAL_MS,
+                GlobalSettingsProto.BleScan.BALANCED_INTERVAL_MS);
+        dumpSetting(s, p,
+                Settings.Global.BLE_SCAN_LOW_LATENCY_INTERVAL_MS,
+                GlobalSettingsProto.BleScan.LOW_LATENCY_INTERVAL_MS);
+        dumpSetting(s, p,
+                Settings.Global.BLE_SCAN_BACKGROUND_MODE,
+                GlobalSettingsProto.BleScan.BACKGROUND_MODE);
+        p.end(bleScanToken);
+
+        final long bluetoothToken = p.start(GlobalSettingsProto.BLUETOOTH);
+        dumpSetting(s, p,
+                Settings.Global.BLUETOOTH_CLASS_OF_DEVICE,
+                GlobalSettingsProto.Bluetooth.CLASS_OF_DEVICE);
+        dumpSetting(s, p,
+                Settings.Global.BLUETOOTH_DISABLED_PROFILES,
+                GlobalSettingsProto.Bluetooth.DISABLED_PROFILES);
+        dumpSetting(s, p,
+                Settings.Global.BLUETOOTH_INTEROPERABILITY_LIST,
+                GlobalSettingsProto.Bluetooth.INTEROPERABILITY_LIST);
+        dumpSetting(s, p,
                 Settings.Global.BLUETOOTH_ON,
-                GlobalSettingsProto.BLUETOOTH_ON);
+                GlobalSettingsProto.Bluetooth.ON);
+        dumpRepeatedSetting(s, p,
+                Settings.Global.BLUETOOTH_HEADSET_PRIORITY_PREFIX,
+                GlobalSettingsProto.Bluetooth.HEADSET_PRIORITIES);
+        dumpRepeatedSetting(s, p,
+                Settings.Global.BLUETOOTH_A2DP_SINK_PRIORITY_PREFIX,
+                GlobalSettingsProto.Bluetooth.A2DP_SINK_PRIORITIES);
+        dumpRepeatedSetting(s, p,
+                Settings.Global.BLUETOOTH_A2DP_SRC_PRIORITY_PREFIX,
+                GlobalSettingsProto.Bluetooth.A2DP_SRC_PRIORITIES);
+        dumpRepeatedSetting(s, p,
+                Settings.Global.BLUETOOTH_A2DP_SUPPORTS_OPTIONAL_CODECS_PREFIX,
+                GlobalSettingsProto.Bluetooth.A2DP_SUPPORTS_OPTIONAL_CODECS);
+        dumpRepeatedSetting(s, p,
+                Settings.Global.BLUETOOTH_A2DP_OPTIONAL_CODECS_ENABLED_PREFIX,
+                GlobalSettingsProto.Bluetooth.A2DP_OPTIONAL_CODECS_ENABLED);
+        dumpRepeatedSetting(s, p,
+                Settings.Global.BLUETOOTH_INPUT_DEVICE_PRIORITY_PREFIX,
+                GlobalSettingsProto.Bluetooth.INPUT_DEVICE_PRIORITIES);
+        dumpRepeatedSetting(s, p,
+                Settings.Global.BLUETOOTH_MAP_PRIORITY_PREFIX,
+                GlobalSettingsProto.Bluetooth.MAP_PRIORITIES);
+        dumpRepeatedSetting(s, p,
+                Settings.Global.BLUETOOTH_MAP_CLIENT_PRIORITY_PREFIX,
+                GlobalSettingsProto.Bluetooth.MAP_CLIENT_PRIORITIES);
+        dumpRepeatedSetting(s, p,
+                Settings.Global.BLUETOOTH_PBAP_CLIENT_PRIORITY_PREFIX,
+                GlobalSettingsProto.Bluetooth.PBAP_CLIENT_PRIORITIES);
+        dumpRepeatedSetting(s, p,
+                Settings.Global.BLUETOOTH_SAP_PRIORITY_PREFIX,
+                GlobalSettingsProto.Bluetooth.SAP_PRIORITIES);
+        dumpRepeatedSetting(s, p,
+                Settings.Global.BLUETOOTH_PAN_PRIORITY_PREFIX,
+                GlobalSettingsProto.Bluetooth.PAN_PRIORITIES);
+        dumpRepeatedSetting(s, p,
+                Settings.Global.BLUETOOTH_HEARING_AID_PRIORITY_PREFIX,
+                GlobalSettingsProto.Bluetooth.HEARING_AID_PRIORITIES);
+        p.end(bluetoothToken);
+
+        dumpSetting(s, p,
+                Settings.Global.BOOT_COUNT,
+                GlobalSettingsProto.BOOT_COUNT);
+        dumpSetting(s, p,
+                Settings.Global.BUGREPORT_IN_POWER_MENU,
+                GlobalSettingsProto.BUGREPORT_IN_POWER_MENU);
+        dumpSetting(s, p,
+                Settings.Global.CALL_AUTO_RETRY,
+                GlobalSettingsProto.CALL_AUTO_RETRY);
+
+        final long captivePortalToken = p.start(GlobalSettingsProto.CAPTIVE_PORTAL);
+        dumpSetting(s, p,
+                Settings.Global.CAPTIVE_PORTAL_MODE,
+                GlobalSettingsProto.CaptivePortal.MODE);
+        dumpSetting(s, p,
+                Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED,
+                GlobalSettingsProto.CaptivePortal.DETECTION_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.CAPTIVE_PORTAL_SERVER,
+                GlobalSettingsProto.CaptivePortal.SERVER);
+        dumpSetting(s, p,
+                Settings.Global.CAPTIVE_PORTAL_HTTPS_URL,
+                GlobalSettingsProto.CaptivePortal.HTTPS_URL);
+        dumpSetting(s, p,
+                Settings.Global.CAPTIVE_PORTAL_HTTP_URL,
+                GlobalSettingsProto.CaptivePortal.HTTP_URL);
+        dumpSetting(s, p,
+                Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL,
+                GlobalSettingsProto.CaptivePortal.FALLBACK_URL);
+        dumpSetting(s, p,
+                Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS,
+                GlobalSettingsProto.CaptivePortal.OTHER_FALLBACK_URLS);
+        dumpSetting(s, p,
+                Settings.Global.CAPTIVE_PORTAL_USE_HTTPS,
+                GlobalSettingsProto.CaptivePortal.USE_HTTPS);
+        dumpSetting(s, p,
+                Settings.Global.CAPTIVE_PORTAL_USER_AGENT,
+                GlobalSettingsProto.CaptivePortal.USER_AGENT);
+        p.end(captivePortalToken);
+
+        final long carrierToken = p.start(GlobalSettingsProto.CARRIER);
+        dumpSetting(s, p,
+                Settings.Global.CARRIER_APP_WHITELIST,
+                GlobalSettingsProto.Carrier.APP_WHITELIST);
+        dumpSetting(s, p,
+                Settings.Global.CARRIER_APP_NAMES,
+                GlobalSettingsProto.Carrier.APP_NAMES);
+        dumpSetting(s, p,
+                Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT,
+                GlobalSettingsProto.Carrier.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT);
+        dumpSetting(s, p,
+                Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS,
+                GlobalSettingsProto.Carrier.INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS);
+        p.end(carrierToken);
+
+        final long cdmaToken = p.start(GlobalSettingsProto.CDMA);
         dumpSetting(s, p,
                 Settings.Global.CDMA_CELL_BROADCAST_SMS,
-                GlobalSettingsProto.CDMA_CELL_BROADCAST_SMS);
+                GlobalSettingsProto.Cdma.CELL_BROADCAST_SMS);
         dumpSetting(s, p,
                 Settings.Global.CDMA_ROAMING_MODE,
-                GlobalSettingsProto.CDMA_ROAMING_MODE);
+                GlobalSettingsProto.Cdma.ROAMING_MODE);
         dumpSetting(s, p,
                 Settings.Global.CDMA_SUBSCRIPTION_MODE,
-                GlobalSettingsProto.CDMA_SUBSCRIPTION_MODE);
+                GlobalSettingsProto.Cdma.SUBSCRIPTION_MODE);
+        p.end(cdmaToken);
+
+        dumpSetting(s, p,
+                Settings.Global.CELL_ON,
+                GlobalSettingsProto.CELL_ON);
+
+        final long certPinToken = p.start(GlobalSettingsProto.CERT_PIN);
+        dumpSetting(s, p,
+                Settings.Global.CERT_PIN_UPDATE_CONTENT_URL,
+                GlobalSettingsProto.CertPin.UPDATE_CONTENT_URL);
+        dumpSetting(s, p,
+                Settings.Global.CERT_PIN_UPDATE_METADATA_URL,
+                GlobalSettingsProto.CertPin.UPDATE_METADATA_URL);
+        p.end(certPinToken);
+
+        dumpSetting(s, p,
+                Global.CHAINED_BATTERY_ATTRIBUTION_ENABLED,
+                GlobalSettingsProto.CHAINED_BATTERY_ATTRIBUTION_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.COMPATIBILITY_MODE,
+                GlobalSettingsProto.COMPATIBILITY_MODE);
+
+        final long connectivityToken = p.start(GlobalSettingsProto.CONNECTIVITY);
+        dumpSetting(s, p,
+                Settings.Global.CONNECTIVITY_METRICS_BUFFER_SIZE,
+                GlobalSettingsProto.Connectivity.METRICS_BUFFER_SIZE);
+        dumpSetting(s, p,
+                Settings.Global.CONNECTIVITY_CHANGE_DELAY,
+                GlobalSettingsProto.Connectivity.CHANGE_DELAY);
+        dumpSetting(s, p,
+                Settings.Global.CONNECTIVITY_SAMPLING_INTERVAL_IN_SECONDS,
+                GlobalSettingsProto.Connectivity.SAMPLING_INTERVAL_IN_SECONDS);
+        p.end(connectivityToken);
+
+        // Settings.Global.CONTACT_METADATA_SYNC intentionally excluded since it's deprecated.
+        dumpSetting(s, p,
+                Settings.Global.CONTACT_METADATA_SYNC_ENABLED,
+                GlobalSettingsProto.CONTACT_METADATA_SYNC_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.CONTACTS_DATABASE_WAL_ENABLED,
+                GlobalSettingsProto.CONTACTS_DATABASE_WAL_ENABLED);
+
+        final long dataToken = p.start(GlobalSettingsProto.DATA);
         // Settings.Global.DEFAULT_RESTRICT_BACKGROUND_DATA intentionally excluded.
         dumpSetting(s, p,
                 Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE,
-                GlobalSettingsProto.DATA_ACTIVITY_TIMEOUT_MOBILE);
+                GlobalSettingsProto.Data.ACTIVITY_TIMEOUT_MOBILE);
         dumpSetting(s, p,
                 Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI,
-                GlobalSettingsProto.DATA_ACTIVITY_TIMEOUT_WIFI);
+                GlobalSettingsProto.Data.ACTIVITY_TIMEOUT_WIFI);
         dumpSetting(s, p,
                 Settings.Global.DATA_ROAMING,
-                GlobalSettingsProto.DATA_ROAMING);
+                GlobalSettingsProto.Data.ROAMING);
         dumpSetting(s, p,
-                Settings.Global.MDC_INITIAL_MAX_RETRY,
-                GlobalSettingsProto.MDC_INITIAL_MAX_RETRY);
+                Settings.Global.DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS,
+                GlobalSettingsProto.Data.STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS);
+        dumpSetting(s, p,
+                Settings.Global.DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS,
+                GlobalSettingsProto.Data.STALL_ALARM_AGGRESSIVE_DELAY_IN_MS);
+        p.end(dataToken);
+
+        final long databaseToken = p.start(GlobalSettingsProto.DATABASE);
+        dumpSetting(s, p,
+                Settings.Global.DATABASE_DOWNGRADE_REASON,
+                GlobalSettingsProto.Database.DOWNGRADE_REASON);
+        dumpSetting(s, p,
+                Settings.Global.DATABASE_CREATION_BUILDID,
+                GlobalSettingsProto.Database.CREATION_BUILDID);
+        p.end(databaseToken);
+
+        final long debugToken = p.start(GlobalSettingsProto.DEBUG);
+        dumpSetting(s, p,
+                Settings.Global.DEBUG_APP,
+                GlobalSettingsProto.Debug.APP);
+        dumpSetting(s, p,
+                Settings.Global.DEBUG_VIEW_ATTRIBUTES,
+                GlobalSettingsProto.Debug.VIEW_ATTRIBUTES);
+        p.end(debugToken);
+
+        final long defaultToken = p.start(GlobalSettingsProto.DEFAULT);
+        // Settings.Global.DEFAULT_SM_DP_PLUS intentionally excluded.
+        dumpSetting(s, p,
+                Settings.Global.DEFAULT_INSTALL_LOCATION,
+                GlobalSettingsProto.Default.INSTALL_LOCATION);
+        dumpSetting(s, p,
+                Settings.Global.DEFAULT_DNS_SERVER,
+                GlobalSettingsProto.Default.DNS_SERVER);
+        p.end(defaultToken);
+
+        final long developmentToken = p.start(GlobalSettingsProto.DEVELOPMENT);
+        dumpSetting(s, p,
+                Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES,
+                GlobalSettingsProto.Development.FORCE_RESIZABLE_ACTIVITIES);
+        dumpSetting(s, p,
+                Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT,
+                GlobalSettingsProto.Development.ENABLE_FREEFORM_WINDOWS_SUPPORT);
+        dumpSetting(s, p,
+                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED,
+                GlobalSettingsProto.Development.SETTINGS_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.DEVELOPMENT_FORCE_RTL,
+                GlobalSettingsProto.Development.FORCE_RTL);
+        dumpSetting(s, p,
+                Settings.Global.EMULATE_DISPLAY_CUTOUT,
+                GlobalSettingsProto.Development.EMULATE_DISPLAY_CUTOUT);
+        p.end(developmentToken);
+
+        final long deviceToken = p.start(GlobalSettingsProto.DEVICE);
+        dumpSetting(s, p,
+                Settings.Global.DEVICE_NAME,
+                GlobalSettingsProto.Device.NAME);
+        dumpSetting(s, p,
+                Settings.Global.DEVICE_PROVISIONED,
+                GlobalSettingsProto.Device.PROVISIONED);
+        dumpSetting(s, p,
+                Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED,
+                GlobalSettingsProto.Device.PROVISIONING_MOBILE_DATA_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.DEVICE_IDLE_CONSTANTS,
+                GlobalSettingsProto.Device.IDLE_CONSTANTS);
+        dumpSetting(s, p,
+                Settings.Global.DEVICE_POLICY_CONSTANTS,
+                GlobalSettingsProto.Device.POLICY_CONSTANTS);
+        dumpSetting(s, p,
+                Settings.Global.DEVICE_DEMO_MODE,
+                GlobalSettingsProto.Device.DEMO_MODE);
+        p.end(deviceToken);
+
+        dumpSetting(s, p,
+                Settings.Global.DISK_FREE_CHANGE_REPORTING_THRESHOLD,
+                GlobalSettingsProto.DISK_FREE_CHANGE_REPORTING_THRESHOLD);
+
+        final long displayToken = p.start(GlobalSettingsProto.DISPLAY);
+        dumpSetting(s, p,
+                Settings.Global.DISPLAY_SIZE_FORCED,
+                GlobalSettingsProto.Display.SIZE_FORCED);
+        dumpSetting(s, p,
+                Settings.Global.DISPLAY_SCALING_FORCE,
+                GlobalSettingsProto.Display.SCALING_FORCE);
+        dumpSetting(s, p,
+                Settings.Global.DISPLAY_PANEL_LPM,
+                GlobalSettingsProto.Display.PANEL_LPM);
+        p.end(displayToken);
+
+        final long dnsResolverToken = p.start(GlobalSettingsProto.DNS_RESOLVER);
+        dumpSetting(s, p,
+                Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS,
+                GlobalSettingsProto.DnsResolver.SAMPLE_VALIDITY_SECONDS);
+        dumpSetting(s, p,
+                Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT,
+                GlobalSettingsProto.DnsResolver.SUCCESS_THRESHOLD_PERCENT);
+        dumpSetting(s, p,
+                Settings.Global.DNS_RESOLVER_MIN_SAMPLES,
+                GlobalSettingsProto.DnsResolver.MIN_SAMPLES);
+        dumpSetting(s, p,
+                Settings.Global.DNS_RESOLVER_MAX_SAMPLES,
+                GlobalSettingsProto.DnsResolver.MAX_SAMPLES);
+        p.end(dnsResolverToken);
+
+        dumpSetting(s, p,
+                Settings.Global.DOCK_AUDIO_MEDIA_ENABLED,
+                GlobalSettingsProto.DOCK_AUDIO_MEDIA_ENABLED);
+
+        final long downloadToken = p.start(GlobalSettingsProto.DOWNLOAD);
+        dumpSetting(s, p,
+                Settings.Global.DOWNLOAD_MAX_BYTES_OVER_MOBILE,
+                GlobalSettingsProto.Download.MAX_BYTES_OVER_MOBILE);
+        dumpSetting(s, p,
+                Settings.Global.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE,
+                GlobalSettingsProto.Download.RECOMMENDED_MAX_BYTES_OVER_MOBILE);
+        p.end(downloadToken);
+
+        final long dropboxToken = p.start(GlobalSettingsProto.DROPBOX);
+        dumpSetting(s, p,
+                Settings.Global.DROPBOX_AGE_SECONDS,
+                GlobalSettingsProto.Dropbox.AGE_SECONDS);
+        dumpSetting(s, p,
+                Settings.Global.DROPBOX_MAX_FILES,
+                GlobalSettingsProto.Dropbox.MAX_FILES);
+        dumpSetting(s, p,
+                Settings.Global.DROPBOX_QUOTA_KB,
+                GlobalSettingsProto.Dropbox.QUOTA_KB);
+        dumpSetting(s, p,
+                Settings.Global.DROPBOX_QUOTA_PERCENT,
+                GlobalSettingsProto.Dropbox.QUOTA_PERCENT);
+        dumpSetting(s, p,
+                Settings.Global.DROPBOX_RESERVE_PERCENT,
+                GlobalSettingsProto.Dropbox.RESERVE_PERCENT);
+        dumpRepeatedSetting(s, p,
+                Settings.Global.DROPBOX_TAG_PREFIX,
+                GlobalSettingsProto.Dropbox.SETTINGS);
+        p.end(dropboxToken);
+
+        final long emergencyToken = p.start(GlobalSettingsProto.EMERGENCY);
+        dumpSetting(s, p,
+                Settings.Global.EMERGENCY_TONE,
+                GlobalSettingsProto.Emergency.TONE);
+        dumpSetting(s, p,
+                Settings.Global.EMERGENCY_AFFORDANCE_NEEDED,
+                GlobalSettingsProto.Emergency.AFFORDANCE_NEEDED);
+        p.end(emergencyToken);
+
+        final long enableToken = p.start(GlobalSettingsProto.ENABLE);
+        dumpSetting(s, p,
+                Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED,
+                GlobalSettingsProto.Enable.ACCESSIBILITY_GLOBAL_GESTURE_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.ENABLE_GPU_DEBUG_LAYERS,
+                GlobalSettingsProto.Enable.GPU_DEBUG_LAYERS);
+        dumpSetting(s, p,
+                Settings.Global.ENABLE_EPHEMERAL_FEATURE,
+                GlobalSettingsProto.Enable.EPHEMERAL_FEATURE);
+        dumpSetting(s, p,
+                Settings.Global.ENABLE_CELLULAR_ON_BOOT,
+                GlobalSettingsProto.Enable.CELLULAR_ON_BOOT);
+        dumpSetting(s, p,
+                Settings.Global.ENABLE_DISKSTATS_LOGGING,
+                GlobalSettingsProto.Enable.DISKSTATS_LOGGING);
+        dumpSetting(s, p,
+                Settings.Global.ENABLE_CACHE_QUOTA_CALCULATION,
+                GlobalSettingsProto.Enable.CACHE_QUOTA_CALCULATION);
+        dumpSetting(s, p,
+                Settings.Global.ENABLE_DELETION_HELPER_NO_THRESHOLD_TOGGLE,
+                GlobalSettingsProto.Enable.DELETION_HELPER_NO_THRESHOLD_TOGGLE);
+        dumpSetting(s, p,
+                Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
+                GlobalSettingsProto.Enable.GNSS_RAW_MEAS_FULL_TRACKING);
+        p.end(enableToken);
+
+        dumpSetting(s, p,
+                Settings.Global.ENCODED_SURROUND_OUTPUT,
+                GlobalSettingsProto.ENCODED_SURROUND_OUTPUT);
+        dumpSetting(s, p,
+                Settings.Global.ENHANCED_4G_MODE_ENABLED,
+                GlobalSettingsProto.ENHANCED_4G_MODE_ENABLED);
+        dumpRepeatedSetting(s, p,
+                Settings.Global.ERROR_LOGCAT_PREFIX,
+                GlobalSettingsProto.ERROR_LOGCAT_LINES);
+
+        final long euiccToken = p.start(GlobalSettingsProto.EUICC);
+        dumpSetting(s, p,
+                Settings.Global.EUICC_PROVISIONED,
+                GlobalSettingsProto.Euicc.PROVISIONED);
+        dumpSetting(s, p,
+                Settings.Global.EUICC_FACTORY_RESET_TIMEOUT_MILLIS,
+                GlobalSettingsProto.Euicc.FACTORY_RESET_TIMEOUT_MILLIS);
+        p.end(euiccToken);
+
+        dumpSetting(s, p,
+                Settings.Global.FANCY_IME_ANIMATIONS,
+                GlobalSettingsProto.FANCY_IME_ANIMATIONS);
         dumpSetting(s, p,
                 Settings.Global.FORCE_ALLOW_ON_EXTERNAL,
                 GlobalSettingsProto.FORCE_ALLOW_ON_EXTERNAL);
-        // Settings.Global.DEFAULT_SM_DP_PLUS intentionally excluded.
         dumpSetting(s, p,
-                Settings.Global.EUICC_PROVISIONED,
-                GlobalSettingsProto.EUICC_PROVISIONED);
+                Settings.Global.FPS_DEVISOR,
+                GlobalSettingsProto.FPS_DIVISOR);
         dumpSetting(s, p,
-                Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES,
-                GlobalSettingsProto.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES);
+                Settings.Global.FSTRIM_MANDATORY_INTERVAL,
+                GlobalSettingsProto.FSTRIM_MANDATORY_INTERVAL);
+
+        final long ghpToken = p.start(GlobalSettingsProto.GLOBAL_HTTP_PROXY);
         dumpSetting(s, p,
-                Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT,
-                GlobalSettingsProto.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT);
+                Settings.Global.GLOBAL_HTTP_PROXY_HOST,
+                GlobalSettingsProto.GlobalHttpProxy.HOST);
         dumpSetting(s, p,
-                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED,
-                GlobalSettingsProto.DEVELOPMENT_SETTINGS_ENABLED);
+                Settings.Global.GLOBAL_HTTP_PROXY_PORT,
+                GlobalSettingsProto.GlobalHttpProxy.PORT);
         dumpSetting(s, p,
-                Settings.Global.DEVICE_PROVISIONED,
-                GlobalSettingsProto.DEVICE_PROVISIONED);
+                Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
+                GlobalSettingsProto.GlobalHttpProxy.EXCLUSION_LIST);
         dumpSetting(s, p,
-                Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED,
-                GlobalSettingsProto.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED);
+                Settings.Global.GLOBAL_HTTP_PROXY_PAC,
+                GlobalSettingsProto.GlobalHttpProxy.PAC);
         dumpSetting(s, p,
-                Settings.Global.DISPLAY_SIZE_FORCED,
-                GlobalSettingsProto.DISPLAY_SIZE_FORCED);
+                Settings.Global.SET_GLOBAL_HTTP_PROXY,
+                GlobalSettingsProto.GlobalHttpProxy.SETTING_UI_ENABLED);
+        p.end(ghpToken);
+
         dumpSetting(s, p,
-                Settings.Global.DISPLAY_SCALING_FORCE,
-                GlobalSettingsProto.DISPLAY_SCALING_FORCE);
+                Settings.Global.GPRS_REGISTER_CHECK_PERIOD_MS,
+                GlobalSettingsProto.GPRS_REGISTER_CHECK_PERIOD_MS);
+
+        final long gpuToken = p.start(GlobalSettingsProto.GPU);
         dumpSetting(s, p,
-                Settings.Global.DOWNLOAD_MAX_BYTES_OVER_MOBILE,
-                GlobalSettingsProto.DOWNLOAD_MAX_BYTES_OVER_MOBILE);
+                Settings.Global.GPU_DEBUG_APP,
+                GlobalSettingsProto.Gpu.DEBUG_APP);
         dumpSetting(s, p,
-                Settings.Global.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE,
-                GlobalSettingsProto.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE);
-        // Settings.Global.INSTALL_NON_MARKET_APPS intentionally excluded since it's deprecated.
+                Settings.Global.GPU_DEBUG_LAYERS,
+                GlobalSettingsProto.Gpu.DEBUG_LAYERS);
+        p.end(gpuToken);
+
+        final long hdmiToken = p.start(GlobalSettingsProto.HDMI);
         dumpSetting(s, p,
                 Settings.Global.HDMI_CONTROL_ENABLED,
-                GlobalSettingsProto.HDMI_CONTROL_ENABLED);
+                GlobalSettingsProto.Hdmi.CONTROL_ENABLED);
         dumpSetting(s, p,
                 Settings.Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED,
-                GlobalSettingsProto.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED);
+                GlobalSettingsProto.Hdmi.SYSTEM_AUDIO_CONTROL_ENABLED);
         dumpSetting(s, p,
                 Settings.Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED,
-                GlobalSettingsProto.HDMI_CONTROL_AUTO_WAKEUP_ENABLED);
+                GlobalSettingsProto.Hdmi.CONTROL_AUTO_WAKEUP_ENABLED);
         dumpSetting(s, p,
                 Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
-                GlobalSettingsProto.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED);
+                GlobalSettingsProto.Hdmi.CONTROL_AUTO_DEVICE_OFF_ENABLED);
+        p.end(hdmiToken);
+
         dumpSetting(s, p,
-                Settings.Global.PRIV_APP_OOB_ENABLED,
-                GlobalSettingsProto.PRIV_APP_OOB_ENABLED);
+                Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
+                GlobalSettingsProto.HEADS_UP_NOTIFICATIONS_ENABLED);
+        dumpSetting(s, p,
+                Global.HIDDEN_API_BLACKLIST_EXEMPTIONS,
+                GlobalSettingsProto.HIDDEN_API_BLACKLIST_EXEMPTIONS);
+
+        final long inetCondToken = p.start(GlobalSettingsProto.INET_CONDITION);
+        dumpSetting(s, p,
+                Settings.Global.INET_CONDITION_DEBOUNCE_UP_DELAY,
+                GlobalSettingsProto.InetCondition.DEBOUNCE_UP_DELAY);
+        dumpSetting(s, p,
+                Settings.Global.INET_CONDITION_DEBOUNCE_DOWN_DELAY,
+                GlobalSettingsProto.InetCondition.DEBOUNCE_DOWN_DELAY);
+        p.end(inetCondToken);
+
+        final long instantAppToken = p.start(GlobalSettingsProto.INSTANT_APP);
+        dumpSetting(s, p,
+                Settings.Global.INSTANT_APP_DEXOPT_ENABLED,
+                GlobalSettingsProto.InstantApp.DEXOPT_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.EPHEMERAL_COOKIE_MAX_SIZE_BYTES,
+                GlobalSettingsProto.InstantApp.EPHEMERAL_COOKIE_MAX_SIZE_BYTES);
+        dumpSetting(s, p,
+                Settings.Global.INSTALLED_INSTANT_APP_MIN_CACHE_PERIOD,
+                GlobalSettingsProto.InstantApp.INSTALLED_MIN_CACHE_PERIOD);
+        dumpSetting(s, p,
+                Settings.Global.INSTALLED_INSTANT_APP_MAX_CACHE_PERIOD,
+                GlobalSettingsProto.InstantApp.INSTALLED_MAX_CACHE_PERIOD);
+        dumpSetting(s, p,
+                Settings.Global.UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD,
+                GlobalSettingsProto.InstantApp.UNINSTALLED_MIN_CACHE_PERIOD);
+        dumpSetting(s, p,
+                Settings.Global.UNINSTALLED_INSTANT_APP_MAX_CACHE_PERIOD,
+                GlobalSettingsProto.InstantApp.UNINSTALLED_MAX_CACHE_PERIOD);
+        p.end(instantAppToken);
+
+        final long intentFirewallToken = p.start(GlobalSettingsProto.INTENT_FIREWALL);
+        dumpSetting(s, p,
+                Settings.Global.INTENT_FIREWALL_UPDATE_CONTENT_URL,
+                GlobalSettingsProto.IntentFirewall.UPDATE_CONTENT_URL);
+        dumpSetting(s, p,
+                Settings.Global.INTENT_FIREWALL_UPDATE_METADATA_URL,
+                GlobalSettingsProto.IntentFirewall.UPDATE_METADATA_URL);
+        p.end(intentFirewallToken);
+
+        dumpSetting(s, p,
+                Settings.Global.JOB_SCHEDULER_CONSTANTS,
+                GlobalSettingsProto.JOB_SCHEDULER_CONSTANTS);
+        dumpSetting(s, p,
+                Settings.Global.KEEP_PROFILE_IN_BACKGROUND,
+                GlobalSettingsProto.KEEP_PROFILE_IN_BACKGROUND);
+
+        final long langIdToken = p.start(GlobalSettingsProto.LANG_ID);
+        dumpSetting(s, p,
+                Settings.Global.LANG_ID_UPDATE_CONTENT_URL,
+                GlobalSettingsProto.LangId.UPDATE_CONTENT_URL);
+        dumpSetting(s, p,
+                Settings.Global.LANG_ID_UPDATE_METADATA_URL,
+                GlobalSettingsProto.LangId.UPDATE_METADATA_URL);
+        p.end(langIdToken);
+
+        final long locationToken = p.start(GlobalSettingsProto.LOCATION);
         dumpSetting(s, p,
                 Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
-                GlobalSettingsProto.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS);
+                GlobalSettingsProto.Location.BACKGROUND_THROTTLE_INTERVAL_MS);
         dumpSetting(s, p,
                 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS,
-                GlobalSettingsProto.LOCATION_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS);
+                GlobalSettingsProto.Location.BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS);
         dumpSetting(s, p,
                 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST,
-                GlobalSettingsProto.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
+                GlobalSettingsProto.Location.BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
+        dumpSetting(s, p,
+                Settings.Global.LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED,
+                GlobalSettingsProto.Location.SETTINGS_LINK_TO_PERMISSIONS_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.LOCATION_GLOBAL_KILL_SWITCH,
+                GlobalSettingsProto.Location.GLOBAL_KILL_SWITCH);
+        p.end(locationToken);
+
+        final long lpmToken = p.start(GlobalSettingsProto.LOW_POWER_MODE);
+        dumpSetting(s, p,
+                Settings.Global.LOW_POWER_MODE,
+                GlobalSettingsProto.LowPowerMode.ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL,
+                GlobalSettingsProto.LowPowerMode.TRIGGER_LEVEL);
+        dumpSetting(s, p,
+                Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL_MAX,
+                GlobalSettingsProto.LowPowerMode.TRIGGER_LEVEL_MAX);
+        p.end(lpmToken);
+
+        dumpSetting(s, p,
+                Settings.Global.LTE_SERVICE_FORCED,
+                GlobalSettingsProto.LTE_SERVICE_FORCED);
+        dumpSetting(s, p,
+                Settings.Global.MDC_INITIAL_MAX_RETRY,
+                GlobalSettingsProto.MDC_INITIAL_MAX_RETRY);
+
+        final long mhlToken = p.start(GlobalSettingsProto.MHL);
         dumpSetting(s, p,
                 Settings.Global.MHL_INPUT_SWITCHING_ENABLED,
-                GlobalSettingsProto.MHL_INPUT_SWITCHING_ENABLED);
+                GlobalSettingsProto.Mhl.INPUT_SWITCHING_ENABLED);
         dumpSetting(s, p,
                 Settings.Global.MHL_POWER_CHARGE_ENABLED,
-                GlobalSettingsProto.MHL_POWER_CHARGE_ENABLED);
+                GlobalSettingsProto.Mhl.POWER_CHARGE_ENABLED);
+        p.end(mhlToken);
+
+        final long mobileDataToken = p.start(GlobalSettingsProto.MOBILE_DATA);
         dumpSetting(s, p,
                 Settings.Global.MOBILE_DATA,
-                GlobalSettingsProto.MOBILE_DATA);
+                GlobalSettingsProto.MobileData.ALLOWED);
         dumpSetting(s, p,
                 Settings.Global.MOBILE_DATA_ALWAYS_ON,
-                GlobalSettingsProto.MOBILE_DATA_ALWAYS_ON);
+                GlobalSettingsProto.MobileData.ALWAYS_ON);
+        p.end(mobileDataToken);
+
         dumpSetting(s, p,
-                Settings.Global.CONNECTIVITY_METRICS_BUFFER_SIZE,
-                GlobalSettingsProto.CONNECTIVITY_METRICS_BUFFER_SIZE);
+                Settings.Global.MODE_RINGER,
+                GlobalSettingsProto.MODE_RINGER);
+
+        final long multiSimToken = p.start(GlobalSettingsProto.MULTI_SIM);
+        dumpSetting(s, p,
+                Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION,
+                GlobalSettingsProto.MultiSim.VOICE_CALL_SUBSCRIPTION);
+        dumpSetting(s, p,
+                Settings.Global.MULTI_SIM_VOICE_PROMPT,
+                GlobalSettingsProto.MultiSim.VOICE_PROMPT);
+        dumpSetting(s, p,
+                Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION,
+                GlobalSettingsProto.MultiSim.DATA_CALL_SUBSCRIPTION);
+        dumpSetting(s, p,
+                Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION,
+                GlobalSettingsProto.MultiSim.SMS_SUBSCRIPTION);
+        dumpSetting(s, p,
+                Settings.Global.MULTI_SIM_SMS_PROMPT,
+                GlobalSettingsProto.MultiSim.SMS_PROMPT);
+        p.end(multiSimToken);
+
+        final long netstatsToken = p.start(GlobalSettingsProto.NETSTATS);
         dumpSetting(s, p,
                 Settings.Global.NETSTATS_ENABLED,
-                GlobalSettingsProto.NETSTATS_ENABLED);
+                GlobalSettingsProto.Netstats.ENABLED);
         dumpSetting(s, p,
                 Settings.Global.NETSTATS_POLL_INTERVAL,
-                GlobalSettingsProto.NETSTATS_POLL_INTERVAL);
+                GlobalSettingsProto.Netstats.POLL_INTERVAL);
         dumpSetting(s, p,
                 Settings.Global.NETSTATS_TIME_CACHE_MAX_AGE,
-                GlobalSettingsProto.NETSTATS_TIME_CACHE_MAX_AGE);
+                GlobalSettingsProto.Netstats.TIME_CACHE_MAX_AGE);
         dumpSetting(s, p,
                 Settings.Global.NETSTATS_GLOBAL_ALERT_BYTES,
-                GlobalSettingsProto.NETSTATS_GLOBAL_ALERT_BYTES);
+                GlobalSettingsProto.Netstats.GLOBAL_ALERT_BYTES);
         dumpSetting(s, p,
                 Settings.Global.NETSTATS_SAMPLE_ENABLED,
-                GlobalSettingsProto.NETSTATS_SAMPLE_ENABLED);
+                GlobalSettingsProto.Netstats.SAMPLE_ENABLED);
         dumpSetting(s, p,
                 Settings.Global.NETSTATS_AUGMENT_ENABLED,
-                GlobalSettingsProto.NETSTATS_AUGMENT_ENABLED);
+                GlobalSettingsProto.Netstats.AUGMENT_ENABLED);
         dumpSetting(s, p,
                 Settings.Global.NETSTATS_DEV_BUCKET_DURATION,
-                GlobalSettingsProto.NETSTATS_DEV_BUCKET_DURATION);
+                GlobalSettingsProto.Netstats.DEV_BUCKET_DURATION);
         dumpSetting(s, p,
                 Settings.Global.NETSTATS_DEV_PERSIST_BYTES,
-                GlobalSettingsProto.NETSTATS_DEV_PERSIST_BYTES);
+                GlobalSettingsProto.Netstats.DEV_PERSIST_BYTES);
         dumpSetting(s, p,
                 Settings.Global.NETSTATS_DEV_ROTATE_AGE,
-                GlobalSettingsProto.NETSTATS_DEV_ROTATE_AGE);
+                GlobalSettingsProto.Netstats.DEV_ROTATE_AGE);
         dumpSetting(s, p,
                 Settings.Global.NETSTATS_DEV_DELETE_AGE,
-                GlobalSettingsProto.NETSTATS_DEV_DELETE_AGE);
+                GlobalSettingsProto.Netstats.DEV_DELETE_AGE);
         dumpSetting(s, p,
                 Settings.Global.NETSTATS_UID_BUCKET_DURATION,
-                GlobalSettingsProto.NETSTATS_UID_BUCKET_DURATION);
+                GlobalSettingsProto.Netstats.UID_BUCKET_DURATION);
         dumpSetting(s, p,
                 Settings.Global.NETSTATS_UID_PERSIST_BYTES,
-                GlobalSettingsProto.NETSTATS_UID_PERSIST_BYTES);
+                GlobalSettingsProto.Netstats.UID_PERSIST_BYTES);
         dumpSetting(s, p,
                 Settings.Global.NETSTATS_UID_ROTATE_AGE,
-                GlobalSettingsProto.NETSTATS_UID_ROTATE_AGE);
+                GlobalSettingsProto.Netstats.UID_ROTATE_AGE);
         dumpSetting(s, p,
                 Settings.Global.NETSTATS_UID_DELETE_AGE,
-                GlobalSettingsProto.NETSTATS_UID_DELETE_AGE);
+                GlobalSettingsProto.Netstats.UID_DELETE_AGE);
         dumpSetting(s, p,
                 Settings.Global.NETSTATS_UID_TAG_BUCKET_DURATION,
-                GlobalSettingsProto.NETSTATS_UID_TAG_BUCKET_DURATION);
+                GlobalSettingsProto.Netstats.UID_TAG_BUCKET_DURATION);
         dumpSetting(s, p,
                 Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES,
-                GlobalSettingsProto.NETSTATS_UID_TAG_PERSIST_BYTES);
+                GlobalSettingsProto.Netstats.UID_TAG_PERSIST_BYTES);
         dumpSetting(s, p,
                 Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE,
-                GlobalSettingsProto.NETSTATS_UID_TAG_ROTATE_AGE);
+                GlobalSettingsProto.Netstats.UID_TAG_ROTATE_AGE);
         dumpSetting(s, p,
                 Settings.Global.NETSTATS_UID_TAG_DELETE_AGE,
-                GlobalSettingsProto.NETSTATS_UID_TAG_DELETE_AGE);
+                GlobalSettingsProto.Netstats.UID_TAG_DELETE_AGE);
+        p.end(netstatsToken);
+
+        final long networkToken = p.start(GlobalSettingsProto.NETWORK);
         dumpSetting(s, p,
                 Settings.Global.NETWORK_PREFERENCE,
-                GlobalSettingsProto.NETWORK_PREFERENCE);
+                GlobalSettingsProto.Network.PREFERENCE);
+        dumpSetting(s, p,
+                Settings.Global.PREFERRED_NETWORK_MODE,
+                GlobalSettingsProto.Network.PREFERRED_NETWORK_MODE);
         dumpSetting(s, p,
                 Settings.Global.NETWORK_SCORER_APP,
-                GlobalSettingsProto.NETWORK_SCORER_APP);
+                GlobalSettingsProto.Network.SCORER_APP);
+        dumpSetting(s, p,
+                Settings.Global.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT,
+                GlobalSettingsProto.Network.SWITCH_NOTIFICATION_DAILY_LIMIT);
+        dumpSetting(s, p,
+                Settings.Global.NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS,
+                GlobalSettingsProto.Network.SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS);
+        dumpSetting(s, p,
+                Settings.Global.NETWORK_AVOID_BAD_WIFI,
+                GlobalSettingsProto.Network.AVOID_BAD_WIFI);
+        dumpSetting(s, p,
+                Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE,
+                GlobalSettingsProto.Network.METERED_MULTIPATH_PREFERENCE);
+        dumpSetting(s, p,
+                Settings.Global.NETWORK_WATCHLIST_LAST_REPORT_TIME,
+                GlobalSettingsProto.Network.WATCHLIST_LAST_REPORT_TIME);
+        dumpSetting(s, p,
+                Settings.Global.NETWORK_SCORING_UI_ENABLED,
+                GlobalSettingsProto.Network.SCORING_UI_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED,
+                GlobalSettingsProto.Network.RECOMMENDATIONS_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE,
+                GlobalSettingsProto.Network.RECOMMENDATIONS_PACKAGE);
+        dumpSetting(s, p,
+                Settings.Global.NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS,
+                GlobalSettingsProto.Network.RECOMMENDATION_REQUEST_TIMEOUT_MS);
+        dumpSetting(s, p,
+                Settings.Global.NETWORK_WATCHLIST_ENABLED,
+                GlobalSettingsProto.Network.WATCHLIST_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.NETWORK_SCORING_PROVISIONED,
+                GlobalSettingsProto.Network.SCORING_PROVISIONED);
+        dumpSetting(s, p,
+                Settings.Global.NETWORK_ACCESS_TIMEOUT_MS,
+                GlobalSettingsProto.Network.ACCESS_TIMEOUT_MS);
+        dumpSetting(s, p,
+                Settings.Global.RECOMMENDED_NETWORK_EVALUATOR_CACHE_EXPIRY_MS,
+                GlobalSettingsProto.Network.RECOMMENDED_NETWORK_EVALUATOR_CACHE_EXPIRY_MS);
+        p.end(networkToken);
+
+        dumpSetting(s, p,
+                Settings.Global.NEW_CONTACT_AGGREGATOR,
+                GlobalSettingsProto.NEW_CONTACT_AGGREGATOR);
         dumpSetting(s, p,
                 Settings.Global.NIGHT_DISPLAY_FORCED_AUTO_MODE_AVAILABLE,
                 GlobalSettingsProto.NIGHT_DISPLAY_FORCED_AUTO_MODE_AVAILABLE);
+
+        final long nitzUpdateToken = p.start(GlobalSettingsProto.NITZ_UPDATE);
         dumpSetting(s, p,
                 Settings.Global.NITZ_UPDATE_DIFF,
-                GlobalSettingsProto.NITZ_UPDATE_DIFF);
+                GlobalSettingsProto.NitzUpdate.DIFF);
         dumpSetting(s, p,
                 Settings.Global.NITZ_UPDATE_SPACING,
-                GlobalSettingsProto.NITZ_UPDATE_SPACING);
+                GlobalSettingsProto.NitzUpdate.SPACING);
+        p.end(nitzUpdateToken);
+
+        final long notificationToken = p.start(GlobalSettingsProto.NOTIFICATION);
+        dumpSetting(s, p,
+                Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
+                GlobalSettingsProto.Notification.MAX_NOTIFICATION_ENQUEUE_RATE);
+        dumpSetting(s, p,
+                Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS,
+                GlobalSettingsProto.Notification.SHOW_NOTIFICATION_CHANNEL_WARNINGS);
+        // The list of snooze options for notifications. This is encoded as a key=value list,
+        // separated by commas.
+        dumpSetting(s, p,
+                Settings.Global.NOTIFICATION_SNOOZE_OPTIONS,
+                GlobalSettingsProto.Notification.SNOOZE_OPTIONS);
+        dumpSetting(s, p,
+                Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS,
+                GlobalSettingsProto.Notification.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS);
+        p.end(notificationToken);
+
+        dumpSetting(s, p,
+                Settings.Global.NSD_ON,
+                GlobalSettingsProto.NSD_ON);
+
+        final long ntpToken = p.start(GlobalSettingsProto.NTP);
         dumpSetting(s, p,
                 Settings.Global.NTP_SERVER,
-                GlobalSettingsProto.NTP_SERVER);
+                GlobalSettingsProto.Ntp.SERVER);
         dumpSetting(s, p,
                 Settings.Global.NTP_TIMEOUT,
-                GlobalSettingsProto.NTP_TIMEOUT);
+                GlobalSettingsProto.Ntp.TIMEOUT_MS);
+        p.end(ntpToken);
+
+        final long obroToken = p.start(GlobalSettingsProto.OFF_BODY_RADIOS_OFF);
         dumpSetting(s, p,
-                Settings.Global.STORAGE_BENCHMARK_INTERVAL,
-                GlobalSettingsProto.STORAGE_BENCHMARK_INTERVAL);
+                Settings.Global.OFF_BODY_RADIOS_OFF_FOR_SMALL_BATTERY_ENABLED,
+                GlobalSettingsProto.OffBodyRadiosOff.ENABLED_FOR_SMALL_BATTERY);
         dumpSetting(s, p,
-                Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS,
-                GlobalSettingsProto.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS);
-        dumpSetting(s, p,
-                Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT,
-                GlobalSettingsProto.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT);
-        dumpSetting(s, p,
-                Settings.Global.DNS_RESOLVER_MIN_SAMPLES,
-                GlobalSettingsProto.DNS_RESOLVER_MIN_SAMPLES);
-        dumpSetting(s, p,
-                Settings.Global.DNS_RESOLVER_MAX_SAMPLES,
-                GlobalSettingsProto.DNS_RESOLVER_MAX_SAMPLES);
+                Settings.Global.OFF_BODY_RADIOS_OFF_DELAY_MS,
+                GlobalSettingsProto.OffBodyRadiosOff.DELAY_MS);
+        p.end(obroToken);
+
         dumpSetting(s, p,
                 Settings.Global.OTA_DISABLE_AUTOMATIC_UPDATE,
                 GlobalSettingsProto.OTA_DISABLE_AUTOMATIC_UPDATE);
         dumpSetting(s, p,
+                Settings.Global.OVERLAY_DISPLAY_DEVICES,
+                GlobalSettingsProto.OVERLAY_DISPLAY_DEVICES);
+        dumpSetting(s, p,
+                Settings.Global.OVERRIDE_SETTINGS_PROVIDER_RESTORE_ANY_VERSION,
+                GlobalSettingsProto.OVERRIDE_SETTINGS_PROVIDER_RESTORE_ANY_VERSION);
+        dumpSetting(s, p,
+                Settings.Global.PAC_CHANGE_DELAY,
+                GlobalSettingsProto.PAC_CHANGE_DELAY);
+
+        final long pkgVerifierToken = p.start(GlobalSettingsProto.PACKAGE_VERIFIER);
+        dumpSetting(s, p,
                 Settings.Global.PACKAGE_VERIFIER_ENABLE,
-                GlobalSettingsProto.PACKAGE_VERIFIER_ENABLE);
+                GlobalSettingsProto.PackageVerifier.ENABLED);
         dumpSetting(s, p,
                 Settings.Global.PACKAGE_VERIFIER_TIMEOUT,
-                GlobalSettingsProto.PACKAGE_VERIFIER_TIMEOUT);
+                GlobalSettingsProto.PackageVerifier.TIMEOUT);
         dumpSetting(s, p,
                 Settings.Global.PACKAGE_VERIFIER_DEFAULT_RESPONSE,
-                GlobalSettingsProto.PACKAGE_VERIFIER_DEFAULT_RESPONSE);
+                GlobalSettingsProto.PackageVerifier.DEFAULT_RESPONSE);
         dumpSetting(s, p,
                 Settings.Global.PACKAGE_VERIFIER_SETTING_VISIBLE,
-                GlobalSettingsProto.PACKAGE_VERIFIER_SETTING_VISIBLE);
+                GlobalSettingsProto.PackageVerifier.SETTING_VISIBLE);
         dumpSetting(s, p,
                 Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB,
-                GlobalSettingsProto.PACKAGE_VERIFIER_INCLUDE_ADB);
-        dumpSetting(s, p,
-                Settings.Global.FSTRIM_MANDATORY_INTERVAL,
-                GlobalSettingsProto.FSTRIM_MANDATORY_INTERVAL);
+                GlobalSettingsProto.PackageVerifier.INCLUDE_ADB);
+        p.end(pkgVerifierToken);
+
+        final long pdpWatchdogToken = p.start(GlobalSettingsProto.PDP_WATCHDOG);
         dumpSetting(s, p,
                 Settings.Global.PDP_WATCHDOG_POLL_INTERVAL_MS,
-                GlobalSettingsProto.PDP_WATCHDOG_POLL_INTERVAL_MS);
+                GlobalSettingsProto.PdpWatchdog.POLL_INTERVAL_MS);
         dumpSetting(s, p,
                 Settings.Global.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS,
-                GlobalSettingsProto.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS);
+                GlobalSettingsProto.PdpWatchdog.LONG_POLL_INTERVAL_MS);
         dumpSetting(s, p,
                 Settings.Global.PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS,
-                GlobalSettingsProto.PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS);
+                GlobalSettingsProto.PdpWatchdog.ERROR_POLL_INTERVAL_MS);
         dumpSetting(s, p,
                 Settings.Global.PDP_WATCHDOG_TRIGGER_PACKET_COUNT,
-                GlobalSettingsProto.PDP_WATCHDOG_TRIGGER_PACKET_COUNT);
+                GlobalSettingsProto.PdpWatchdog.TRIGGER_PACKET_COUNT);
         dumpSetting(s, p,
                 Settings.Global.PDP_WATCHDOG_ERROR_POLL_COUNT,
-                GlobalSettingsProto.PDP_WATCHDOG_ERROR_POLL_COUNT);
+                GlobalSettingsProto.PdpWatchdog.ERROR_POLL_COUNT);
         dumpSetting(s, p,
                 Settings.Global.PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT,
-                GlobalSettingsProto.PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT);
+                GlobalSettingsProto.PdpWatchdog.MAX_PDP_RESET_FAIL_COUNT);
+        p.end(pdpWatchdogToken);
+
+        dumpSetting(s, p,
+                Settings.Global.POLICY_CONTROL,
+                GlobalSettingsProto.POLICY_CONTROL);
+        dumpSetting(s, p,
+                Settings.Global.POWER_MANAGER_CONSTANTS,
+                GlobalSettingsProto.POWER_MANAGER_CONSTANTS);
+        dumpSetting(s, p,
+                Settings.Global.PRIV_APP_OOB_ENABLED,
+                GlobalSettingsProto.PRIV_APP_OOB_ENABLED);
+
+        final long prepaidSetupToken = p.start(GlobalSettingsProto.PREPAID_SETUP);
         dumpSetting(s, p,
                 Settings.Global.SETUP_PREPAID_DATA_SERVICE_URL,
-                GlobalSettingsProto.SETUP_PREPAID_DATA_SERVICE_URL);
+                GlobalSettingsProto.PrepaidSetup.DATA_SERVICE_URL);
         dumpSetting(s, p,
                 Settings.Global.SETUP_PREPAID_DETECTION_TARGET_URL,
-                GlobalSettingsProto.SETUP_PREPAID_DETECTION_TARGET_URL);
+                GlobalSettingsProto.PrepaidSetup.DETECTION_TARGET_URL);
         dumpSetting(s, p,
                 Settings.Global.SETUP_PREPAID_DETECTION_REDIR_HOST,
-                GlobalSettingsProto.SETUP_PREPAID_DETECTION_REDIR_HOST);
+                GlobalSettingsProto.PrepaidSetup.DETECTION_REDIR_HOST);
+        p.end(prepaidSetupToken);
+
+        final long privateToken = p.start(GlobalSettingsProto.PRIVATE);
+        dumpSetting(s, p,
+                Settings.Global.PRIVATE_DNS_MODE,
+                GlobalSettingsProto.Private.DNS_MODE);
+        dumpSetting(s, p,
+                Settings.Global.PRIVATE_DNS_SPECIFIER,
+                GlobalSettingsProto.Private.DNS_SPECIFIER);
+        p.end(privateToken);
+
+        dumpSetting(s, p,
+                Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS,
+                GlobalSettingsProto.PROVISIONING_APN_ALARM_DELAY_IN_MS);
+        dumpSetting(s, p,
+                Settings.Global.READ_EXTERNAL_STORAGE_ENFORCED_DEFAULT,
+                GlobalSettingsProto.READ_EXTERNAL_STORAGE_ENFORCED_DEFAULT);
+        dumpSetting(s, p,
+                Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT,
+                GlobalSettingsProto.REQUIRE_PASSWORD_TO_DECRYPT);
+        dumpSetting(s, p,
+                Settings.Global.SAFE_BOOT_DISALLOWED,
+                GlobalSettingsProto.SAFE_BOOT_DISALLOWED);
+
+        final long selinuxToken = p.start(GlobalSettingsProto.SELINUX);
+        dumpSetting(s, p,
+                Settings.Global.SELINUX_UPDATE_CONTENT_URL,
+                GlobalSettingsProto.Selinux.UPDATE_CONTENT_URL);
+        dumpSetting(s, p,
+                Settings.Global.SELINUX_UPDATE_METADATA_URL,
+                GlobalSettingsProto.Selinux.UPDATE_METADATA_URL);
+        dumpSetting(s, p,
+                Settings.Global.SELINUX_STATUS,
+                GlobalSettingsProto.Selinux.STATUS);
+        p.end(selinuxToken);
+
+        dumpSetting(s, p,
+                Settings.Global.SEND_ACTION_APP_ERROR,
+                GlobalSettingsProto.SEND_ACTION_APP_ERROR);
+        dumpSetting(s, p,
+                Settings.Global.SET_INSTALL_LOCATION,
+                GlobalSettingsProto.SET_INSTALL_LOCATION);
+        dumpSetting(s, p,
+                Settings.Global.SHORTCUT_MANAGER_CONSTANTS,
+                GlobalSettingsProto.SHORTCUT_MANAGER_CONSTANTS);
+        dumpSetting(s, p,
+                Settings.Global.SHOW_FIRST_CRASH_DIALOG,
+                GlobalSettingsProto.SHOW_FIRST_CRASH_DIALOG);
+        // Settings.Global.SHOW_PROCESSES intentionally excluded since it's deprecated.
+        dumpSetting(s, p,
+                Settings.Global.SHOW_RESTART_IN_CRASH_DIALOG,
+                GlobalSettingsProto.SHOW_RESTART_IN_CRASH_DIALOG);
+        dumpSetting(s, p,
+                Settings.Global.SHOW_MUTE_IN_CRASH_DIALOG,
+                GlobalSettingsProto.SHOW_MUTE_IN_CRASH_DIALOG);
+
+        final long smartSelectToken = p.start(GlobalSettingsProto.SMART_SELECTION);
+        dumpSetting(s, p,
+                Settings.Global.SMART_SELECTION_UPDATE_CONTENT_URL,
+                GlobalSettingsProto.SmartSelection.UPDATE_CONTENT_URL);
+        dumpSetting(s, p,
+                Settings.Global.SMART_SELECTION_UPDATE_METADATA_URL,
+                GlobalSettingsProto.SmartSelection.UPDATE_METADATA_URL);
+        p.end(smartSelectToken);
+
+        final long smsToken = p.start(GlobalSettingsProto.SMS);
         dumpSetting(s, p,
                 Settings.Global.SMS_OUTGOING_CHECK_INTERVAL_MS,
-                GlobalSettingsProto.SMS_OUTGOING_CHECK_INTERVAL_MS);
+                GlobalSettingsProto.Sms.OUTGOING_CHECK_INTERVAL_MS);
         dumpSetting(s, p,
                 Settings.Global.SMS_OUTGOING_CHECK_MAX_COUNT,
-                GlobalSettingsProto.SMS_OUTGOING_CHECK_MAX_COUNT);
+                GlobalSettingsProto.Sms.OUTGOING_CHECK_MAX_COUNT);
         dumpSetting(s, p,
                 Settings.Global.SMS_SHORT_CODE_CONFIRMATION,
-                GlobalSettingsProto.SMS_SHORT_CODE_CONFIRMATION);
+                GlobalSettingsProto.Sms.SHORT_CODE_CONFIRMATION);
         dumpSetting(s, p,
                 Settings.Global.SMS_SHORT_CODE_RULE,
-                GlobalSettingsProto.SMS_SHORT_CODE_RULE);
+                GlobalSettingsProto.Sms.SHORT_CODE_RULE);
+        dumpSetting(s, p,
+                Settings.Global.SMS_SHORT_CODES_UPDATE_CONTENT_URL,
+                GlobalSettingsProto.Sms.SHORT_CODES_UPDATE_CONTENT_URL);
+        dumpSetting(s, p,
+                Settings.Global.SMS_SHORT_CODES_UPDATE_METADATA_URL,
+                GlobalSettingsProto.Sms.SHORT_CODES_UPDATE_METADATA_URL);
+        p.end(smsToken);
+
+        final long soundsToken = p.start(GlobalSettingsProto.SOUNDS);
+        dumpSetting(s, p,
+                Settings.Global.CAR_DOCK_SOUND,
+                GlobalSettingsProto.Sounds.CAR_DOCK);
+        dumpSetting(s, p,
+                Settings.Global.CAR_UNDOCK_SOUND,
+                GlobalSettingsProto.Sounds.CAR_UNDOCK);
+        dumpSetting(s, p,
+                Settings.Global.DESK_DOCK_SOUND,
+                GlobalSettingsProto.Sounds.DESK_DOCK);
+        dumpSetting(s, p,
+                Settings.Global.DESK_UNDOCK_SOUND,
+                GlobalSettingsProto.Sounds.DESK_UNDOCK);
+        dumpSetting(s, p,
+                Settings.Global.DOCK_SOUNDS_ENABLED,
+                GlobalSettingsProto.Sounds.DOCK_SOUNDS_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.DOCK_SOUNDS_ENABLED_WHEN_ACCESSIBILITY,
+                GlobalSettingsProto.Sounds.DOCK_SOUNDS_ENABLED_WHEN_ACCESSIBILITY);
+        dumpSetting(s, p,
+                Settings.Global.LOCK_SOUND,
+                GlobalSettingsProto.Sounds.LOCK);
+        dumpSetting(s, p,
+                Settings.Global.UNLOCK_SOUND,
+                GlobalSettingsProto.Sounds.UNLOCK);
+        dumpSetting(s, p,
+                Settings.Global.TRUSTED_SOUND,
+                GlobalSettingsProto.Sounds.TRUSTED);
+        dumpSetting(s, p,
+                Settings.Global.LOW_BATTERY_SOUND,
+                GlobalSettingsProto.Sounds.LOW_BATTERY);
+        dumpSetting(s, p,
+                Settings.Global.LOW_BATTERY_SOUND_TIMEOUT,
+                GlobalSettingsProto.Sounds.LOW_BATTERY_SOUND_TIMEOUT);
+        dumpSetting(s, p,
+                Settings.Global.POWER_SOUNDS_ENABLED,
+                GlobalSettingsProto.Sounds.LOW_BATTERY_SOUNDS_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.CHARGING_STARTED_SOUND,
+                GlobalSettingsProto.Sounds.CHARGING_STARTED);
+        dumpSetting(s, p,
+                Settings.Global.CHARGING_SOUNDS_ENABLED,
+                GlobalSettingsProto.Sounds.CHARGING_SOUNDS_ENABLED);
+        p.end(soundsToken);
+
+        final long soundTriggerToken = p.start(GlobalSettingsProto.SOUND_TRIGGER);
+        dumpSetting(s, p,
+                Global.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY,
+                GlobalSettingsProto.SoundTrigger.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY);
+        dumpSetting(s, p,
+                Global.SOUND_TRIGGER_DETECTION_SERVICE_OP_TIMEOUT,
+                GlobalSettingsProto.SoundTrigger.DETECTION_SERVICE_OP_TIMEOUT_MS);
+        p.end(soundTriggerToken);
+
+        dumpSetting(s, p,
+                Settings.Global.SPEED_LABEL_CACHE_EVICTION_AGE_MILLIS,
+                GlobalSettingsProto.SPEED_LABEL_CACHE_EVICTION_AGE_MS);
+        dumpSetting(s, p,
+                Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS,
+                GlobalSettingsProto.SQLITE_COMPATIBILITY_WAL_FLAGS);
+        dumpSetting(s, p,
+                Settings.Global.STAY_ON_WHILE_PLUGGED_IN,
+                GlobalSettingsProto.STAY_ON_WHILE_PLUGGED_IN);
+
+        final long storageToken = p.start(GlobalSettingsProto.STORAGE);
+        dumpSetting(s, p,
+                Settings.Global.STORAGE_BENCHMARK_INTERVAL,
+                GlobalSettingsProto.Storage.BENCHMARK_INTERVAL);
+        dumpSetting(s, p,
+                Settings.Global.STORAGE_SETTINGS_CLOBBER_THRESHOLD,
+                GlobalSettingsProto.Storage.SETTINGS_CLOBBER_THRESHOLD);
+        p.end(storageToken);
+
+        final long syncToken = p.start(GlobalSettingsProto.SYNC);
+        dumpSetting(s, p,
+                Settings.Global.SYNC_MAX_RETRY_DELAY_IN_SECONDS,
+                GlobalSettingsProto.Sync.MAX_RETRY_DELAY_IN_SECONDS);
+        dumpSetting(s, p,
+                Settings.Global.SYNC_MANAGER_CONSTANTS,
+                GlobalSettingsProto.Sync.MANAGER_CONSTANTS);
+        p.end(syncToken);
+
+        final long sysToken = p.start(GlobalSettingsProto.SYS);
+        dumpSetting(s, p,
+                Settings.Global.SYS_FREE_STORAGE_LOG_INTERVAL,
+                GlobalSettingsProto.Sys.FREE_STORAGE_LOG_INTERVAL_MINS);
+        dumpSetting(s, p,
+                Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE,
+                GlobalSettingsProto.Sys.STORAGE_THRESHOLD_PERCENTAGE);
+        dumpSetting(s, p,
+                Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES,
+                GlobalSettingsProto.Sys.STORAGE_THRESHOLD_MAX_BYTES);
+        dumpSetting(s, p,
+                Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES,
+                GlobalSettingsProto.Sys.STORAGE_FULL_THRESHOLD_BYTES);
+        dumpSetting(s, p,
+                Settings.Global.SYS_STORAGE_CACHE_PERCENTAGE,
+                GlobalSettingsProto.Sys.STORAGE_CACHE_PERCENTAGE);
+        dumpSetting(s, p,
+                Settings.Global.SYS_STORAGE_CACHE_MAX_BYTES,
+                GlobalSettingsProto.Sys.STORAGE_CACHE_MAX_BYTES);
+        dumpSetting(s, p,
+                Settings.Global.SYS_VDSO,
+                GlobalSettingsProto.Sys.VDSO);
+        dumpSetting(s, p,
+                Settings.Global.SYS_UIDCPUPOWER,
+                GlobalSettingsProto.Sys.UIDCPUPOWER);
+        p.end(sysToken);
+
         dumpSetting(s, p,
                 Settings.Global.TCP_DEFAULT_INIT_RWND,
                 GlobalSettingsProto.TCP_DEFAULT_INIT_RWND);
+
+        final long tempWarningToken = p.start(GlobalSettingsProto.TEMPERATURE_WARNING);
+        dumpSetting(s, p,
+                Settings.Global.SHOW_TEMPERATURE_WARNING,
+                GlobalSettingsProto.TemperatureWarning.SHOW_TEMPERATURE_WARNING);
+        dumpSetting(s, p,
+                Settings.Global.WARNING_TEMPERATURE,
+                GlobalSettingsProto.TemperatureWarning.WARNING_TEMPERATURE_LEVEL);
+        p.end(tempWarningToken);
+
+        final long tetherToken = p.start(GlobalSettingsProto.TETHER);
         dumpSetting(s, p,
                 Settings.Global.TETHER_SUPPORTED,
-                GlobalSettingsProto.TETHER_SUPPORTED);
+                GlobalSettingsProto.Tether.SUPPORTED);
         dumpSetting(s, p,
                 Settings.Global.TETHER_DUN_REQUIRED,
-                GlobalSettingsProto.TETHER_DUN_REQUIRED);
+                GlobalSettingsProto.Tether.DUN_REQUIRED);
         dumpSetting(s, p,
                 Settings.Global.TETHER_DUN_APN,
-                GlobalSettingsProto.TETHER_DUN_APN);
+                GlobalSettingsProto.Tether.DUN_APN);
         dumpSetting(s, p,
                 Settings.Global.TETHER_OFFLOAD_DISABLED,
-                GlobalSettingsProto.TETHER_OFFLOAD_DISABLED);
+                GlobalSettingsProto.Tether.OFFLOAD_DISABLED);
         dumpSetting(s, p,
-                Settings.Global.CARRIER_APP_WHITELIST,
-                GlobalSettingsProto.CARRIER_APP_WHITELIST);
+                Settings.Global.SOFT_AP_TIMEOUT_ENABLED,
+                GlobalSettingsProto.Tether.TIMEOUT_ENABLED);
+        p.end(tetherToken);
+
         dumpSetting(s, p,
-                Settings.Global.CARRIER_APP_NAMES,
-                GlobalSettingsProto.CARRIER_APP_NAMES);
+                Settings.Global.TEXT_CLASSIFIER_CONSTANTS,
+                GlobalSettingsProto.TEXT_CLASSIFIER_CONSTANTS);
+        dumpSetting(s, p,
+                Settings.Global.THEATER_MODE_ON,
+                GlobalSettingsProto.THEATER_MODE_ON);
+        dumpSetting(s, p,
+                Settings.Global.TIME_ONLY_MODE_CONSTANTS,
+                GlobalSettingsProto.TIME_ONLY_MODE_CONSTANTS);
+        dumpSetting(s, p,
+                Settings.Global.TRANSITION_ANIMATION_SCALE,
+                GlobalSettingsProto.TRANSITION_ANIMATION_SCALE);
+
+        final long tzinfoToken = p.start(GlobalSettingsProto.TZINFO);
+        dumpSetting(s, p,
+                Settings.Global.TZINFO_UPDATE_CONTENT_URL,
+                GlobalSettingsProto.Tzinfo.UPDATE_CONTENT_URL);
+        dumpSetting(s, p,
+                Settings.Global.TZINFO_UPDATE_METADATA_URL,
+                GlobalSettingsProto.Tzinfo.UPDATE_METADATA_URL);
+        p.end(tzinfoToken);
+
+        dumpSetting(s, p,
+                Settings.Global.UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD,
+                GlobalSettingsProto.UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD_MS);
         dumpSetting(s, p,
                 Settings.Global.USB_MASS_STORAGE_ENABLED,
                 GlobalSettingsProto.USB_MASS_STORAGE_ENABLED);
@@ -461,807 +1296,186 @@
                 Settings.Global.USE_GOOGLE_MAIL,
                 GlobalSettingsProto.USE_GOOGLE_MAIL);
         dumpSetting(s, p,
-                Settings.Global.WEBVIEW_DATA_REDUCTION_PROXY_KEY,
-                GlobalSettingsProto.WEBVIEW_DATA_REDUCTION_PROXY_KEY);
-        dumpSetting(s, p,
-                Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED,
-                GlobalSettingsProto.WEBVIEW_FALLBACK_LOGIC_ENABLED);
-        dumpSetting(s, p,
-                Settings.Global.WEBVIEW_PROVIDER,
-                GlobalSettingsProto.WEBVIEW_PROVIDER);
-        dumpSetting(s, p,
-                Settings.Global.WEBVIEW_MULTIPROCESS,
-                GlobalSettingsProto.WEBVIEW_MULTIPROCESS);
-        dumpSetting(s, p,
-                Settings.Global.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT,
-                GlobalSettingsProto.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT);
-        dumpSetting(s, p,
-                Settings.Global.NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS,
-                GlobalSettingsProto.NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS);
-        dumpSetting(s, p,
-                Settings.Global.NETWORK_AVOID_BAD_WIFI,
-                GlobalSettingsProto.NETWORK_AVOID_BAD_WIFI);
-        dumpSetting(s, p,
-                Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE,
-                GlobalSettingsProto.NETWORK_METERED_MULTIPATH_PREFERENCE);
-        dumpSetting(s, p,
-                Settings.Global.NETWORK_WATCHLIST_LAST_REPORT_TIME,
-                GlobalSettingsProto.NETWORK_WATCHLIST_LAST_REPORT_TIME);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_BADGING_THRESHOLDS,
-                GlobalSettingsProto.WIFI_BADGING_THRESHOLDS);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_DISPLAY_ON,
-                GlobalSettingsProto.WIFI_DISPLAY_ON);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_DISPLAY_CERTIFICATION_ON,
-                GlobalSettingsProto.WIFI_DISPLAY_CERTIFICATION_ON);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_DISPLAY_WPS_CONFIG,
-                GlobalSettingsProto.WIFI_DISPLAY_WPS_CONFIG);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
-                GlobalSettingsProto.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_CARRIER_NETWORKS_AVAILABLE_NOTIFICATION_ON,
-                GlobalSettingsProto.WIFI_CARRIER_NETWORKS_AVAILABLE_NOTIFICATION_ON);
-        dumpSetting(s, p,
-                Settings.Global.WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON,
-                GlobalSettingsProto.WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,
-                GlobalSettingsProto.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_COUNTRY_CODE,
-                GlobalSettingsProto.WIFI_COUNTRY_CODE);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS,
-                GlobalSettingsProto.WIFI_FRAMEWORK_SCAN_INTERVAL_MS);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_IDLE_MS,
-                GlobalSettingsProto.WIFI_IDLE_MS);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_NUM_OPEN_NETWORKS_KEPT,
-                GlobalSettingsProto.WIFI_NUM_OPEN_NETWORKS_KEPT);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_ON,
-                GlobalSettingsProto.WIFI_ON);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE,
-                GlobalSettingsProto.WIFI_SCAN_ALWAYS_AVAILABLE);
-        dumpSetting(s, p,
-                Settings.Global.SOFT_AP_TIMEOUT_ENABLED,
-                GlobalSettingsProto.SOFT_AP_TIMEOUT_ENABLED);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_WAKEUP_ENABLED,
-                GlobalSettingsProto.WIFI_WAKEUP_ENABLED);
-        dumpSetting(s, p,
-                Settings.Global.NETWORK_SCORING_UI_ENABLED,
-                GlobalSettingsProto.NETWORK_SCORING_UI_ENABLED);
-        dumpSetting(s, p,
-                Settings.Global.SPEED_LABEL_CACHE_EVICTION_AGE_MILLIS,
-                GlobalSettingsProto.SPEED_LABEL_CACHE_EVICTION_AGE_MILLIS);
-        dumpSetting(s, p,
-                Settings.Global.RECOMMENDED_NETWORK_EVALUATOR_CACHE_EXPIRY_MS,
-                GlobalSettingsProto.RECOMMENDED_NETWORK_EVALUATOR_CACHE_EXPIRY_MS);
-        dumpSetting(s, p,
-                Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED,
-                GlobalSettingsProto.NETWORK_RECOMMENDATIONS_ENABLED);
-        dumpSetting(s, p,
-                Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE,
-                GlobalSettingsProto.NETWORK_RECOMMENDATIONS_PACKAGE);
-        dumpSetting(s, p,
                 Settings.Global.USE_OPEN_WIFI_PACKAGE,
                 GlobalSettingsProto.USE_OPEN_WIFI_PACKAGE);
         dumpSetting(s, p,
-                Settings.Global.NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS,
-                GlobalSettingsProto.NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS);
-        dumpSetting(s, p,
-                Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE,
-                GlobalSettingsProto.BLE_SCAN_ALWAYS_AVAILABLE);
-        dumpSetting(s, p,
-                Settings.Global.BLE_SCAN_LOW_POWER_WINDOW_MS,
-                GlobalSettingsProto.BLE_SCAN_LOW_POWER_WINDOW_MS);
-        dumpSetting(s, p,
-                Settings.Global.BLE_SCAN_BALANCED_WINDOW_MS,
-                GlobalSettingsProto.BLE_SCAN_BALANCED_WINDOW_MS);
-        dumpSetting(s, p,
-                Settings.Global.BLE_SCAN_LOW_LATENCY_WINDOW_MS,
-                GlobalSettingsProto.BLE_SCAN_LOW_LATENCY_WINDOW_MS);
-        dumpSetting(s, p,
-                Settings.Global.BLE_SCAN_LOW_POWER_INTERVAL_MS,
-                GlobalSettingsProto.BLE_SCAN_LOW_POWER_INTERVAL_MS);
-        dumpSetting(s, p,
-                Settings.Global.BLE_SCAN_BALANCED_INTERVAL_MS,
-                GlobalSettingsProto.BLE_SCAN_BALANCED_INTERVAL_MS);
-        dumpSetting(s, p,
-                Settings.Global.BLE_SCAN_LOW_LATENCY_INTERVAL_MS,
-                GlobalSettingsProto.BLE_SCAN_LOW_LATENCY_INTERVAL_MS);
-        dumpSetting(s, p,
-                Settings.Global.BLE_SCAN_BACKGROUND_MODE,
-                GlobalSettingsProto.BLE_SCAN_BACKGROUND_MODE);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_SAVED_STATE,
-                GlobalSettingsProto.WIFI_SAVED_STATE);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,
-                GlobalSettingsProto.WIFI_SUPPLICANT_SCAN_INTERVAL_MS);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_ENHANCED_AUTO_JOIN,
-                GlobalSettingsProto.WIFI_ENHANCED_AUTO_JOIN);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_NETWORK_SHOW_RSSI,
-                GlobalSettingsProto.WIFI_NETWORK_SHOW_RSSI);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS,
-                GlobalSettingsProto.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_WATCHDOG_ON,
-                GlobalSettingsProto.WIFI_WATCHDOG_ON);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED,
-                GlobalSettingsProto.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED,
-                GlobalSettingsProto.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED,
-                GlobalSettingsProto.WIFI_VERBOSE_LOGGING_ENABLED);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED,
-                GlobalSettingsProto.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT,
-                GlobalSettingsProto.WIFI_MAX_DHCP_RETRY_COUNT);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS,
-                GlobalSettingsProto.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN,
-                GlobalSettingsProto.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_FREQUENCY_BAND,
-                GlobalSettingsProto.WIFI_FREQUENCY_BAND);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_P2P_DEVICE_NAME,
-                GlobalSettingsProto.WIFI_P2P_DEVICE_NAME);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_REENABLE_DELAY_MS,
-                GlobalSettingsProto.WIFI_REENABLE_DELAY_MS);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS,
-                GlobalSettingsProto.WIFI_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS);
-        dumpSetting(s, p,
-                Settings.Global.DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS,
-                GlobalSettingsProto.DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS);
-        dumpSetting(s, p,
-                Settings.Global.DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS,
-                GlobalSettingsProto.DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS);
-        dumpSetting(s, p,
-                Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS,
-                GlobalSettingsProto.PROVISIONING_APN_ALARM_DELAY_IN_MS);
-        dumpSetting(s, p,
-                Settings.Global.GPRS_REGISTER_CHECK_PERIOD_MS,
-                GlobalSettingsProto.GPRS_REGISTER_CHECK_PERIOD_MS);
-        dumpSetting(s, p,
-                Settings.Global.WTF_IS_FATAL,
-                GlobalSettingsProto.WTF_IS_FATAL);
-        dumpSetting(s, p,
-                Settings.Global.MODE_RINGER,
-                GlobalSettingsProto.MODE_RINGER);
-        dumpSetting(s, p,
-                Settings.Global.OVERLAY_DISPLAY_DEVICES,
-                GlobalSettingsProto.OVERLAY_DISPLAY_DEVICES);
-        dumpSetting(s, p,
-                Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD,
-                GlobalSettingsProto.BATTERY_DISCHARGE_DURATION_THRESHOLD);
-        dumpSetting(s, p,
-                Settings.Global.BATTERY_DISCHARGE_THRESHOLD,
-                GlobalSettingsProto.BATTERY_DISCHARGE_THRESHOLD);
-        dumpSetting(s, p,
-                Settings.Global.SEND_ACTION_APP_ERROR,
-                GlobalSettingsProto.SEND_ACTION_APP_ERROR);
-        dumpSetting(s, p,
-                Settings.Global.DROPBOX_AGE_SECONDS,
-                GlobalSettingsProto.DROPBOX_AGE_SECONDS);
-        dumpSetting(s, p,
-                Settings.Global.DROPBOX_MAX_FILES,
-                GlobalSettingsProto.DROPBOX_MAX_FILES);
-        dumpSetting(s, p,
-                Settings.Global.DROPBOX_QUOTA_KB,
-                GlobalSettingsProto.DROPBOX_QUOTA_KB);
-        dumpSetting(s, p,
-                Settings.Global.DROPBOX_QUOTA_PERCENT,
-                GlobalSettingsProto.DROPBOX_QUOTA_PERCENT);
-        dumpSetting(s, p,
-                Settings.Global.DROPBOX_RESERVE_PERCENT,
-                GlobalSettingsProto.DROPBOX_RESERVE_PERCENT);
-        dumpRepeatedSetting(s, p,
-                Settings.Global.DROPBOX_TAG_PREFIX,
-                GlobalSettingsProto.DROPBOX_SETTINGS);
-        dumpRepeatedSetting(s, p,
-                Settings.Global.ERROR_LOGCAT_PREFIX,
-                GlobalSettingsProto.ERROR_LOGCAT_LINES);
-        dumpSetting(s, p,
-                Settings.Global.SYS_FREE_STORAGE_LOG_INTERVAL,
-                GlobalSettingsProto.SYS_FREE_STORAGE_LOG_INTERVAL);
-        dumpSetting(s, p,
-                Settings.Global.DISK_FREE_CHANGE_REPORTING_THRESHOLD,
-                GlobalSettingsProto.DISK_FREE_CHANGE_REPORTING_THRESHOLD);
-        dumpSetting(s, p,
-                Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE,
-                GlobalSettingsProto.SYS_STORAGE_THRESHOLD_PERCENTAGE);
-        dumpSetting(s, p,
-                Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES,
-                GlobalSettingsProto.SYS_STORAGE_THRESHOLD_MAX_BYTES);
-        dumpSetting(s, p,
-                Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES,
-                GlobalSettingsProto.SYS_STORAGE_FULL_THRESHOLD_BYTES);
-        dumpSetting(s, p,
-                Settings.Global.SYS_STORAGE_CACHE_PERCENTAGE,
-                GlobalSettingsProto.SYS_STORAGE_CACHE_PERCENTAGE);
-        dumpSetting(s, p,
-                Settings.Global.SYS_STORAGE_CACHE_MAX_BYTES,
-                GlobalSettingsProto.SYS_STORAGE_CACHE_MAX_BYTES);
-        dumpSetting(s, p,
-                Settings.Global.SYNC_MAX_RETRY_DELAY_IN_SECONDS,
-                GlobalSettingsProto.SYNC_MAX_RETRY_DELAY_IN_SECONDS);
-        dumpSetting(s, p,
-                Settings.Global.CONNECTIVITY_CHANGE_DELAY,
-                GlobalSettingsProto.CONNECTIVITY_CHANGE_DELAY);
-        dumpSetting(s, p,
-                Settings.Global.CONNECTIVITY_SAMPLING_INTERVAL_IN_SECONDS,
-                GlobalSettingsProto.CONNECTIVITY_SAMPLING_INTERVAL_IN_SECONDS);
-        dumpSetting(s, p,
-                Settings.Global.PAC_CHANGE_DELAY,
-                GlobalSettingsProto.PAC_CHANGE_DELAY);
-        dumpSetting(s, p,
-                Settings.Global.CAPTIVE_PORTAL_MODE,
-                GlobalSettingsProto.CAPTIVE_PORTAL_MODE);
-        dumpSetting(s, p,
-                Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED,
-                GlobalSettingsProto.CAPTIVE_PORTAL_DETECTION_ENABLED);
-        dumpSetting(s, p,
-                Settings.Global.CAPTIVE_PORTAL_SERVER,
-                GlobalSettingsProto.CAPTIVE_PORTAL_SERVER);
-        dumpSetting(s, p,
-                Settings.Global.CAPTIVE_PORTAL_HTTPS_URL,
-                GlobalSettingsProto.CAPTIVE_PORTAL_HTTPS_URL);
-        dumpSetting(s, p,
-                Settings.Global.CAPTIVE_PORTAL_HTTP_URL,
-                GlobalSettingsProto.CAPTIVE_PORTAL_HTTP_URL);
-        dumpSetting(s, p,
-                Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL,
-                GlobalSettingsProto.CAPTIVE_PORTAL_FALLBACK_URL);
-        dumpSetting(s, p,
-                Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS,
-                GlobalSettingsProto.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS);
-        dumpSetting(s, p,
-                Settings.Global.CAPTIVE_PORTAL_USE_HTTPS,
-                GlobalSettingsProto.CAPTIVE_PORTAL_USE_HTTPS);
-        dumpSetting(s, p,
-                Settings.Global.CAPTIVE_PORTAL_USER_AGENT,
-                GlobalSettingsProto.CAPTIVE_PORTAL_USER_AGENT);
-        dumpSetting(s, p,
-                Settings.Global.NSD_ON,
-                GlobalSettingsProto.NSD_ON);
-        dumpSetting(s, p,
-                Settings.Global.SET_INSTALL_LOCATION,
-                GlobalSettingsProto.SET_INSTALL_LOCATION);
-        dumpSetting(s, p,
-                Settings.Global.DEFAULT_INSTALL_LOCATION,
-                GlobalSettingsProto.DEFAULT_INSTALL_LOCATION);
-        dumpSetting(s, p,
-                Settings.Global.INET_CONDITION_DEBOUNCE_UP_DELAY,
-                GlobalSettingsProto.INET_CONDITION_DEBOUNCE_UP_DELAY);
-        dumpSetting(s, p,
-                Settings.Global.INET_CONDITION_DEBOUNCE_DOWN_DELAY,
-                GlobalSettingsProto.INET_CONDITION_DEBOUNCE_DOWN_DELAY);
-        dumpSetting(s, p,
-                Settings.Global.READ_EXTERNAL_STORAGE_ENFORCED_DEFAULT,
-                GlobalSettingsProto.READ_EXTERNAL_STORAGE_ENFORCED_DEFAULT);
-        dumpSetting(s, p,
-                Settings.Global.HTTP_PROXY,
-                GlobalSettingsProto.HTTP_PROXY);
-        dumpSetting(s, p,
-                Settings.Global.GLOBAL_HTTP_PROXY_HOST,
-                GlobalSettingsProto.GLOBAL_HTTP_PROXY_HOST);
-        dumpSetting(s, p,
-                Settings.Global.GLOBAL_HTTP_PROXY_PORT,
-                GlobalSettingsProto.GLOBAL_HTTP_PROXY_PORT);
-        dumpSetting(s, p,
-                Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
-                GlobalSettingsProto.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
-        dumpSetting(s, p,
-                Settings.Global.GLOBAL_HTTP_PROXY_PAC,
-                GlobalSettingsProto.GLOBAL_HTTP_PROXY_PAC);
-        dumpSetting(s, p,
-                Settings.Global.SET_GLOBAL_HTTP_PROXY,
-                GlobalSettingsProto.SET_GLOBAL_HTTP_PROXY);
-        dumpSetting(s, p,
-                Settings.Global.DEFAULT_DNS_SERVER,
-                GlobalSettingsProto.DEFAULT_DNS_SERVER);
-        dumpSetting(s, p,
-                Settings.Global.PRIVATE_DNS_MODE,
-                GlobalSettingsProto.PRIVATE_DNS_MODE);
-        dumpSetting(s, p,
-                Settings.Global.PRIVATE_DNS_SPECIFIER,
-                GlobalSettingsProto.PRIVATE_DNS_SPECIFIER);
-        dumpRepeatedSetting(s, p,
-                Settings.Global.BLUETOOTH_HEADSET_PRIORITY_PREFIX,
-                GlobalSettingsProto.BLUETOOTH_HEADSET_PRIORITIES);
-        dumpRepeatedSetting(s, p,
-                Settings.Global.BLUETOOTH_A2DP_SINK_PRIORITY_PREFIX,
-                GlobalSettingsProto.BLUETOOTH_A2DP_SINK_PRIORITIES);
-        dumpRepeatedSetting(s, p,
-                Settings.Global.BLUETOOTH_A2DP_SRC_PRIORITY_PREFIX,
-                GlobalSettingsProto.BLUETOOTH_A2DP_SRC_PRIORITIES);
-        dumpRepeatedSetting(s, p,
-                Settings.Global.BLUETOOTH_A2DP_SUPPORTS_OPTIONAL_CODECS_PREFIX,
-                GlobalSettingsProto.BLUETOOTH_A2DP_SUPPORTS_OPTIONAL_CODECS);
-        dumpRepeatedSetting(s, p,
-                Settings.Global.BLUETOOTH_A2DP_OPTIONAL_CODECS_ENABLED_PREFIX,
-                GlobalSettingsProto.BLUETOOTH_A2DP_OPTIONAL_CODECS_ENABLED);
-        dumpRepeatedSetting(s, p,
-                Settings.Global.BLUETOOTH_INPUT_DEVICE_PRIORITY_PREFIX,
-                GlobalSettingsProto.BLUETOOTH_INPUT_DEVICE_PRIORITIES);
-        dumpRepeatedSetting(s, p,
-                Settings.Global.BLUETOOTH_MAP_PRIORITY_PREFIX,
-                GlobalSettingsProto.BLUETOOTH_MAP_PRIORITIES);
-        dumpRepeatedSetting(s, p,
-                Settings.Global.BLUETOOTH_MAP_CLIENT_PRIORITY_PREFIX,
-                GlobalSettingsProto.BLUETOOTH_MAP_CLIENT_PRIORITIES);
-        dumpRepeatedSetting(s, p,
-                Settings.Global.BLUETOOTH_PBAP_CLIENT_PRIORITY_PREFIX,
-                GlobalSettingsProto.BLUETOOTH_PBAP_CLIENT_PRIORITIES);
-        dumpRepeatedSetting(s, p,
-                Settings.Global.BLUETOOTH_SAP_PRIORITY_PREFIX,
-                GlobalSettingsProto.BLUETOOTH_SAP_PRIORITIES);
-        dumpRepeatedSetting(s, p,
-                Settings.Global.BLUETOOTH_PAN_PRIORITY_PREFIX,
-                GlobalSettingsProto.BLUETOOTH_PAN_PRIORITIES);
-        dumpRepeatedSetting(s, p,
-                Settings.Global.BLUETOOTH_HEARING_AID_PRIORITY_PREFIX,
-                GlobalSettingsProto.BLUETOOTH_HEARING_AID_PRIORITIES);
-        dumpSetting(s, p,
-                Settings.Global.ACTIVITY_MANAGER_CONSTANTS,
-                GlobalSettingsProto.ACTIVITY_MANAGER_CONSTANTS);
-        dumpSetting(s, p,
-                Settings.Global.DEVICE_IDLE_CONSTANTS,
-                GlobalSettingsProto.DEVICE_IDLE_CONSTANTS);
-        dumpSetting(s, p,
-                Settings.Global.BATTERY_SAVER_CONSTANTS,
-                GlobalSettingsProto.BATTERY_SAVER_CONSTANTS);
-        dumpSetting(s, p,
-                Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS,
-                GlobalSettingsProto.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS);
-        dumpSetting(s, p,
-                Settings.Global.BATTERY_TIP_CONSTANTS,
-                GlobalSettingsProto.BATTERY_TIP_CONSTANTS);
-        dumpSetting(s, p,
-                Settings.Global.ANOMALY_DETECTION_CONSTANTS,
-                GlobalSettingsProto.ANOMALY_DETECTION_CONSTANTS);
-        dumpSetting(s, p,
-                Settings.Global.ANOMALY_CONFIG_VERSION,
-                GlobalSettingsProto.ANOMALY_CONFIG_VERSION);
-        dumpSetting(s, p,
-                Settings.Global.ANOMALY_CONFIG,
-                GlobalSettingsProto.ANOMALY_CONFIG);
-        dumpSetting(s, p,
-                Settings.Global.ALWAYS_ON_DISPLAY_CONSTANTS,
-                GlobalSettingsProto.ALWAYS_ON_DISPLAY_CONSTANTS);
-        dumpSetting(s, p,
-                Settings.Global.SYS_VDSO,
-                GlobalSettingsProto.SYS_VDSO);
-        dumpSetting(s, p,
-                Settings.Global.SYS_UIDCPUPOWER,
-                GlobalSettingsProto.SYS_UIDCPUPOWER);
-        dumpSetting(s, p,
-                Settings.Global.FPS_DEVISOR,
-                GlobalSettingsProto.FPS_DIVISOR);
-        dumpSetting(s, p,
-                Settings.Global.DISPLAY_PANEL_LPM,
-                GlobalSettingsProto.DISPLAY_PANEL_LPM);
-        dumpSetting(s, p,
-                Settings.Global.APP_IDLE_CONSTANTS,
-                GlobalSettingsProto.APP_IDLE_CONSTANTS);
-        dumpSetting(s, p,
-                Settings.Global.POWER_MANAGER_CONSTANTS,
-                GlobalSettingsProto.POWER_MANAGER_CONSTANTS);
-        dumpSetting(s, p,
-                Settings.Global.ALARM_MANAGER_CONSTANTS,
-                GlobalSettingsProto.ALARM_MANAGER_CONSTANTS);
-        dumpSetting(s, p,
-                Settings.Global.JOB_SCHEDULER_CONSTANTS,
-                GlobalSettingsProto.JOB_SCHEDULER_CONSTANTS);
-        dumpSetting(s, p,
-                Settings.Global.SHORTCUT_MANAGER_CONSTANTS,
-                GlobalSettingsProto.SHORTCUT_MANAGER_CONSTANTS);
-        dumpSetting(s, p,
-                Settings.Global.DEVICE_POLICY_CONSTANTS,
-                GlobalSettingsProto.DEVICE_POLICY_CONSTANTS);
-        dumpSetting(s, p,
-                Settings.Global.TEXT_CLASSIFIER_CONSTANTS,
-                GlobalSettingsProto.TEXT_CLASSIFIER_CONSTANTS);
-        dumpSetting(s, p,
-                Settings.Global.BATTERY_STATS_CONSTANTS,
-                GlobalSettingsProto.BATTERY_STATS_CONSTANTS);
-        dumpSetting(s, p,
-                Settings.Global.SYNC_MANAGER_CONSTANTS,
-                GlobalSettingsProto.SYNC_MANAGER_CONSTANTS);
-        dumpSetting(s, p,
-                Settings.Global.APP_STANDBY_ENABLED,
-                GlobalSettingsProto.APP_STANDBY_ENABLED);
-        dumpSetting(s, p,
-                Settings.Global.APP_AUTO_RESTRICTION_ENABLED,
-                GlobalSettingsProto.APP_AUTO_RESTRICTION_ENABLED);
-        dumpSetting(s, p,
-                Settings.Global.FORCED_APP_STANDBY_ENABLED,
-                GlobalSettingsProto.FORCED_APP_STANDBY_ENABLED);
-        dumpSetting(s, p,
-                Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED,
-                GlobalSettingsProto.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED);
-        dumpSetting(s, p,
-                Settings.Global.OFF_BODY_RADIOS_OFF_FOR_SMALL_BATTERY_ENABLED,
-                GlobalSettingsProto.OFF_BODY_RADIOS_OFF_FOR_SMALL_BATTERY_ENABLED);
-        dumpSetting(s, p,
-                Settings.Global.OFF_BODY_RADIOS_OFF_DELAY_MS,
-                GlobalSettingsProto.OFF_BODY_RADIOS_OFF_DELAY_MS);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_ON_WHEN_PROXY_DISCONNECTED,
-                GlobalSettingsProto.WIFI_ON_WHEN_PROXY_DISCONNECTED);
-        dumpSetting(s, p,
-                Settings.Global.TIME_ONLY_MODE_CONSTANTS,
-                GlobalSettingsProto.TIME_ONLY_MODE_CONSTANTS);
-        dumpSetting(s, p,
-                Settings.Global.NETWORK_WATCHLIST_ENABLED,
-                GlobalSettingsProto.NETWORK_WATCHLIST_ENABLED);
-        dumpSetting(s, p,
-                Settings.Global.KEEP_PROFILE_IN_BACKGROUND,
-                GlobalSettingsProto.KEEP_PROFILE_IN_BACKGROUND);
-        dumpSetting(s, p,
-                Settings.Global.WINDOW_ANIMATION_SCALE,
-                GlobalSettingsProto.WINDOW_ANIMATION_SCALE);
-        dumpSetting(s, p,
-                Settings.Global.TRANSITION_ANIMATION_SCALE,
-                GlobalSettingsProto.TRANSITION_ANIMATION_SCALE);
-        dumpSetting(s, p,
-                Settings.Global.ANIMATOR_DURATION_SCALE,
-                GlobalSettingsProto.ANIMATOR_DURATION_SCALE);
-        dumpSetting(s, p,
-                Settings.Global.FANCY_IME_ANIMATIONS,
-                GlobalSettingsProto.FANCY_IME_ANIMATIONS);
-        dumpSetting(s, p,
-                Settings.Global.COMPATIBILITY_MODE,
-                GlobalSettingsProto.COMPATIBILITY_MODE);
-        dumpSetting(s, p,
-                Settings.Global.EMERGENCY_TONE,
-                GlobalSettingsProto.EMERGENCY_TONE);
-        dumpSetting(s, p,
-                Settings.Global.CALL_AUTO_RETRY,
-                GlobalSettingsProto.CALL_AUTO_RETRY);
-        dumpSetting(s, p,
-                Settings.Global.EMERGENCY_AFFORDANCE_NEEDED,
-                GlobalSettingsProto.EMERGENCY_AFFORDANCE_NEEDED);
-        dumpSetting(s, p,
-                Settings.Global.PREFERRED_NETWORK_MODE,
-                GlobalSettingsProto.PREFERRED_NETWORK_MODE);
-        dumpSetting(s, p,
-                Settings.Global.DEBUG_APP,
-                GlobalSettingsProto.DEBUG_APP);
-        dumpSetting(s, p,
-                Settings.Global.WAIT_FOR_DEBUGGER,
-                GlobalSettingsProto.WAIT_FOR_DEBUGGER);
-        dumpSetting(s, p,
-                Settings.Global.ENABLE_GPU_DEBUG_LAYERS,
-                GlobalSettingsProto.ENABLE_GPU_DEBUG_LAYERS);
-        dumpSetting(s, p,
-                Settings.Global.GPU_DEBUG_APP,
-                GlobalSettingsProto.GPU_DEBUG_APP);
-        dumpSetting(s, p,
-                Settings.Global.GPU_DEBUG_LAYERS,
-                GlobalSettingsProto.GPU_DEBUG_LAYERS);
-        // Settings.Global.SHOW_PROCESSES intentionally excluded since it's deprecated.
-        dumpSetting(s, p,
-                Settings.Global.LOW_POWER_MODE,
-                GlobalSettingsProto.LOW_POWER_MODE);
-        dumpSetting(s, p,
-                Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL,
-                GlobalSettingsProto.LOW_POWER_MODE_TRIGGER_LEVEL);
-        dumpSetting(s, p,
-                Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL_MAX,
-                GlobalSettingsProto.LOW_POWER_MODE_TRIGGER_LEVEL_MAX);
-        dumpSetting(s, p,
-                Settings.Global.ALWAYS_FINISH_ACTIVITIES,
-                GlobalSettingsProto.ALWAYS_FINISH_ACTIVITIES);
-        dumpSetting(s, p,
-                Settings.Global.DOCK_AUDIO_MEDIA_ENABLED,
-                GlobalSettingsProto.DOCK_AUDIO_MEDIA_ENABLED);
-        dumpSetting(s, p,
-                Settings.Global.ENCODED_SURROUND_OUTPUT,
-                GlobalSettingsProto.ENCODED_SURROUND_OUTPUT);
-        dumpSetting(s, p,
-                Settings.Global.AUDIO_SAFE_VOLUME_STATE,
-                GlobalSettingsProto.AUDIO_SAFE_VOLUME_STATE);
-        dumpSetting(s, p,
-                Settings.Global.TZINFO_UPDATE_CONTENT_URL,
-                GlobalSettingsProto.TZINFO_UPDATE_CONTENT_URL);
-        dumpSetting(s, p,
-                Settings.Global.TZINFO_UPDATE_METADATA_URL,
-                GlobalSettingsProto.TZINFO_UPDATE_METADATA_URL);
-        dumpSetting(s, p,
-                Settings.Global.SELINUX_UPDATE_CONTENT_URL,
-                GlobalSettingsProto.SELINUX_UPDATE_CONTENT_URL);
-        dumpSetting(s, p,
-                Settings.Global.SELINUX_UPDATE_METADATA_URL,
-                GlobalSettingsProto.SELINUX_UPDATE_METADATA_URL);
-        dumpSetting(s, p,
-                Settings.Global.SMS_SHORT_CODES_UPDATE_CONTENT_URL,
-                GlobalSettingsProto.SMS_SHORT_CODES_UPDATE_CONTENT_URL);
-        dumpSetting(s, p,
-                Settings.Global.SMS_SHORT_CODES_UPDATE_METADATA_URL,
-                GlobalSettingsProto.SMS_SHORT_CODES_UPDATE_METADATA_URL);
-        dumpSetting(s, p,
-                Settings.Global.APN_DB_UPDATE_CONTENT_URL,
-                GlobalSettingsProto.APN_DB_UPDATE_CONTENT_URL);
-        dumpSetting(s, p,
-                Settings.Global.APN_DB_UPDATE_METADATA_URL,
-                GlobalSettingsProto.APN_DB_UPDATE_METADATA_URL);
-        dumpSetting(s, p,
-                Settings.Global.CERT_PIN_UPDATE_CONTENT_URL,
-                GlobalSettingsProto.CERT_PIN_UPDATE_CONTENT_URL);
-        dumpSetting(s, p,
-                Settings.Global.CERT_PIN_UPDATE_METADATA_URL,
-                GlobalSettingsProto.CERT_PIN_UPDATE_METADATA_URL);
-        dumpSetting(s, p,
-                Settings.Global.INTENT_FIREWALL_UPDATE_CONTENT_URL,
-                GlobalSettingsProto.INTENT_FIREWALL_UPDATE_CONTENT_URL);
-        dumpSetting(s, p,
-                Settings.Global.INTENT_FIREWALL_UPDATE_METADATA_URL,
-                GlobalSettingsProto.INTENT_FIREWALL_UPDATE_METADATA_URL);
-        dumpSetting(s, p,
-                Settings.Global.LANG_ID_UPDATE_CONTENT_URL,
-                GlobalSettingsProto.LANG_ID_UPDATE_CONTENT_URL);
-        dumpSetting(s, p,
-                Settings.Global.LANG_ID_UPDATE_METADATA_URL,
-                GlobalSettingsProto.LANG_ID_UPDATE_METADATA_URL);
-        dumpSetting(s, p,
-                Settings.Global.SMART_SELECTION_UPDATE_CONTENT_URL,
-                GlobalSettingsProto.SMART_SELECTION_UPDATE_CONTENT_URL);
-        dumpSetting(s, p,
-                Settings.Global.SMART_SELECTION_UPDATE_METADATA_URL,
-                GlobalSettingsProto.SMART_SELECTION_UPDATE_METADATA_URL);
-        dumpSetting(s, p,
-                Settings.Global.SELINUX_STATUS,
-                GlobalSettingsProto.SELINUX_STATUS);
-        dumpSetting(s, p,
-                Settings.Global.DEVELOPMENT_FORCE_RTL,
-                GlobalSettingsProto.DEVELOPMENT_FORCE_RTL);
-        dumpSetting(s, p,
-                Settings.Global.LOW_BATTERY_SOUND_TIMEOUT,
-                GlobalSettingsProto.LOW_BATTERY_SOUND_TIMEOUT);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_BOUNCE_DELAY_OVERRIDE_MS,
-                GlobalSettingsProto.WIFI_BOUNCE_DELAY_OVERRIDE_MS);
-        dumpSetting(s, p,
-                Settings.Global.POLICY_CONTROL,
-                GlobalSettingsProto.POLICY_CONTROL);
-        dumpSetting(s, p,
-                Settings.Global.EMULATE_DISPLAY_CUTOUT,
-                GlobalSettingsProto.EMULATE_DISPLAY_CUTOUT);
-        dumpSetting(s, p,
-                Settings.Global.ZEN_MODE,
-                GlobalSettingsProto.ZEN_MODE);
-        dumpSetting(s, p,
-                Settings.Global.ZEN_MODE_RINGER_LEVEL,
-                GlobalSettingsProto.ZEN_MODE_RINGER_LEVEL);
-        dumpSetting(s, p,
-                Settings.Global.ZEN_MODE_CONFIG_ETAG,
-                GlobalSettingsProto.ZEN_MODE_CONFIG_ETAG);
-        dumpSetting(s, p,
-                Settings.Global.ZEN_DURATION,
-                GlobalSettingsProto.ZEN_DURATION);
-        dumpSetting(s, p,
-                Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
-                GlobalSettingsProto.HEADS_UP_NOTIFICATIONS_ENABLED);
-        dumpSetting(s, p,
-                Settings.Global.DEVICE_NAME,
-                GlobalSettingsProto.DEVICE_NAME);
-        dumpSetting(s, p,
-                Settings.Global.NETWORK_SCORING_PROVISIONED,
-                GlobalSettingsProto.NETWORK_SCORING_PROVISIONED);
-        dumpSetting(s, p,
-                Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT,
-                GlobalSettingsProto.REQUIRE_PASSWORD_TO_DECRYPT);
-        dumpSetting(s, p,
-                Settings.Global.ENHANCED_4G_MODE_ENABLED,
-                GlobalSettingsProto.ENHANCED_4G_MODE_ENABLED);
-        dumpSetting(s, p,
                 Settings.Global.VT_IMS_ENABLED,
                 GlobalSettingsProto.VT_IMS_ENABLED);
         dumpSetting(s, p,
+                Settings.Global.WAIT_FOR_DEBUGGER,
+                GlobalSettingsProto.WAIT_FOR_DEBUGGER);
+
+        final long webviewToken = p.start(GlobalSettingsProto.WEBVIEW);
+        dumpSetting(s, p,
+                Settings.Global.WEBVIEW_DATA_REDUCTION_PROXY_KEY,
+                GlobalSettingsProto.Webview.DATA_REDUCTION_PROXY_KEY);
+        dumpSetting(s, p,
+                Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED,
+                GlobalSettingsProto.Webview.FALLBACK_LOGIC_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.WEBVIEW_PROVIDER,
+                GlobalSettingsProto.Webview.PROVIDER);
+        dumpSetting(s, p,
+                Settings.Global.WEBVIEW_MULTIPROCESS,
+                GlobalSettingsProto.Webview.MULTIPROCESS);
+        p.end(webviewToken);
+
+        final long wfcToken = p.start(GlobalSettingsProto.WFC);
+        dumpSetting(s, p,
                 Settings.Global.WFC_IMS_ENABLED,
-                GlobalSettingsProto.WFC_IMS_ENABLED);
+                GlobalSettingsProto.Wfc.IMS_ENABLED);
         dumpSetting(s, p,
                 Settings.Global.WFC_IMS_MODE,
-                GlobalSettingsProto.WFC_IMS_MODE);
+                GlobalSettingsProto.Wfc.IMS_MODE);
         dumpSetting(s, p,
                 Settings.Global.WFC_IMS_ROAMING_MODE,
-                GlobalSettingsProto.WFC_IMS_ROAMING_MODE);
+                GlobalSettingsProto.Wfc.IMS_ROAMING_MODE);
         dumpSetting(s, p,
                 Settings.Global.WFC_IMS_ROAMING_ENABLED,
-                GlobalSettingsProto.WFC_IMS_ROAMING_ENABLED);
+                GlobalSettingsProto.Wfc.IMS_ROAMING_ENABLED);
+        p.end(wfcToken);
+
+        final long wifiToken = p.start(GlobalSettingsProto.WIFI);
         dumpSetting(s, p,
-                Settings.Global.LTE_SERVICE_FORCED,
-                GlobalSettingsProto.LTE_SERVICE_FORCED);
+                Settings.Global.WIFI_SLEEP_POLICY,
+                GlobalSettingsProto.Wifi.SLEEP_POLICY);
         dumpSetting(s, p,
-                Settings.Global.EPHEMERAL_COOKIE_MAX_SIZE_BYTES,
-                GlobalSettingsProto.EPHEMERAL_COOKIE_MAX_SIZE_BYTES);
+                Settings.Global.WIFI_BADGING_THRESHOLDS,
+                GlobalSettingsProto.Wifi.BADGING_THRESHOLDS);
         dumpSetting(s, p,
-                Settings.Global.ENABLE_EPHEMERAL_FEATURE,
-                GlobalSettingsProto.ENABLE_EPHEMERAL_FEATURE);
+                Settings.Global.WIFI_DISPLAY_ON,
+                GlobalSettingsProto.Wifi.DISPLAY_ON);
         dumpSetting(s, p,
-                Settings.Global.INSTANT_APP_DEXOPT_ENABLED,
-                GlobalSettingsProto.INSTANT_APP_DEXOPT_ENABLED);
+                Settings.Global.WIFI_DISPLAY_CERTIFICATION_ON,
+                GlobalSettingsProto.Wifi.DISPLAY_CERTIFICATION_ON);
         dumpSetting(s, p,
-                Settings.Global.INSTALLED_INSTANT_APP_MIN_CACHE_PERIOD,
-                GlobalSettingsProto.INSTALLED_INSTANT_APP_MIN_CACHE_PERIOD);
+                Settings.Global.WIFI_DISPLAY_WPS_CONFIG,
+                GlobalSettingsProto.Wifi.DISPLAY_WPS_CONFIG);
         dumpSetting(s, p,
-                Settings.Global.INSTALLED_INSTANT_APP_MAX_CACHE_PERIOD,
-                GlobalSettingsProto.INSTALLED_INSTANT_APP_MAX_CACHE_PERIOD);
+                Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
+                GlobalSettingsProto.Wifi.NETWORKS_AVAILABLE_NOTIFICATION_ON);
         dumpSetting(s, p,
-                Settings.Global.UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD,
-                GlobalSettingsProto.UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD);
+                Settings.Global.WIFI_CARRIER_NETWORKS_AVAILABLE_NOTIFICATION_ON,
+                GlobalSettingsProto.Wifi.CARRIER_NETWORKS_AVAILABLE_NOTIFICATION_ON);
         dumpSetting(s, p,
-                Settings.Global.UNINSTALLED_INSTANT_APP_MAX_CACHE_PERIOD,
-                GlobalSettingsProto.UNINSTALLED_INSTANT_APP_MAX_CACHE_PERIOD);
+                Settings.Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,
+                GlobalSettingsProto.Wifi.NETWORKS_AVAILABLE_REPEAT_DELAY);
         dumpSetting(s, p,
-                Settings.Global.UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD,
-                GlobalSettingsProto.UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD);
+                Settings.Global.WIFI_COUNTRY_CODE,
+                GlobalSettingsProto.Wifi.COUNTRY_CODE);
         dumpSetting(s, p,
-                Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED,
-                GlobalSettingsProto.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED);
+                Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS,
+                GlobalSettingsProto.Wifi.FRAMEWORK_SCAN_INTERVAL_MS);
         dumpSetting(s, p,
-                Settings.Global.BOOT_COUNT,
-                GlobalSettingsProto.BOOT_COUNT);
+                Settings.Global.WIFI_IDLE_MS,
+                GlobalSettingsProto.Wifi.IDLE_MS);
         dumpSetting(s, p,
-                Settings.Global.SAFE_BOOT_DISALLOWED,
-                GlobalSettingsProto.SAFE_BOOT_DISALLOWED);
+                Settings.Global.WIFI_NUM_OPEN_NETWORKS_KEPT,
+                GlobalSettingsProto.Wifi.NUM_OPEN_NETWORKS_KEPT);
         dumpSetting(s, p,
-                Settings.Global.DEVICE_DEMO_MODE,
-                GlobalSettingsProto.DEVICE_DEMO_MODE);
+                Settings.Global.WIFI_ON,
+                GlobalSettingsProto.Wifi.ON);
         dumpSetting(s, p,
-                Settings.Global.NETWORK_ACCESS_TIMEOUT_MS,
-                GlobalSettingsProto.NETWORK_ACCESS_TIMEOUT_MS);
+                Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE,
+                GlobalSettingsProto.Wifi.SCAN_ALWAYS_AVAILABLE);
         dumpSetting(s, p,
-                Settings.Global.DATABASE_DOWNGRADE_REASON,
-                GlobalSettingsProto.DATABASE_DOWNGRADE_REASON);
+                Settings.Global.WIFI_WAKEUP_ENABLED,
+                GlobalSettingsProto.Wifi.WAKEUP_ENABLED);
         dumpSetting(s, p,
-                Settings.Global.DATABASE_CREATION_BUILDID,
-                GlobalSettingsProto.DATABASE_CREATION_BUILDID);
+                Settings.Global.WIFI_SAVED_STATE,
+                GlobalSettingsProto.Wifi.SAVED_STATE);
         dumpSetting(s, p,
-                Settings.Global.CONTACTS_DATABASE_WAL_ENABLED,
-                GlobalSettingsProto.CONTACTS_DATABASE_WAL_ENABLED);
+                Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,
+                GlobalSettingsProto.Wifi.SUPPLICANT_SCAN_INTERVAL_MS);
         dumpSetting(s, p,
-                Settings.Global.LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED,
-                GlobalSettingsProto.LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED);
+                Settings.Global.WIFI_ENHANCED_AUTO_JOIN,
+                GlobalSettingsProto.Wifi.ENHANCED_AUTO_JOIN);
         dumpSetting(s, p,
-                Settings.Global.EUICC_FACTORY_RESET_TIMEOUT_MILLIS,
-                GlobalSettingsProto.EUICC_FACTORY_RESET_TIMEOUT_MILLIS);
+                Settings.Global.WIFI_NETWORK_SHOW_RSSI,
+                GlobalSettingsProto.Wifi.NETWORK_SHOW_RSSI);
         dumpSetting(s, p,
-                Settings.Global.STORAGE_SETTINGS_CLOBBER_THRESHOLD,
-                GlobalSettingsProto.STORAGE_SETTINGS_CLOBBER_THRESHOLD);
+                Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS,
+                GlobalSettingsProto.Wifi.SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS);
         dumpSetting(s, p,
-                Settings.Global.LOCATION_GLOBAL_KILL_SWITCH,
-                GlobalSettingsProto.LOCATION_GLOBAL_KILL_SWITCH);
+                Settings.Global.WIFI_WATCHDOG_ON,
+                GlobalSettingsProto.Wifi.WATCHDOG_ON);
         dumpSetting(s, p,
-                Settings.Global.OVERRIDE_SETTINGS_PROVIDER_RESTORE_ANY_VERSION,
-                GlobalSettingsProto.OVERRIDE_SETTINGS_PROVIDER_RESTORE_ANY_VERSION);
+                Settings.Global.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED,
+                GlobalSettingsProto.Wifi.WATCHDOG_POOR_NETWORK_TEST_ENABLED);
         dumpSetting(s, p,
-                Global.CHAINED_BATTERY_ATTRIBUTION_ENABLED,
-                GlobalSettingsProto.CHAINED_BATTERY_ATTRIBUTION_ENABLED);
+                Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED,
+                GlobalSettingsProto.Wifi.SUSPEND_OPTIMIZATIONS_ENABLED);
         dumpSetting(s, p,
-                Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES,
-                GlobalSettingsProto.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES);
+                Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED,
+                GlobalSettingsProto.Wifi.VERBOSE_LOGGING_ENABLED);
         dumpSetting(s, p,
-                Global.HIDDEN_API_BLACKLIST_EXEMPTIONS,
-                GlobalSettingsProto.HIDDEN_API_BLACKLIST_EXEMPTIONS);
+                Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED,
+                GlobalSettingsProto.Wifi.CONNECTED_MAC_RANDOMIZATION_ENABLED);
         dumpSetting(s, p,
-                Global.SOUND_TRIGGER_DETECTION_SERVICE_OP_TIMEOUT,
-                GlobalSettingsProto.SOUND_TRIGGER_DETECTION_SERVICE_OP_TIMEOUT);
+                Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT,
+                GlobalSettingsProto.Wifi.MAX_DHCP_RETRY_COUNT);
         dumpSetting(s, p,
-                Global.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY,
-                GlobalSettingsProto.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY);
+                Settings.Global.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS,
+                GlobalSettingsProto.Wifi.MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS);
         dumpSetting(s, p,
-                Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION,
-                GlobalSettingsProto.MULTI_SIM_VOICE_CALL_SUBSCRIPTION);
+                Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN,
+                GlobalSettingsProto.Wifi.DEVICE_OWNER_CONFIGS_LOCKDOWN);
         dumpSetting(s, p,
-                Settings.Global.MULTI_SIM_VOICE_PROMPT,
-                GlobalSettingsProto.MULTI_SIM_VOICE_PROMPT);
+                Settings.Global.WIFI_FREQUENCY_BAND,
+                GlobalSettingsProto.Wifi.FREQUENCY_BAND);
         dumpSetting(s, p,
-                Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION,
-                GlobalSettingsProto.MULTI_SIM_DATA_CALL_SUBSCRIPTION);
+                Settings.Global.WIFI_P2P_DEVICE_NAME,
+                GlobalSettingsProto.Wifi.P2P_DEVICE_NAME);
         dumpSetting(s, p,
-                Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION,
-                GlobalSettingsProto.MULTI_SIM_SMS_SUBSCRIPTION);
+                Settings.Global.WIFI_REENABLE_DELAY_MS,
+                GlobalSettingsProto.Wifi.REENABLE_DELAY_MS);
         dumpSetting(s, p,
-                Settings.Global.MULTI_SIM_SMS_PROMPT,
-                GlobalSettingsProto.MULTI_SIM_SMS_PROMPT);
+                Settings.Global.WIFI_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS,
+                GlobalSettingsProto.Wifi.EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS);
         dumpSetting(s, p,
-                Settings.Global.NEW_CONTACT_AGGREGATOR,
-                GlobalSettingsProto.NEW_CONTACT_AGGREGATOR);
-        // Settings.Global.CONTACT_METADATA_SYNC intentionally excluded since it's deprecated.
+                Settings.Global.WIFI_ON_WHEN_PROXY_DISCONNECTED,
+                GlobalSettingsProto.Wifi.ON_WHEN_PROXY_DISCONNECTED);
         dumpSetting(s, p,
-                Settings.Global.CONTACT_METADATA_SYNC_ENABLED,
-                GlobalSettingsProto.CONTACT_METADATA_SYNC_ENABLED);
+                Settings.Global.WIFI_BOUNCE_DELAY_OVERRIDE_MS,
+                GlobalSettingsProto.Wifi.BOUNCE_DELAY_OVERRIDE_MS);
+        p.end(wifiToken);
+
         dumpSetting(s, p,
-                Settings.Global.ENABLE_CELLULAR_ON_BOOT,
-                GlobalSettingsProto.ENABLE_CELLULAR_ON_BOOT);
+                Settings.Global.WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON,
+                GlobalSettingsProto.WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON);
         dumpSetting(s, p,
-                Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
-                GlobalSettingsProto.MAX_NOTIFICATION_ENQUEUE_RATE);
+                Settings.Global.WINDOW_ANIMATION_SCALE,
+                GlobalSettingsProto.WINDOW_ANIMATION_SCALE);
         dumpSetting(s, p,
-                Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS,
-                GlobalSettingsProto.SHOW_NOTIFICATION_CHANNEL_WARNINGS);
+                Settings.Global.WTF_IS_FATAL,
+                GlobalSettingsProto.WTF_IS_FATAL);
+
+        final long zenToken = p.start(GlobalSettingsProto.ZEN);
         dumpSetting(s, p,
-                Settings.Global.CELL_ON,
-                GlobalSettingsProto.CELL_ON);
+                Settings.Global.ZEN_MODE,
+                GlobalSettingsProto.Zen.MODE);
         dumpSetting(s, p,
-                Settings.Global.SHOW_TEMPERATURE_WARNING,
-                GlobalSettingsProto.SHOW_TEMPERATURE_WARNING);
+                Settings.Global.ZEN_MODE_RINGER_LEVEL,
+                GlobalSettingsProto.Zen.MODE_RINGER_LEVEL);
         dumpSetting(s, p,
-                Settings.Global.WARNING_TEMPERATURE,
-                GlobalSettingsProto.WARNING_TEMPERATURE);
+                Settings.Global.ZEN_MODE_CONFIG_ETAG,
+                GlobalSettingsProto.Zen.MODE_CONFIG_ETAG);
         dumpSetting(s, p,
-                Settings.Global.ENABLE_DISKSTATS_LOGGING,
-                GlobalSettingsProto.ENABLE_DISKSTATS_LOGGING);
+                Settings.Global.ZEN_DURATION,
+                GlobalSettingsProto.Zen.DURATION);
         dumpSetting(s, p,
-                Settings.Global.ENABLE_CACHE_QUOTA_CALCULATION,
-                GlobalSettingsProto.ENABLE_CACHE_QUOTA_CALCULATION);
-        dumpSetting(s, p,
-                Settings.Global.ENABLE_DELETION_HELPER_NO_THRESHOLD_TOGGLE,
-                GlobalSettingsProto.ENABLE_DELETION_HELPER_NO_THRESHOLD_TOGGLE);
-        // The list of snooze options for notifications. This is encoded as a key=value list,
-        // separated by commas.
-        dumpSetting(s, p,
-                Settings.Global.NOTIFICATION_SNOOZE_OPTIONS,
-                GlobalSettingsProto.NOTIFICATION_SNOOZE_OPTIONS);
-        dumpSetting(s, p,
-                Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS,
-                GlobalSettingsProto.SQLITE_COMPATIBILITY_WAL_FLAGS);
-        dumpSetting(s, p,
-                Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
-                GlobalSettingsProto.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING);
-        dumpSetting(s, p,
-                Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT,
-                GlobalSettingsProto.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT);
-        dumpSetting(s, p,
-                Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS,
-                GlobalSettingsProto.INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS);
+                Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION,
+                GlobalSettingsProto.Zen.SHOW_ZEN_UPGRADE_NOTIFICATION);
+        p.end(zenToken);
+
         dumpSetting(s, p,
                 Settings.Global.ZRAM_ENABLED,
                 GlobalSettingsProto.ZRAM_ENABLED);
-        dumpSetting(s, p,
-                Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS,
-                GlobalSettingsProto.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS);
-        dumpSetting(s, p,
-                Settings.Global.SHOW_FIRST_CRASH_DIALOG,
-                GlobalSettingsProto.SHOW_FIRST_CRASH_DIALOG);
-        dumpSetting(s, p,
-                Settings.Global.SHOW_RESTART_IN_CRASH_DIALOG,
-                GlobalSettingsProto.SHOW_RESTART_IN_CRASH_DIALOG);
-        dumpSetting(s, p,
-                Settings.Global.SHOW_MUTE_IN_CRASH_DIALOG,
-                GlobalSettingsProto.SHOW_MUTE_IN_CRASH_DIALOG);
-        dumpSetting(s, p,
-                Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION,
-                GlobalSettingsProto.SHOW_ZEN_UPGRADE_NOTIFICATION);
-        dumpSetting(s, p,
-                Settings.Global.BACKUP_AGENT_TIMEOUT_PARAMETERS,
-                GlobalSettingsProto.BACKUP_AGENT_TIMEOUT_PARAMETERS);
-        // Please insert new settings using the same order as in Settings.Global.
 
         p.end(token);
+        // Please insert new settings using the same order as in GlobalSettingsProto.
+
+        // Settings.Global.INSTALL_NON_MARKET_APPS intentionally excluded since it's deprecated.
     }
 
     /** Dumps settings that use a common prefix into a repeated field. */
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 3a2ec06..a6d6250 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2754,12 +2754,17 @@
             mGenerationRegistry.incrementGeneration(key);
 
             if (isGlobalSettingsKey(key)) {
-                if (Global.LOCATION_GLOBAL_KILL_SWITCH.equals(name)) {
-                    // When the global kill switch is updated, send the
-                    // change notification for the location setting.
-                    notifyLocationChangeForRunningUsers();
+                final long token = Binder.clearCallingIdentity();
+                try {
+                    if (Global.LOCATION_GLOBAL_KILL_SWITCH.equals(name)) {
+                        // When the global kill switch is updated, send the
+                        // change notification for the location setting.
+                        notifyLocationChangeForRunningUsers();
+                    }
+                    notifyGlobalSettingChangeForRunningUsers(key, name);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
                 }
-                notifyGlobalSettingChangeForRunningUsers(key, name);
             } else {
                 final int userId = getUserIdFromKey(key);
                 final Uri uri = getNotificationUriFor(key, name);
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index ea1ad2d1..ef18725 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -22,6 +22,7 @@
     android:layout_width="match_parent"
     android:layout_height="@dimen/qs_footer_height"
     android:elevation="4dp"
+    android:background="@android:color/transparent"
     android:baselineAligned="false"
     android:clickable="false"
     android:clipChildren="false"
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 1c9ce18..72ff653 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -56,9 +56,9 @@
         android:layout_height="wrap_content"
         android:layout_marginBottom="@dimen/qs_footer_height"
         android:elevation="4dp"
+        android:background="@android:color/transparent"
     />
 
-
     <include layout="@layout/quick_status_bar_expanded_header" />
 
     <include layout="@layout/qs_footer_impl" />
diff --git a/packages/SystemUI/res/layout/qs_tile_label.xml b/packages/SystemUI/res/layout/qs_tile_label.xml
index b138df0..74c22b0 100644
--- a/packages/SystemUI/res/layout/qs_tile_label.xml
+++ b/packages/SystemUI/res/layout/qs_tile_label.xml
@@ -44,7 +44,7 @@
             android:maxLines="2"
             android:padding="0dp"
             android:gravity="center"
-            android:ellipsize="end"
+            android:ellipsize="marquee"
             android:textAppearance="@style/TextAppearance.QS.TileLabel"
             android:textColor="?android:attr/textColorPrimary"/>
 
@@ -75,6 +75,7 @@
         android:layout_alignEnd="@id/label_group"
         android:layout_below="@id/label_group"
         android:clickable="false"
+        android:ellipsize="marquee"
         android:maxLines="1"
         android:padding="0dp"
         android:visibility="gone"
diff --git a/packages/SystemUI/res/layout/status_bar_notification_dismiss_all.xml b/packages/SystemUI/res/layout/status_bar_notification_footer.xml
similarity index 63%
rename from packages/SystemUI/res/layout/status_bar_notification_dismiss_all.xml
rename to packages/SystemUI/res/layout/status_bar_notification_footer.xml
index 8dc4cb4..aa0d4a0 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_dismiss_all.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_footer.xml
@@ -15,13 +15,27 @@
   -->
 
 <!-- Extends Framelayout -->
-<com.android.systemui.statusbar.DismissView
+<com.android.systemui.statusbar.FooterView
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:paddingEnd="8dp"
         android:visibility="gone">
-    <com.android.systemui.statusbar.DismissViewButton
+    <FrameLayout
+        android:id="@+id/content"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" >
+        <com.android.systemui.statusbar.FooterViewButton
+            style="@android:style/Widget.Material.Button.Borderless"
+            android:id="@+id/manage_text"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="start"
+            android:focusable="true"
+            android:text="@string/manage_notifications_text"
+            android:textColor="?attr/wallpaperTextColor"
+            android:textAllCaps="false"/>
+        <com.android.systemui.statusbar.FooterViewButton
             style="@android:style/Widget.Material.Button.Borderless"
             android:id="@+id/dismiss_text"
             android:layout_width="wrap_content"
@@ -32,4 +46,5 @@
             android:text="@string/clear_all_notifications_text"
             android:textColor="?attr/wallpaperTextColor"
             android:textAllCaps="true"/>
-</com.android.systemui.statusbar.DismissView>
+    </FrameLayout>
+</com.android.systemui.statusbar.FooterView>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index e37ca1c..c59492f 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -24,6 +24,8 @@
 
     <dimen name="brightness_mirror_height">96dp</dimen>
 
+    <!-- Width for the spacer, used between QS tiles. -->
+    <dimen name="qs_quick_tile_space_width">38dp</dimen>
     <dimen name="qs_tile_margin_top">2dp</dimen>
     <dimen name="qs_header_tooltip_height">24dp</dimen>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index ff3f696..91c8724 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -317,6 +317,8 @@
     <dimen name="qs_tile_margin_vertical">24dp</dimen>
     <dimen name="qs_tile_margin_top">18dp</dimen>
     <dimen name="qs_quick_tile_size">48dp</dimen>
+    <!-- Width for the spacer, used between QS tiles. -->
+    <dimen name="qs_quick_tile_space_width">0dp</dimen>
     <dimen name="qs_quick_tile_padding">12dp</dimen>
     <dimen name="qs_header_gear_translation">16dp</dimen>
     <dimen name="qs_header_tile_margin_horizontal">0dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 131b35c..909c18b 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -191,16 +191,14 @@
     <string name="screenshot_saving_ticker">Saving screenshot\u2026</string>
     <!-- Notification title displayed when a screenshot is being saved to the Gallery. [CHAR LIMIT=50] -->
     <string name="screenshot_saving_title">Saving screenshot\u2026</string>
-    <!-- Notification text displayed when a screenshot is being saved to the Gallery. [CHAR LIMIT=100] -->
-    <string name="screenshot_saving_text">Screenshot is being saved</string>
     <!-- Notification title displayed when a screenshot is saved to the Gallery. [CHAR LIMIT=50] -->
     <string name="screenshot_saved_title">Screenshot saved</string>
     <!-- Notification text displayed when a screenshot is saved to the Gallery. [CHAR LIMIT=100] -->
     <string name="screenshot_saved_text">Tap to view your screenshot</string>
     <!-- Notification title displayed when we fail to take a screenshot. [CHAR LIMIT=50] -->
-    <string name="screenshot_failed_title">Couldn\'t capture screenshot</string>
+    <string name="screenshot_failed_title">Couldn\'t save screenshot</string>
     <!-- Notification text displayed when we fail to save a screenshot for unknown reasons. [CHAR LIMIT=100] -->
-    <string name="screenshot_failed_to_save_unknown_text">Problem encountered while saving screenshot</string>
+    <string name="screenshot_failed_to_save_unknown_text">Try taking screenshot again</string>
     <!-- Notification text displayed when we fail to save a screenshot. [CHAR LIMIT=100] -->
     <string name="screenshot_failed_to_save_text">Can\'t save screenshot due to limited storage space</string>
     <!-- Notification text displayed when we fail to take a screenshot. [CHAR LIMIT=100] -->
@@ -1055,6 +1053,9 @@
     <!-- The text to clear all notifications. [CHAR LIMIT=60] -->
     <string name="clear_all_notifications_text">Clear all</string>
 
+    <!-- The text for the manage notifications link. [CHAR LIMIT=40] -->
+    <string name="manage_notifications_text">Manage notifications</string>
+
     <!-- The text to show in the notifications shade when dnd is suppressing notifications. [CHAR LIMIT=100] -->
     <string name="dnd_suppressing_shade_text">Do Not disturb is hiding notifications</string>
 
@@ -1602,7 +1603,7 @@
     <!-- Notification: Menu row: Content description for the snooze icon. [CHAR LIMIT=NONE] -->
     <string name="notification_menu_snooze_description">notification snooze options</string>
 
-    <!-- Notification: Menu row: Content description for the snooze action shown in local context menu. [CHAR LIMIT=NONE] -->
+    <!-- Notification: Menu row: Label for the snooze action shown in local context menu. [CHAR LIMIT=NONE] -->
     <string name="notification_menu_snooze_action">Snooze</string>
 
     <!-- Notification: Snooze panel: Snooze undo button label. [CHAR LIMIT=50]-->
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
index 62b5004..5b4d652 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
@@ -137,6 +137,10 @@
         mCancelAction = cancelAction;
     }
 
+    public boolean hasDismissActions() {
+        return mDismissAction != null || mCancelAction != null;
+    }
+
     public void cancelDismissAction() {
         setOnDismissAction(null, null);
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index d24675c..1bab36b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -68,7 +68,6 @@
 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
 import android.telephony.TelephonyManager;
 import android.util.Log;
-import android.util.Slog;
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 
@@ -88,6 +87,7 @@
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map.Entry;
 
@@ -400,16 +400,9 @@
         // Hack level over 9000: Because the subscription id is not yet valid when we see the
         // first update in handleSimStateChange, we need to force refresh all all SIM states
         // so the subscription id for them is consistent.
-        ArrayList<SubscriptionInfo> changedSubscriptions = new ArrayList<>();
-        for (int i = 0; i < subscriptionInfos.size(); i++) {
-            SubscriptionInfo info = subscriptionInfos.get(i);
-            boolean changed = refreshSimState(info.getSubscriptionId(), info.getSimSlotIndex());
-            if (changed) {
-                changedSubscriptions.add(info);
-            }
-        }
-        for (int i = 0; i < changedSubscriptions.size(); i++) {
-            SimData data = mSimDatas.get(changedSubscriptions.get(i).getSubscriptionId());
+        List<Integer> changedSubscriptionIds = refreshSimState(subscriptionInfos);
+        for (int i = 0; i < changedSubscriptionIds.size(); i++) {
+            SimData data = mSimDatas.get(changedSubscriptionIds.get(i));
             for (int j = 0; j < mCallbacks.size(); j++) {
                 KeyguardUpdateMonitorCallback cb = mCallbacks.get(j).get();
                 if (cb != null) {
@@ -1846,34 +1839,56 @@
     };
 
     /**
-     * @return true if and only if the state has changed for the specified {@code slotId}
+     * @return A list of changed subscriptions, maybe empty but never null
      */
-    private boolean refreshSimState(int subId, int slotId) {
+    private List<Integer> refreshSimState(final List<SubscriptionInfo> activeSubscriptionInfos) {
 
         // This is awful. It exists because there are two APIs for getting the SIM status
         // that don't return the complete set of values and have different types. In Keyguard we
         // need IccCardConstants, but TelephonyManager would only give us
         // TelephonyManager.SIM_STATE*, so we retrieve it manually.
         final TelephonyManager tele = TelephonyManager.from(mContext);
-        int simState =  tele.getSimState(slotId);
-        State state;
-        try {
-            state = State.intToState(simState);
-        } catch(IllegalArgumentException ex) {
-            Log.w(TAG, "Unknown sim state: " + simState);
-            state = State.UNKNOWN;
+        ArrayList<Integer> changedSubscriptionIds = new ArrayList<>();
+        HashSet<Integer> activeSubIds = new HashSet<>();
+
+        for (SubscriptionInfo info : activeSubscriptionInfos) {
+            int subId = info.getSubscriptionId();
+            int slotId = info.getSimSlotIndex();
+            int simState =  tele.getSimState(slotId);
+            State state;
+            try {
+                state = State.intToState(simState);
+            } catch(IllegalArgumentException ex) {
+                Log.w(TAG, "Unknown sim state: " + simState);
+                state = State.UNKNOWN;
+            }
+
+            SimData data = mSimDatas.get(subId);
+            final boolean changed;
+            if (data == null) {
+                data = new SimData(state, slotId, subId);
+                mSimDatas.put(subId, data);
+                changed = true;               // no data yet; force update
+            } else {
+                changed = data.simState != state;
+                data.simState = state;
+            }
+            if (changed) {
+                changedSubscriptionIds.add(subId);
+            }
+
+            activeSubIds.add(subId);
         }
-        SimData data = mSimDatas.get(subId);
-        final boolean changed;
-        if (data == null) {
-            data = new SimData(state, slotId, subId);
-            mSimDatas.put(subId, data);
-            changed = true; // no data yet; force update
-        } else {
-            changed = data.simState != state;
-            data.simState = state;
+
+        for (SimData data : mSimDatas.values()) {
+            if (!activeSubIds.contains(data.subId) && data.simState != State.ABSENT) {
+                // for the inactive subscriptions, reset state to ABSENT
+                data.simState = State.ABSENT;
+                changedSubscriptionIds.add(data.subId);
+            }
         }
-        return changed;
+
+        return changedSubscriptionIds;
     }
 
     public static boolean isSimPinSecure(IccCardConstants.State state) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 2270b60..c9c04d9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -17,6 +17,7 @@
 package com.android.systemui.qs;
 
 import android.content.Context;
+import android.content.res.Configuration;
 import android.util.AttributeSet;
 import android.view.Gravity;
 import android.view.View;
@@ -179,16 +180,56 @@
 
         protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
         private boolean mListening;
+        /** Size of the QS tile (width & height). */
+        private int mTileDimensionSize;
 
         public HeaderTileLayout(Context context) {
             super(context);
             setClipChildren(false);
             setClipToPadding(false);
-            setGravity(Gravity.CENTER_VERTICAL);
+
+            mTileDimensionSize = mContext.getResources().getDimensionPixelSize(
+                    R.dimen.qs_quick_tile_size);
+
+            setGravity(Gravity.CENTER);
             setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
         }
 
         @Override
+        protected void onConfigurationChanged(Configuration newConfig) {
+            super.onConfigurationChanged(newConfig);
+
+            setGravity(Gravity.CENTER);
+            LayoutParams staticSpaceLayoutParams = generateSpaceLayoutParams(
+                    mContext.getResources().getDimensionPixelSize(
+                            R.dimen.qs_quick_tile_space_width));
+
+            // Update space params since they fill any open space in portrait orientation and have
+            // a static width in landscape orientation.
+            final int childViewCount = getChildCount();
+            for (int i = 0; i < childViewCount; i++) {
+                View childView = getChildAt(i);
+                if (childView instanceof Space) {
+                    childView.setLayoutParams(staticSpaceLayoutParams);
+                }
+            }
+        }
+
+        /**
+         * Returns {@link LayoutParams} based on the given {@code spaceWidth}. If the width is 0,
+         * then we're going to have the space expand to take up as much space as possible. If the
+         * width is non-zero, we want the inter-tile spacers to be fixed.
+         */
+        private LayoutParams generateSpaceLayoutParams(int spaceWidth) {
+            LayoutParams lp = new LayoutParams(spaceWidth, mTileDimensionSize);
+            if (spaceWidth == 0) {
+                lp.weight = 1;
+            }
+            lp.gravity = Gravity.CENTER;
+            return lp;
+        }
+
+        @Override
         public void setListening(boolean listening) {
             if (mListening == listening) return;
             mListening = listening;
@@ -200,25 +241,22 @@
         @Override
         public void addTile(TileRecord tile) {
             if (getChildCount() != 0) {
-                // Add a spacer.
-                addView(new Space(mContext), getChildCount(), generateSpaceParams());
+                // Add a spacer between tiles. We want static-width spaces if we're in landscape to
+                // keep the tiles close. For portrait, we stick with spaces that fill up any
+                // available space.
+                LayoutParams spaceLayoutParams = generateSpaceLayoutParams(
+                        mContext.getResources().getDimensionPixelSize(
+                                R.dimen.qs_quick_tile_space_width));
+                addView(new Space(mContext), getChildCount(), spaceLayoutParams);
             }
-            addView(tile.tileView, getChildCount(), generateLayoutParams());
+
+            addView(tile.tileView, getChildCount(), generateTileLayoutParams());
             mRecords.add(tile);
             tile.tile.setListening(this, mListening);
         }
 
-        private LayoutParams generateSpaceParams() {
-            int size = mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size);
-            LayoutParams lp = new LayoutParams(0, size);
-            lp.weight = 1;
-            lp.gravity = Gravity.CENTER;
-            return lp;
-        }
-
-        private LayoutParams generateLayoutParams() {
-            int size = mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size);
-            LayoutParams lp = new LayoutParams(size, size);
+        private LayoutParams generateTileLayoutParams() {
+            LayoutParams lp = new LayoutParams(mTileDimensionSize, mTileDimensionSize);
             lp.gravity = Gravity.CENTER;
             return lp;
         }
@@ -237,8 +275,8 @@
         }
 
         private int getChildIndex(QSTileView tileView) {
-            final int N = getChildCount();
-            for (int i = 0; i < N; i++) {
+            final int childViewCount = getChildCount();
+            for (int i = 0; i < childViewCount; i++) {
                 if (getChildAt(i) == tileView) {
                     return i;
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
index c9c678c..a9defc8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
@@ -15,7 +15,6 @@
 
 import static com.android.systemui.qs.tileimpl.QSIconViewImpl.QS_ANIM_LENGTH;
 
-import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.ColorStateList;
@@ -122,14 +121,14 @@
     private void setRipple(RippleDrawable tileBackground) {
         mRipple = tileBackground;
         if (getWidth() != 0) {
-            updateRippleSize(getWidth(), getHeight());
+            updateRippleSize();
         }
     }
 
-    private void updateRippleSize(int width, int height) {
+    private void updateRippleSize() {
         // center the touch feedback on the center of the icon, and dial it down a bit
-        final int cx = width / 2;
-        final int cy = mIconFrame.getMeasuredHeight() / 2;
+        final int cx = mIconFrame.getMeasuredWidth() / 2 + mIconFrame.getLeft();
+        final int cy = mIconFrame.getMeasuredHeight() / 2 + mIconFrame.getTop();
         final int rad = (int) (mIcon.getHeight() * .85f);
         mRipple.setHotspotBounds(cx - rad, cy - rad, cx + rad, cy + rad);
     }
@@ -151,11 +150,8 @@
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         super.onLayout(changed, l, t, r, b);
-        final int w = getMeasuredWidth();
-        final int h = getMeasuredHeight();
-
         if (mRipple != null) {
-            updateRippleSize(w, h);
+            updateRippleSize();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
index 4774785..3cb4c71 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
@@ -32,11 +32,12 @@
 import com.android.systemui.plugins.qs.QSIconView;
 import com.android.systemui.plugins.qs.QSTile;
 
+
 import java.util.Objects;
 
 /** View that represents a standard quick settings tile. **/
 public class QSTileView extends QSTileBaseView {
-
+    private static final int DEFAULT_MAX_LINES = 2;
     private static final boolean DUAL_TARGET_ALLOWED = false;
     private View mDivider;
     protected TextView mLabel;
@@ -61,7 +62,7 @@
         setId(View.generateViewId());
         createLabel();
         setOrientation(VERTICAL);
-        setGravity(Gravity.CENTER);
+        setGravity(Gravity.CENTER_HORIZONTAL | Gravity.TOP);
     }
 
     TextView getLabel() {
@@ -72,6 +73,7 @@
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
         FontSizeUtils.updateFontSize(mLabel, R.dimen.qs_tile_text_size);
+        FontSizeUtils.updateFontSize(mSecondLine, R.dimen.qs_tile_text_size);
     }
 
     @Override
@@ -85,17 +87,33 @@
         mLabelContainer.setClipChildren(false);
         mLabelContainer.setClipToPadding(false);
         mLabel = mLabelContainer.findViewById(R.id.tile_label);
+        mLabel.setSelected(true); // Allow marquee to work.
         mPadLock = mLabelContainer.findViewById(R.id.restricted_padlock);
         mDivider = mLabelContainer.findViewById(R.id.underline);
         mExpandIndicator = mLabelContainer.findViewById(R.id.expand_indicator);
         mExpandSpace = mLabelContainer.findViewById(R.id.expand_space);
         mSecondLine = mLabelContainer.findViewById(R.id.app_label);
         mSecondLine.setAlpha(.6f);
-
+        mSecondLine.setSelected(true); // Allow marquee to work.
         addView(mLabelContainer);
     }
 
     @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        if (mLabel.getMaxLines() != DEFAULT_MAX_LINES) {
+            mLabel.setMaxLines(DEFAULT_MAX_LINES);
+        }
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+        // Remeasure view if the secondary label text will be cut off.
+        if (!TextUtils.isEmpty(mSecondLine.getText())
+                && mSecondLine.getLineHeight() > mSecondLine.getHeight()) {
+            mLabel.setSingleLine();
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        }
+    }
+
+    @Override
     protected void handleStateChanged(QSTile.State state) {
         super.handleStateChanged(state);
         if (!Objects.equals(mLabel.getText(), state.label) || mState != state.state) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 28fdc11..8a1e4da 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -150,8 +150,8 @@
             cb = mSignalCallback.mInfo;
         }
         boolean transientEnabling = arg == ARG_SHOW_TRANSIENT_ENABLING;
-        boolean wifiConnected = cb.enabled && (cb.wifiSignalIconId > 0) && (cb.enabledDesc != null);
-        boolean wifiNotConnected = (cb.wifiSignalIconId > 0) && (cb.enabledDesc == null);
+        boolean wifiConnected = cb.enabled && (cb.wifiSignalIconId > 0) && (cb.ssid != null);
+        boolean wifiNotConnected = (cb.wifiSignalIconId > 0) && (cb.ssid == null);
         boolean enabledChanging = state.value != cb.enabled;
         if (enabledChanging) {
             mDetailAdapter.setItemsVisible(cb.enabled);
@@ -163,7 +163,7 @@
         }
         state.slash.isSlashed = false;
         boolean isTransient = transientEnabling || cb.isTransient;
-        state.secondaryLabel = getSecondaryLabel(isTransient);
+        state.secondaryLabel = getSecondaryLabel(isTransient, cb.statusLabel);
         state.state = Tile.STATE_ACTIVE;
         state.dualTarget = true;
         state.value = transientEnabling || cb.enabled;
@@ -181,7 +181,7 @@
             state.label = r.getString(R.string.quick_settings_wifi_label);
         } else if (wifiConnected) {
             state.icon = ResourceIcon.get(cb.wifiSignalIconId);
-            state.label = removeDoubleQuotes(cb.enabledDesc);
+            state.label = removeDoubleQuotes(cb.ssid);
         } else if (wifiNotConnected) {
             state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_disconnected);
             state.label = r.getString(R.string.quick_settings_wifi_label);
@@ -194,7 +194,7 @@
         if (state.value) {
             if (wifiConnected) {
                 minimalContentDescription.append(cb.wifiSignalContentDescription).append(",");
-                minimalContentDescription.append(removeDoubleQuotes(cb.enabledDesc));
+                minimalContentDescription.append(removeDoubleQuotes(cb.ssid));
             }
         }
         state.contentDescription = minimalContentDescription.toString();
@@ -203,10 +203,10 @@
         state.expandedAccessibilityClassName = Switch.class.getName();
     }
 
-    private CharSequence getSecondaryLabel(boolean isTransient) {
+    private CharSequence getSecondaryLabel(boolean isTransient, String statusLabel) {
         return isTransient
                 ? mContext.getString(R.string.quick_settings_wifi_secondary_label_transient)
-                : null;
+                : statusLabel;
     }
 
     @Override
@@ -246,11 +246,12 @@
         boolean enabled;
         boolean connected;
         int wifiSignalIconId;
-        String enabledDesc;
+        String ssid;
         boolean activityIn;
         boolean activityOut;
         String wifiSignalContentDescription;
         boolean isTransient;
+        public String statusLabel;
 
         @Override
         public String toString() {
@@ -258,7 +259,7 @@
                     .append("enabled=").append(enabled)
                     .append(",connected=").append(connected)
                     .append(",wifiSignalIconId=").append(wifiSignalIconId)
-                    .append(",enabledDesc=").append(enabledDesc)
+                    .append(",ssid=").append(ssid)
                     .append(",activityIn=").append(activityIn)
                     .append(",activityOut=").append(activityOut)
                     .append(",wifiSignalContentDescription=").append(wifiSignalContentDescription)
@@ -272,16 +273,18 @@
 
         @Override
         public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
-                boolean activityIn, boolean activityOut, String description, boolean isTransient) {
+                boolean activityIn, boolean activityOut, String description, boolean isTransient,
+                String statusLabel) {
             if (DEBUG) Log.d(TAG, "onWifiSignalChanged enabled=" + enabled);
             mInfo.enabled = enabled;
             mInfo.connected = qsIcon.visible;
             mInfo.wifiSignalIconId = qsIcon.icon;
-            mInfo.enabledDesc = description;
+            mInfo.ssid = description;
             mInfo.activityIn = activityIn;
             mInfo.activityOut = activityOut;
             mInfo.wifiSignalContentDescription = qsIcon.contentDescription;
             mInfo.isTransient = isTransient;
+            mInfo.statusLabel = statusLabel;
             if (isShowingDetail()) {
                 mDetailAdapter.updateItems();
             }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 068fd3f..227f2d2 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -189,7 +189,6 @@
         mPublicNotificationBuilder =
                 new Notification.Builder(context, NotificationChannels.SCREENSHOTS_HEADSUP)
                         .setContentTitle(r.getString(R.string.screenshot_saving_title))
-                        .setContentText(r.getString(R.string.screenshot_saving_text))
                         .setSmallIcon(R.drawable.stat_notify_image)
                         .setCategory(Notification.CATEGORY_PROGRESS)
                         .setWhen(now)
@@ -203,7 +202,6 @@
             .setTicker(r.getString(R.string.screenshot_saving_ticker)
                     + (mTickerAddSpace ? " " : ""))
             .setContentTitle(r.getString(R.string.screenshot_saving_title))
-            .setContentText(r.getString(R.string.screenshot_saving_text))
             .setSmallIcon(R.drawable.stat_notify_image)
             .setWhen(now)
             .setShowWhen(true)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
index 3698c3a0..4388b41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
@@ -48,6 +48,11 @@
         return findViewById(R.id.no_notifications);
     }
 
+    @Override
+    protected View findSecondaryView() {
+        return null;
+    }
+
     public void setTextColor(@ColorInt int color) {
         mEmptyText.setTextColor(color);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 6b9567d..ebc7b94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -1061,6 +1061,7 @@
     }
 
     public void setDismissed(boolean fromAccessibility) {
+        setLongPressListener(null);
         mDismissed = true;
         mGroupParentWhenDismissed = mNotificationParent;
         mRefocusOnDismiss = fromAccessibility;
@@ -1558,6 +1559,11 @@
                 }
             }
             invalidateOutline();
+
+            // In order to keep the shelf in sync with this swiping, we're simply translating
+            // it's icon by the same amount. The translation is already being used for the normal
+            // positioning, so we can use the scrollX instead.
+            getEntry().expandedIcon.setScrollX((int) -translationX);
         }
         if (mMenuRow.getMenuView() != null) {
             mMenuRow.onTranslationUpdate(translationX);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java b/packages/SystemUI/src/com/android/systemui/statusbar/FooterView.java
similarity index 68%
rename from packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/FooterView.java
index d7c6443..0f4b621 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FooterView.java
@@ -26,11 +26,12 @@
 import com.android.systemui.statusbar.stack.ExpandableViewState;
 import com.android.systemui.statusbar.stack.StackScrollState;
 
-public class DismissView extends StackScrollerDecorView {
+public class FooterView extends StackScrollerDecorView {
     private final int mClearAllTopPadding;
-    private DismissViewButton mDismissButton;
+    private FooterViewButton mDismissButton;
+    private FooterViewButton mManageButton;
 
-    public DismissView(Context context, AttributeSet attrs) {
+    public FooterView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mClearAllTopPadding = context.getResources().getDimensionPixelSize(
                 R.dimen.clear_all_padding_top);
@@ -38,21 +39,31 @@
 
     @Override
     protected View findContentView() {
+        return findViewById(R.id.content);
+    }
+
+    protected View findSecondaryView() {
         return findViewById(R.id.dismiss_text);
     }
 
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mDismissButton = (DismissViewButton) findContentView();
+        mDismissButton = (FooterViewButton) findSecondaryView();
+        mManageButton = findViewById(R.id.manage_text);
     }
 
     public void setTextColor(@ColorInt int color) {
+        mManageButton.setTextColor(color);
         mDismissButton.setTextColor(color);
     }
 
-    public void setOnButtonClickListener(OnClickListener listener) {
-        mContent.setOnClickListener(listener);
+    public void setManageButtonClickListener(OnClickListener listener) {
+        mManageButton.setOnClickListener(listener);
+    }
+
+    public void setDismissButtonClickListener(OnClickListener listener) {
+        mDismissButton.setOnClickListener(listener);
     }
 
     public boolean isOnEmptySpace(float touchX, float touchY) {
@@ -68,25 +79,26 @@
         mDismissButton.setText(R.string.clear_all_notifications_text);
         mDismissButton.setContentDescription(
                 mContext.getString(R.string.accessibility_clear_all));
+        mManageButton.setText(R.string.manage_notifications_text);
     }
 
     public boolean isButtonVisible() {
-        return mDismissButton.getAlpha() != 0.0f;
+        return mManageButton.getAlpha() != 0.0f;
     }
 
     @Override
     public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
-        return new DismissViewState();
+        return new FooterViewState();
     }
 
-    public class DismissViewState extends ExpandableViewState {
+    public class FooterViewState extends ExpandableViewState {
         @Override
         public void applyToView(View view) {
             super.applyToView(view);
-            if (view instanceof DismissView) {
-                DismissView dismissView = (DismissView) view;
+            if (view instanceof FooterView) {
+                FooterView footerView = (FooterView) view;
                 boolean visible = this.clipTopAmount < mClearAllTopPadding;
-                dismissView.performVisibilityAnimation(visible && !dismissView.willBeGone());
+                footerView.performVisibilityAnimation(visible && !footerView.willBeGone());
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DismissViewButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/FooterViewButton.java
similarity index 84%
rename from packages/SystemUI/src/com/android/systemui/statusbar/DismissViewButton.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/FooterViewButton.java
index b608d67..16ca0f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DismissViewButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FooterViewButton.java
@@ -23,21 +23,21 @@
 
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
-public class DismissViewButton extends AlphaOptimizedButton {
+public class FooterViewButton extends AlphaOptimizedButton {
 
-    public DismissViewButton(Context context) {
+    public FooterViewButton(Context context) {
         this(context, null);
     }
 
-    public DismissViewButton(Context context, AttributeSet attrs) {
+    public FooterViewButton(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
-    public DismissViewButton(Context context, AttributeSet attrs, int defStyleAttr) {
+    public FooterViewButton(Context context, AttributeSet attrs, int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
 
-    public DismissViewButton(Context context, AttributeSet attrs, int defStyleAttr,
+    public FooterViewButton(Context context, AttributeSet attrs, int defStyleAttr,
             int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 41c7559..a4aa598 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -85,6 +85,7 @@
     private boolean mAnimationsEnabled = true;
     private boolean mShowNotificationShelf;
     private float mFirstElementRoundness;
+    private Rect mClipRect = new Rect();
 
     public NotificationShelf(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -672,6 +673,11 @@
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
         updateRelativeOffset();
+
+        // we always want to clip to our sides, such that nothing can draw outside of these bounds
+        int height = getResources().getDisplayMetrics().heightPixels;
+        mClipRect.set(0, -height, getWidth(), height);
+        mShelfIcons.setClipBounds(mClipRect);
     }
 
     private void updateRelativeOffset() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 3cf7741..e7b768f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -55,7 +55,6 @@
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Objects;
 
 // Intimately tied to the design of res/layout/signal_cluster_view.xml
 public class SignalClusterView extends LinearLayout implements NetworkControllerImpl.SignalCallback,
@@ -277,7 +276,8 @@
 
     @Override
     public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
-            boolean activityIn, boolean activityOut, String description, boolean isTransient) {
+            boolean activityIn, boolean activityOut, String description, boolean isTransient,
+            String secondaryLabel) {
         mWifiVisible = statusIcon.visible && !mBlockWifi;
         mWifiStrengthId = statusIcon.icon;
         mWifiDescription = statusIcon.contentDescription;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java
index badc40d..14a6c42 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java
@@ -31,8 +31,11 @@
 public abstract class StackScrollerDecorView extends ExpandableView {
 
     protected View mContent;
+    protected View mSecondaryView;
     private boolean mIsVisible;
+    private boolean mIsSecondaryVisible;
     private boolean mAnimating;
+    private int mDuration = 260;
 
     public StackScrollerDecorView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -42,6 +45,7 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
         mContent = findContentView();
+        mSecondaryView = findSecondaryView();
         setInvisible();
     }
 
@@ -57,17 +61,37 @@
     }
 
     public void performVisibilityAnimation(boolean nowVisible) {
-        animateText(nowVisible, null /* onFinishedRunnable */);
+        animateText(mContent, nowVisible, null /* onFinishedRunnable */);
+        mIsVisible = nowVisible;
     }
 
     public void performVisibilityAnimation(boolean nowVisible, Runnable onFinishedRunnable) {
-        animateText(nowVisible, onFinishedRunnable);
+        animateText(mContent, nowVisible, onFinishedRunnable);
+        mIsVisible = nowVisible;
+    }
+
+    public void performSecondaryVisibilityAnimation(boolean nowVisible) {
+        performSecondaryVisibilityAnimation(nowVisible, null /* onFinishedRunnable */);
+    }
+
+    public void performSecondaryVisibilityAnimation(boolean nowVisible,
+            Runnable onFinishedRunnable) {
+        animateText(mSecondaryView, nowVisible, onFinishedRunnable);
+        mIsSecondaryVisible = nowVisible;
+    }
+
+    public boolean isSecondaryVisible() {
+        return mSecondaryView != null && (mIsSecondaryVisible || mAnimating);
     }
 
     public boolean isVisible() {
         return mIsVisible || mAnimating;
     }
 
+    void setDuration(int duration) {
+        mDuration = duration;
+    }
+
     /**
      * Animate the text to a new visibility.
      *
@@ -75,7 +99,10 @@
      * @param onFinishedRunnable A runnable which should be run when the animation is
      *        finished.
      */
-    private void animateText(boolean nowVisible, final Runnable onFinishedRunnable) {
+    private void animateText(View view, boolean nowVisible, final Runnable onFinishedRunnable) {
+        if (view == null) {
+            return;
+        }
         if (nowVisible != mIsVisible) {
             // Animate text
             float endValue = nowVisible ? 1.0f : 0.0f;
@@ -86,10 +113,10 @@
                 interpolator = Interpolators.ALPHA_OUT;
             }
             mAnimating = true;
-            mContent.animate()
+            view.animate()
                     .alpha(endValue)
                     .setInterpolator(interpolator)
-                    .setDuration(260)
+                    .setDuration(mDuration)
                     .withEndAction(new Runnable() {
                         @Override
                         public void run() {
@@ -99,7 +126,6 @@
                             }
                         }
                     });
-            mIsVisible = nowVisible;
         } else {
             if (onFinishedRunnable != null) {
                 onFinishedRunnable.run();
@@ -109,7 +135,11 @@
 
     public void setInvisible() {
         mContent.setAlpha(0.0f);
+        if (mSecondaryView != null) {
+            mSecondaryView.setAlpha(0.0f);
+        }
         mIsVisible = false;
+        mIsSecondaryVisible = false;
     }
 
     @Override
@@ -134,7 +164,15 @@
 
     public void cancelAnimation() {
         mContent.animate().cancel();
+        if (mSecondaryView != null) {
+            mSecondaryView.animate().cancel();
+        }
     }
 
     protected abstract View findContentView();
+
+    /**
+     * Returns a view that might not always appear while the main content view is still visible.
+     */
+    protected abstract View findSecondaryView();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index d609ae7..fcd4e8f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -330,6 +330,10 @@
         }
     }
 
+    public boolean willDismissWithAction() {
+        return mKeyguardView != null && mKeyguardView.hasDismissActions();
+    }
+
     protected void ensureView() {
         // Removal of the view might be deferred to reduce unlock latency,
         // in this case we need to force the removal, otherwise we'll
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index a39800d..58f8baa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -171,7 +171,7 @@
     private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() {
         @Override
         public void onConnectionChanged(boolean isConnected) {
-            mNavigationBarView.onOverviewProxyConnectionChanged(isConnected);
+            mNavigationBarView.updateStates();
             updateScreenPinningGestures();
             WindowManagerWrapper.getInstance()
                     .setNavBarVirtualKeyHapticFeedbackEnabled(!isConnected);
@@ -188,6 +188,7 @@
         @Override
         public void onInteractionFlagsChanged(@InteractionType int flags) {
             mNavigationBarView.updateStates();
+            updateScreenPinningGestures();
         }
     };
 
@@ -925,7 +926,9 @@
     private boolean onLongPressRecents() {
         if (mRecents == null || !ActivityManager.supportsMultiWindow(getContext())
                 || !mDivider.getView().getSnapAlgorithm().isSplitScreenFeasible()
-                || Recents.getConfiguration().isLowRamDevice) {
+                || Recents.getConfiguration().isLowRamDevice
+                // If we are connected to the overview service, then disable the recents button
+                || mOverviewProxyService.getProxy() != null) {
             return false;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 8fb0620..b4cb088 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -681,6 +681,7 @@
         updateSlippery();
         reloadNavIcons();
         updateNavButtonIcons();
+        setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
     }
 
     private void updateSlippery() {
@@ -816,11 +817,6 @@
         }
     }
 
-    public void onOverviewProxyConnectionChanged(boolean isConnected) {
-        updateStates();
-        setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
-    }
-
     @Override
     protected void onDraw(Canvas canvas) {
         mGestureHelper.onDraw(canvas);
@@ -842,10 +838,17 @@
             buttonBounds.setEmpty();
             return;
         }
+        // Temporarily reset the translation back to origin to get the position in window
+        final float posX = view.getTranslationX();
+        final float posY = view.getTranslationY();
+        view.setTranslationX(0);
+        view.setTranslationY(0);
         view.getLocationInWindow(mTmpPosition);
         buttonBounds.set(mTmpPosition[0], mTmpPosition[1],
                 mTmpPosition[0] + view.getMeasuredWidth(),
                 mTmpPosition[1] + view.getMeasuredHeight());
+        view.setTranslationX(posX);
+        view.setTranslationY(posY);
     }
 
     private void updateRotatedViews() {
@@ -1038,7 +1041,7 @@
         onPluginDisconnected(null); // Create default gesture helper
         Dependency.get(PluginManager.class).addPluginListener(this,
                 NavGesture.class, false /* Only one */);
-        setUpSwipeUpOnboarding(mOverviewProxyService.getProxy() != null);
+        setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 64e205d..cccda90 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -2165,18 +2165,18 @@
 
     @Override
     protected boolean fullyExpandedClearAllVisible() {
-        return mNotificationStackScroller.isDismissViewNotGone()
+        return mNotificationStackScroller.isFooterViewNotGone()
                 && mNotificationStackScroller.isScrolledToBottom() && !mQsExpandImmediate;
     }
 
     @Override
     protected boolean isClearAllVisible() {
-        return mNotificationStackScroller.isDismissViewVisible();
+        return mNotificationStackScroller.isFooterViewVisible();
     }
 
     @Override
     protected int getClearAllHeight() {
-        return mNotificationStackScroller.getDismissViewHeight();
+        return mNotificationStackScroller.getFooterViewHeight();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
index 6047f8e..a51cd93 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -303,16 +303,18 @@
 
     @Override
     public void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        final int width = right - left;
-        final int height = bottom - top;
+        final int width = (right - left) - mNavigationBarView.getPaddingEnd()
+                - mNavigationBarView.getPaddingStart();
+        final int height = (bottom - top) - mNavigationBarView.getPaddingBottom()
+                - mNavigationBarView.getPaddingTop();
         final int x1, x2, y1, y2;
         if (mIsVertical) {
-            x1 = (width - mTrackThickness) / 2;
+            x1 = (width - mTrackThickness) / 2 + mNavigationBarView.getPaddingStart();
             x2 = x1 + mTrackThickness;
             y1 = mDragPositive ? height / 2 : mTrackPadding;
             y2 = y1 + height / 2 - mTrackPadding;
         } else {
-            y1 = (height - mTrackThickness) / 2;
+            y1 = (height - mTrackThickness) / 2 + mNavigationBarView.getPaddingTop();
             y2 = y1 + mTrackThickness;
             x1 = mDragPositive ? width / 2 : mTrackPadding;
             x2 = x1 + width / 2 - mTrackPadding;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index cfc0cc6..7a6e98d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -148,7 +148,7 @@
     private float mNotificationDensity;
 
     // Scrim blanking callbacks
-    private Choreographer.FrameCallback mPendingFrameCallback;
+    private Runnable mPendingFrameCallback;
     private Runnable mBlankingTransitionRunnable;
 
     private final WakeLock mWakeLock;
@@ -240,7 +240,7 @@
 
         // Cancel blanking transitions that were pending before we requested a new state
         if (mPendingFrameCallback != null) {
-            Choreographer.getInstance().removeFrameCallback(mPendingFrameCallback);
+            mScrimBehind.removeCallbacks(mPendingFrameCallback);
             mPendingFrameCallback = null;
         }
         if (getHandler().hasCallbacks(mBlankingTransitionRunnable)) {
@@ -278,7 +278,7 @@
             // with too many things at this case, in order to not skip the initial frames.
             mScrimInFront.postOnAnimationDelayed(this::scheduleUpdate, 16);
             mAnimationDelay = StatusBar.FADE_KEYGUARD_START_DELAY;
-        } else if (!mDozeParameters.getAlwaysOn() && oldState == ScrimState.AOD
+        } else if ((!mDozeParameters.getAlwaysOn() && oldState == ScrimState.AOD)
                 || (mState == ScrimState.AOD && !mDozeParameters.getDisplayNeedsBlanking())) {
             // Scheduling a frame isn't enough when:
             //  • Leaving doze and we need to modify scrim color immediately
@@ -727,7 +727,7 @@
 
         // Notify callback that the screen is completely black and we're
         // ready to change the display power mode
-        mPendingFrameCallback = frameTimeNanos -> {
+        mPendingFrameCallback = () -> {
             if (mCallback != null) {
                 mCallback.onDisplayBlanked();
                 mScreenBlankingCallbackCalled = true;
@@ -743,7 +743,7 @@
 
             // Setting power states can happen after we push out the frame. Make sure we
             // stay fully opaque until the power state request reaches the lower levels.
-            final int delay = mScreenOn ? 16 : 500;
+            final int delay = mScreenOn ? 32 : 500;
             if (DEBUG) {
                 Log.d(TAG, "Fading out scrims with delay: " + delay);
             }
@@ -752,9 +752,15 @@
         doOnTheNextFrame(mPendingFrameCallback);
     }
 
+    /**
+     * Executes a callback after the frame has hit the display.
+     * @param callback What to run.
+     */
     @VisibleForTesting
-    protected void doOnTheNextFrame(Choreographer.FrameCallback callback) {
-        Choreographer.getInstance().postFrameCallback(callback);
+    protected void doOnTheNextFrame(Runnable callback) {
+        // Just calling View#postOnAnimation isn't enough because the frame might not have reached
+        // the display yet. A timeout is the safest solution.
+        mScrimBehind.postOnAnimationDelayed(callback, 32 /* delayMillis */);
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 8cd6295..ddb67df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -130,7 +130,6 @@
 import com.android.internal.colorextraction.ColorExtractor;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.widget.LockPatternUtils;
@@ -185,12 +184,11 @@
 import com.android.systemui.statusbar.BackDropView;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.CrossFadeHelper;
-import com.android.systemui.statusbar.DismissView;
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.EmptyShadeView;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.FooterView;
 import com.android.systemui.statusbar.GestureRecorder;
-import com.android.systemui.statusbar.HeadsUpStatusBarView;
 import com.android.systemui.statusbar.KeyboardShortcuts;
 import com.android.systemui.statusbar.KeyguardIndicationController;
 import com.android.systemui.statusbar.NotificationData;
@@ -237,7 +235,6 @@
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
-import com.android.systemui.util.NotificationChannels;
 import com.android.systemui.volume.VolumeComponent;
 
 import java.io.FileDescriptor;
@@ -577,7 +574,7 @@
     private final LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
     protected NotificationIconAreaController mNotificationIconAreaController;
     private boolean mReinflateNotificationsOnUserSwitched;
-    private boolean mClearAllEnabled;
+    protected boolean mClearAllEnabled;
     @Nullable private View mAmbientIndicationContainer;
     private SysuiColorExtractor mColorExtractor;
     private ScreenLifecycle mScreenLifecycle;
@@ -868,7 +865,7 @@
         mVisualStabilityManager.setVisibilityLocationProvider(mStackScroller);
 
         inflateEmptyShadeView();
-        inflateDismissView();
+        inflateFooterView();
 
         mBackdrop = mStatusBarWindow.findViewById(R.id.backdrop);
         mBackdropFront = mBackdrop.findViewById(R.id.backdrop_front);
@@ -1133,8 +1130,8 @@
 
     protected void reevaluateStyles() {
         inflateSignalClusters();
-        inflateDismissView();
-        updateClearAll();
+        inflateFooterView();
+        updateFooter();
         inflateEmptyShadeView();
         updateEmptyShadeView();
     }
@@ -1186,18 +1183,21 @@
         mStackScroller.setEmptyShadeView(mEmptyShadeView);
     }
 
-    private void inflateDismissView() {
-        if (!mClearAllEnabled || mStackScroller == null) {
+    private void inflateFooterView() {
+        if (mStackScroller == null) {
             return;
         }
 
-        mDismissView = (DismissView) LayoutInflater.from(mContext).inflate(
-                R.layout.status_bar_notification_dismiss_all, mStackScroller, false);
-        mDismissView.setOnButtonClickListener(v -> {
+        mFooterView = (FooterView) LayoutInflater.from(mContext).inflate(
+                R.layout.status_bar_notification_footer, mStackScroller, false);
+        mFooterView.setDismissButtonClickListener(v -> {
             mMetricsLogger.action(MetricsEvent.ACTION_DISMISS_ALL_NOTES);
             clearAllNotifications();
         });
-        mStackScroller.setDismissView(mDismissView);
+        mFooterView.setManageButtonClickListener(v -> {
+            manageNotifications();
+        });
+        mStackScroller.setFooterView(mFooterView);
     }
 
     protected void createUserSwitcher() {
@@ -1211,6 +1211,12 @@
                 R.layout.super_status_bar, null);
     }
 
+    public void manageNotifications() {
+        Intent intent = new Intent(Settings.ACTION_ALL_APPS_NOTIFICATION_SETTINGS);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        startActivity(intent, true, true);
+    }
+
     public void clearAllNotifications() {
 
         // animate-swipe all dismissable notifications, then animate the shade closed
@@ -1393,7 +1399,7 @@
         mViewHierarchyManager.updateNotificationViews();
 
         updateSpeedBumpIndex();
-        updateClearAll();
+        updateFooter();
         updateEmptyShadeView();
 
         updateQsExpansionEnabled();
@@ -1457,13 +1463,14 @@
         mQSPanel.clickTile(tile);
     }
 
-    private void updateClearAll() {
-        if (!mClearAllEnabled) {
-            return;
-        }
-        boolean showDismissView = mState != StatusBarState.KEYGUARD
+    @VisibleForTesting
+    protected void updateFooter() {
+        boolean showFooterView = mState != StatusBarState.KEYGUARD
+                && mEntryManager.getNotificationData().getActiveNotifications().size() != 0;
+        boolean showDismissView = mClearAllEnabled && mState != StatusBarState.KEYGUARD
                 && hasActiveClearableNotifications();
-        mStackScroller.updateDismissView(showDismissView);
+
+        mStackScroller.updateFooterView(showFooterView, showDismissView);
     }
 
     /**
@@ -4654,9 +4661,12 @@
 
         if (mBouncerShowing) {
             // Bouncer needs the front scrim when it's on top of an activity,
-            // tapping on a notification or editing QS.
-            mScrimController.transitionTo(mIsOccluded || mNotificationPanel.needsScrimming() ?
-                    ScrimState.BOUNCER_SCRIMMED : ScrimState.BOUNCER);
+            // tapping on a notification, editing QS or being dismissed by
+            // FLAG_DISMISS_KEYGUARD_ACTIVITY.
+            ScrimState state = mIsOccluded || mNotificationPanel.needsScrimming()
+                    || mStatusBarKeyguardViewManager.willDismissWithAction() ?
+                    ScrimState.BOUNCER_SCRIMMED : ScrimState.BOUNCER;
+            mScrimController.transitionTo(state);
         } else if (mLaunchCameraOnScreenTurningOn || isInLaunchTransition()) {
             mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
         } else if (mBrightnessMirrorVisible) {
@@ -4935,7 +4945,7 @@
     protected RecentsComponent mRecents;
 
     protected NotificationShelf mNotificationShelf;
-    protected DismissView mDismissView;
+    protected FooterView mFooterView;
     protected EmptyShadeView mEmptyShadeView;
 
     protected AssistManager mAssistManager;
@@ -5408,8 +5418,8 @@
         // incremented in the following "changeViewPosition" calls so that its value is correct for
         // subsequent calls.
         int offsetFromEnd = 1;
-        if (mDismissView != null) {
-            mStackScroller.changeViewPosition(mDismissView,
+        if (mFooterView != null) {
+            mStackScroller.changeViewPosition(mFooterView,
                     mStackScroller.getChildCount() - offsetFromEnd++);
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 56a7b1b..1a64b00 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -140,11 +140,14 @@
     }
 
     private void onPanelExpansionChanged(float expansion, boolean tracking) {
-        // We don't want to translate the bounce when the keyguard is occluded, because we're in
-        // a FLAG_SHOW_WHEN_LOCKED activity and need to conserve the original animation.
-        // We also don't want to show the bouncer when the user quickly taps on the display.
+        // We don't want to translate the bounce when:
+        // • Keyguard is occluded, because we're in a FLAG_SHOW_WHEN_LOCKED activity and need to
+        //   conserve the original animation.
+        // • The user quickly taps on the display and we show "swipe up to unlock."
+        // • Keyguard will be dismissed by an action. a.k.a: FLAG_DISMISS_KEYGUARD_ACTIVITY
         final boolean noLongerTracking = mLastTracking != tracking && !tracking;
-        if (mOccluded || mNotificationPanelView.isUnlockHintRunning()) {
+        if (mOccluded || mNotificationPanelView.isUnlockHintRunning()
+                || mBouncer.willDismissWithAction()) {
             mBouncer.setExpansion(0);
         } else if (mShowing && mStatusBar.isKeyguardCurrentlySecure() && !mDozing) {
             mBouncer.setExpansion(expansion);
@@ -696,6 +699,10 @@
         }
     }
 
+    public boolean willDismissWithAction() {
+        return mBouncer.willDismissWithAction();
+    }
+
     private static class DismissWithActionRequest {
         final OnDismissAction dismissAction;
         final Runnable cancelAction;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
index 5159e8d..b76d536 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
@@ -109,13 +109,13 @@
     @Override
     public void setWifiIndicators(final boolean enabled, final IconState statusIcon,
             final IconState qsIcon, final boolean activityIn, final boolean activityOut,
-            final String description, boolean isTransient) {
+            final String description, boolean isTransient, String secondaryLabel) {
         post(new Runnable() {
             @Override
             public void run() {
                 for (SignalCallback callback : mSignalCallbacks) {
                     callback.setWifiIndicators(enabled, statusIcon, qsIcon, activityIn, activityOut,
-                            description, isTransient);
+                            description, isTransient, secondaryLabel);
                 }
             }
         });
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 76e3ad7..51fef7d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -47,7 +47,8 @@
 
     public interface SignalCallback {
         default void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
-                boolean activityIn, boolean activityOut, String description, boolean isTransient) {}
+                boolean activityIn, boolean activityOut, String description, boolean isTransient,
+                String statusLabel) {}
 
         default void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
                 int qsType, boolean activityIn, boolean activityOut, String typeContentDescription,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index 0f65421..e5e576d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -17,12 +17,15 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.net.ConnectivityManager;
 import android.net.NetworkCapabilities;
+import android.net.NetworkScoreManager;
 import android.net.wifi.WifiManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Messenger;
+import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -37,7 +40,6 @@
 
 public class WifiSignalController extends
         SignalController<WifiSignalController.WifiState, SignalController.IconGroup> {
-    private final WifiManager mWifiManager;
     private final AsyncChannel mWifiChannel;
     private final boolean mHasMobileData;
     private final WifiStatusTracker mWifiTracker;
@@ -47,12 +49,17 @@
             WifiManager wifiManager) {
         super("WifiSignalController", context, NetworkCapabilities.TRANSPORT_WIFI,
                 callbackHandler, networkController);
-        mWifiManager = wifiManager;
-        mWifiTracker = new WifiStatusTracker(mWifiManager);
+        NetworkScoreManager networkScoreManager =
+                context.getSystemService(NetworkScoreManager.class);
+        ConnectivityManager connectivityManager =
+                context.getSystemService(ConnectivityManager.class);
+        mWifiTracker = new WifiStatusTracker(mContext, wifiManager, networkScoreManager,
+                connectivityManager, this::handleStatusUpdated);
+        mWifiTracker.setListening(true);
         mHasMobileData = hasMobileData;
         Handler handler = new WifiHandler(Looper.getMainLooper());
         mWifiChannel = new AsyncChannel();
-        Messenger wifiMessenger = mWifiManager.getWifiServiceMessenger();
+        Messenger wifiMessenger = wifiManager.getWifiServiceMessenger();
         if (wifiMessenger != null) {
             mWifiChannel.connect(context, handler, wifiMessenger);
         }
@@ -68,7 +75,6 @@
                 WifiIcons.QS_WIFI_NO_NETWORK,
                 AccessibilityContentDescriptions.WIFI_NO_CONNECTION
                 );
-
     }
 
     @Override
@@ -87,13 +93,12 @@
         if (mCurrentState.inetCondition == 0) {
             contentDescription += ("," + mContext.getString(R.string.data_connection_no_internet));
         }
-
         IconState statusIcon = new IconState(wifiVisible, getCurrentIconId(), contentDescription);
         IconState qsIcon = new IconState(mCurrentState.connected, getQsCurrentIconId(),
                 contentDescription);
         callback.setWifiIndicators(mCurrentState.enabled, statusIcon, qsIcon,
                 ssidPresent && mCurrentState.activityIn, ssidPresent && mCurrentState.activityOut,
-                wifiDesc, mCurrentState.isTransient);
+                wifiDesc, mCurrentState.isTransient, mCurrentState.statusLabel);
     }
 
     /**
@@ -106,6 +111,12 @@
         mCurrentState.ssid = mWifiTracker.ssid;
         mCurrentState.rssi = mWifiTracker.rssi;
         mCurrentState.level = mWifiTracker.level;
+        mCurrentState.statusLabel = mWifiTracker.statusLabel;
+        notifyListenersIfNecessary();
+    }
+
+    private void handleStatusUpdated() {
+        mCurrentState.statusLabel = mWifiTracker.statusLabel;
         notifyListenersIfNecessary();
     }
 
@@ -150,6 +161,7 @@
     static class WifiState extends SignalController.State {
         String ssid;
         boolean isTransient;
+        String statusLabel;
 
         @Override
         public void copyFrom(State s) {
@@ -157,20 +169,26 @@
             WifiState state = (WifiState) s;
             ssid = state.ssid;
             isTransient = state.isTransient;
+            statusLabel = state.statusLabel;
         }
 
         @Override
         protected void toString(StringBuilder builder) {
             super.toString(builder);
-            builder.append(',').append("ssid=").append(ssid);
-            builder.append(',').append("isTransient=").append(isTransient);
+            builder.append(",ssid=").append(ssid)
+                .append(",isTransient=").append(isTransient)
+                .append(",statusLabel=").append(statusLabel);
         }
 
         @Override
         public boolean equals(Object o) {
-            return super.equals(o)
-                    && Objects.equals(((WifiState) o).ssid, ssid)
-                    && (((WifiState) o).isTransient == isTransient);
+            if (!super.equals(o)) {
+                return false;
+            }
+            WifiState other = (WifiState) o;
+            return Objects.equals(other.ssid, ssid)
+                    && other.isTransient == isTransient
+                    && TextUtils.equals(other.statusLabel, statusLabel);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index dc94203..8f6fa49 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -16,7 +16,8 @@
 
 package com.android.systemui.statusbar.stack;
 
-import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
+import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator
+        .ExpandAnimationParameters;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -43,6 +44,7 @@
 import android.service.notification.StatusBarNotification;
 import android.support.annotation.NonNull;
 import android.support.annotation.VisibleForTesting;
+import android.support.v4.graphics.ColorUtils;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
 import android.util.Log;
@@ -77,10 +79,10 @@
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
 import com.android.systemui.statusbar.ActivatableNotificationView;
-import com.android.systemui.statusbar.DismissView;
 import com.android.systemui.statusbar.EmptyShadeView;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.ExpandableView;
+import com.android.systemui.statusbar.FooterView;
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.NotificationGuts;
 import com.android.systemui.statusbar.NotificationListContainer;
@@ -99,8 +101,6 @@
 import com.android.systemui.statusbar.policy.HeadsUpUtil;
 import com.android.systemui.statusbar.policy.ScrollAdapter;
 
-import android.support.v4.graphics.ColorUtils;
-
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -109,7 +109,6 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.function.BiConsumer;
-import java.util.function.Consumer;
 
 /**
  * A layout which handles a dynamic amount of notifications and presents them in a scrollable stack.
@@ -226,7 +225,7 @@
     private boolean mExpandingNotification;
     private boolean mExpandedInThisMotion;
     protected boolean mScrollingEnabled;
-    protected DismissView mDismissView;
+    protected FooterView mFooterView;
     protected EmptyShadeView mEmptyShadeView;
     private boolean mDismissAllInProgress;
     private boolean mFadeNotificationsOnDismiss;
@@ -3838,13 +3837,13 @@
         Context context = new ContextThemeWrapper(mContext,
                 lightTheme ? R.style.Theme_SystemUI_Light : R.style.Theme_SystemUI);
         final int textColor = Utils.getColorAttr(context, R.attr.wallpaperTextColor);
-        mDismissView.setTextColor(textColor);
+        mFooterView.setTextColor(textColor);
         mEmptyShadeView.setTextColor(textColor);
     }
 
     public void goToFullShade(long delay) {
-        if (mDismissView != null) {
-            mDismissView.setInvisible();
+        if (mFooterView != null) {
+            mFooterView.setInvisible();
         }
         mEmptyShadeView.setInvisible();
         mGoToFullShadeNeedsAnimation = true;
@@ -3967,14 +3966,14 @@
         return -1;
     }
 
-    public void setDismissView(@NonNull DismissView dismissView) {
+    public void setFooterView(@NonNull FooterView footerView) {
         int index = -1;
-        if (mDismissView != null) {
-            index = indexOfChild(mDismissView);
-            removeView(mDismissView);
+        if (mFooterView != null) {
+            index = indexOfChild(mFooterView);
+            removeView(mFooterView);
         }
-        mDismissView = dismissView;
-        addView(mDismissView, index);
+        mFooterView = footerView;
+        addView(mFooterView, index);
     }
 
     public void setEmptyShadeView(EmptyShadeView emptyShadeView) {
@@ -3992,77 +3991,64 @@
         int newVisibility = visible ? VISIBLE : GONE;
         if (oldVisibility != newVisibility) {
             if (newVisibility != GONE) {
-                if (mEmptyShadeView.willBeGone()) {
-                    mEmptyShadeView.cancelAnimation();
-                } else {
-                    mEmptyShadeView.setInvisible();
-                }
                 if (mStatusBar.areNotificationsHidden()) {
                     mEmptyShadeView.setText(R.string.dnd_suppressing_shade_text);
                 } else {
                     mEmptyShadeView.setText(R.string.empty_shade_text);
                 }
-                mEmptyShadeView.setVisibility(newVisibility);
-                mEmptyShadeView.setWillBeGone(false);
-                updateContentHeight();
-                notifyHeightChangeListener(mEmptyShadeView);
+                showFooterView(mEmptyShadeView);
             } else {
-                Runnable onFinishedRunnable = new Runnable() {
-                    @Override
-                    public void run() {
-                        mEmptyShadeView.setVisibility(GONE);
-                        mEmptyShadeView.setWillBeGone(false);
-                        updateContentHeight();
-                        notifyHeightChangeListener(mEmptyShadeView);
-                    }
-                };
-                if (mAnimationsEnabled && mIsExpanded) {
-                    mEmptyShadeView.setWillBeGone(true);
-                    mEmptyShadeView.performVisibilityAnimation(false, onFinishedRunnable);
-                } else {
-                    mEmptyShadeView.setInvisible();
-                    onFinishedRunnable.run();
-                }
+                hideFooterView(mEmptyShadeView, true);
             }
         }
     }
 
-    public void updateDismissView(boolean visible) {
-        if (mDismissView == null) {
+    public void updateFooterView(boolean visible, boolean showDismissView) {
+        if (mFooterView == null) {
             return;
         }
-
-        int oldVisibility = mDismissView.willBeGone() ? GONE : mDismissView.getVisibility();
+        int oldVisibility = mFooterView.willBeGone() ? GONE : mFooterView.getVisibility();
         int newVisibility = visible ? VISIBLE : GONE;
         if (oldVisibility != newVisibility) {
             if (newVisibility != GONE) {
-                if (mDismissView.willBeGone()) {
-                    mDismissView.cancelAnimation();
-                } else {
-                    mDismissView.setInvisible();
-                }
-                mDismissView.setVisibility(newVisibility);
-                mDismissView.setWillBeGone(false);
-                updateContentHeight();
-                notifyHeightChangeListener(mDismissView);
+                showFooterView(mFooterView);
             } else {
-                Runnable dimissHideFinishRunnable = new Runnable() {
-                    @Override
-                    public void run() {
-                        mDismissView.setVisibility(GONE);
-                        mDismissView.setWillBeGone(false);
-                        updateContentHeight();
-                        notifyHeightChangeListener(mDismissView);
-                    }
-                };
-                if (mDismissView.isButtonVisible() && mIsExpanded && mAnimationsEnabled) {
-                    mDismissView.setWillBeGone(true);
-                    mDismissView.performVisibilityAnimation(false, dimissHideFinishRunnable);
-                } else {
-                    dimissHideFinishRunnable.run();
-                }
+                hideFooterView(mFooterView, mFooterView.isButtonVisible());
             }
         }
+        if (mFooterView.isSecondaryVisible() != showDismissView) {
+            mFooterView.performSecondaryVisibilityAnimation(showDismissView);
+        }
+    }
+
+    private void showFooterView(StackScrollerDecorView footerView) {
+        if (footerView.willBeGone()) {
+            footerView.cancelAnimation();
+        } else {
+            footerView.setInvisible();
+        }
+        footerView.setVisibility(VISIBLE);
+        footerView.setWillBeGone(false);
+        updateContentHeight();
+        notifyHeightChangeListener(footerView);
+    }
+
+    private void hideFooterView(StackScrollerDecorView footerView, boolean isButtonVisible) {
+        Runnable onHideFinishRunnable = new Runnable() {
+            @Override
+            public void run() {
+                footerView.setVisibility(GONE);
+                footerView.setWillBeGone(false);
+                updateContentHeight();
+                notifyHeightChangeListener(footerView);
+            }
+        };
+        if (isButtonVisible && mIsExpanded && mAnimationsEnabled) {
+            footerView.setWillBeGone(true);
+            footerView.performVisibilityAnimation(false, onHideFinishRunnable);
+        } else {
+            onHideFinishRunnable.run();
+        }
     }
 
     public void setDismissAllInProgress(boolean dismissAllInProgress) {
@@ -4088,18 +4074,18 @@
         }
     }
 
-    public boolean isDismissViewNotGone() {
-        return mDismissView != null
-                && mDismissView.getVisibility() != View.GONE
-                && !mDismissView.willBeGone();
+    public boolean isFooterViewNotGone() {
+        return mFooterView != null
+                && mFooterView.getVisibility() != View.GONE
+                && !mFooterView.willBeGone();
     }
 
-    public boolean isDismissViewVisible() {
-        return mDismissView != null && mDismissView.isVisible();
+    public boolean isFooterViewVisible() {
+        return mFooterView != null && mFooterView.isVisible();
     }
 
-    public int getDismissViewHeight() {
-        return mDismissView == null ? 0 : mDismissView.getHeight() + mPaddingBetweenElements;
+    public int getFooterViewHeight() {
+        return mFooterView == null ? 0 : mFooterView.getHeight() + mPaddingBetweenElements;
     }
 
     public int getEmptyShadeViewHeight() {
@@ -4155,8 +4141,8 @@
                 }
                 boolean belowChild = touchY > childTop + child.getActualHeight()
                         - child.getClipBottomAmount();
-                if (child == mDismissView) {
-                    if(!belowChild && !mDismissView.isOnEmptySpace(touchX - mDismissView.getX(),
+                if (child == mFooterView) {
+                    if(!belowChild && !mFooterView.isOnEmptySpace(touchX - mFooterView.getX(),
                                     touchY - childTop)) {
                         // We clicked on the dismiss button
                         return false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 7c8e0fc..a8d2d98 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -22,10 +22,10 @@
 import android.view.View;
 import android.view.ViewGroup;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.DismissView;
 import com.android.systemui.statusbar.EmptyShadeView;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.ExpandableView;
+import com.android.systemui.statusbar.FooterView;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.notification.NotificationUtils;
 
@@ -390,7 +390,7 @@
         int paddingAfterChild = getPaddingAfterChild(algorithmState, child);
         int childHeight = getMaxAllowedChildHeight(child);
         childViewState.yTranslation = currentYPosition;
-        boolean isDismissView = child instanceof DismissView;
+        boolean isFooterView = child instanceof FooterView;
         boolean isEmptyShadeView = child instanceof EmptyShadeView;
 
         childViewState.location = ExpandableViewState.LOCATION_MAIN_AREA;
@@ -404,7 +404,7 @@
             float end = childViewState.yTranslation + childViewState.height + inset;
             childViewState.headsUpIsVisible = end < ambientState.getMaxHeadsUpTranslation();
         }
-        if (isDismissView) {
+        if (isFooterView) {
             childViewState.yTranslation = Math.min(childViewState.yTranslation,
                     ambientState.getInnerHeight() - childHeight);
         } else if (isEmptyShadeView) {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewTest.java
new file mode 100644
index 0000000..3f85c9d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.keyguard;
+
+import static org.mockito.Mockito.mock;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class KeyguardHostViewTest extends SysuiTestCase {
+
+    private KeyguardHostView mKeyguardHostView;
+
+    @Before
+    public void setup() {
+        mKeyguardHostView = new KeyguardHostView(getContext());
+    }
+
+    @Test
+    public void testHasDismissActions() {
+        Assert.assertFalse("Action not set yet", mKeyguardHostView.hasDismissActions());
+        mKeyguardHostView.setOnDismissAction(mock(KeyguardHostView.OnDismissAction.class),
+                null /* cancelAction */);
+        Assert.assertTrue("Action should exist", mKeyguardHostView.hasDismissActions());
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
index 231a1866..af29ab4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
@@ -18,7 +18,9 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -32,6 +34,7 @@
 import android.view.View;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
 import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
 
@@ -159,6 +162,22 @@
     }
 
     @Test
+    public void testSetDismissed_longPressListenerRemoved() {
+        ExpandableNotificationRow.LongPressListener listener =
+                mock(ExpandableNotificationRow.LongPressListener.class);
+        mGroup.setLongPressListener(listener);
+        mGroup.doLongClickCallback(0,0);
+        verify(listener, times(1)).onLongPress(eq(mGroup), eq(0), eq(0),
+                any(NotificationMenuRowPlugin.MenuItem.class));
+        reset(listener);
+
+        mGroup.setDismissed(true);
+        mGroup.doLongClickCallback(0,0);
+        verify(listener, times(0)).onLongPress(eq(mGroup), eq(0), eq(0),
+                any(NotificationMenuRowPlugin.MenuItem.class));
+    }
+
+    @Test
     public void testShowAppOps_noHeader() {
         // public notification is custom layout - no header
         mGroup.setSensitive(true, true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/FooterViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/FooterViewTest.java
new file mode 100644
index 0000000..96b0255
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/FooterViewTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.graphics.drawable.Icon;
+import android.os.UserHandle;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.util.NotificationColorUtil;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class FooterViewTest extends SysuiTestCase {
+
+    FooterView mView;
+
+    @Before
+    public void setUp() {
+        mView = (FooterView) LayoutInflater.from(mContext).inflate(
+                R.layout.status_bar_notification_footer, null, false);
+        mView.setDuration(0);
+    }
+
+    @Test
+    public void testViewsNotNull() {
+        assertNotNull(mView.findContentView());
+        assertNotNull(mView.findSecondaryView());
+    }
+
+    @Test
+    public void setDismissOnClick() {
+        mView.setDismissButtonClickListener(mock(View.OnClickListener.class));
+        assertTrue(mView.findSecondaryView().hasOnClickListeners());
+    }
+
+    @Test
+    public void setManageOnClick() {
+        mView.setManageButtonClickListener(mock(View.OnClickListener.class));
+        assertTrue(mView.findViewById(R.id.manage_text).hasOnClickListeners());
+    }
+
+    @Test
+    public void testPerformVisibilityAnimation() {
+        mView.setInvisible();
+        assertFalse(mView.isVisible());
+
+        Runnable test = new Runnable() {
+            @Override
+            public void run() {
+                assertEquals(1.0f, mView.findContentView().getAlpha());
+                assertEquals(0.0f, mView.findSecondaryView().getAlpha());
+                assertTrue(mView.isVisible());
+            }
+        };
+        mView.performVisibilityAnimation(true, test);
+    }
+
+    @Test
+    public void testPerformSecondaryVisibilityAnimation() {
+        mView.setInvisible();
+        assertFalse(mView.isSecondaryVisible());
+
+        Runnable test = new Runnable() {
+            @Override
+            public void run() {
+                assertEquals(0.0f, mView.findContentView().getAlpha());
+                assertEquals(1.0f, mView.findSecondaryView().getAlpha());
+                assertTrue(mView.isSecondaryVisible());
+            }
+        };
+        mView.performSecondaryVisibilityAnimation(true, test);
+    }
+}
+
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index a37947d..67453d5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -22,6 +22,7 @@
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.spy;
@@ -307,4 +308,12 @@
                     mBouncer.isSecure(), mode != KeyguardSecurityModel.SecurityMode.None);
         }
     }
+
+    @Test
+    public void testWillDismissWithAction() {
+        mBouncer.ensureView();
+        Assert.assertFalse("Action not set yet", mBouncer.willDismissWithAction());
+        when(mKeyguardHostView.hasDismissActions()).thenReturn(true);
+        Assert.assertTrue("Action should exist", mBouncer.willDismissWithAction());
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 45845fc..7743c6b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -39,10 +39,8 @@
 import android.support.test.filters.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
-import android.view.Choreographer;
 import android.view.View;
 
-import com.android.internal.util.Preconditions;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.ScrimView;
@@ -557,8 +555,8 @@
          * @param callback What to execute.
          */
         @Override
-        protected void doOnTheNextFrame(Choreographer.FrameCallback callback) {
-            callback.doFrame(0);
+        protected void doOnTheNextFrame(Runnable callback) {
+            callback.run();
         }
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index f13fa4e..f81ffd8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -18,7 +18,9 @@
 
 import static android.app.NotificationManager.IMPORTANCE_HIGH;
 
+import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertTrue;
 import static junit.framework.TestCase.fail;
 
@@ -55,6 +57,8 @@
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 import android.util.SparseArray;
+import android.view.Gravity;
+import android.view.View;
 import android.view.ViewGroup.LayoutParams;
 
 import com.android.internal.logging.MetricsLogger;
@@ -65,13 +69,15 @@
 import com.android.systemui.ForegroundServiceController;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.UiOffloadThread;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.statusbar.ActivatableNotificationView;
 import com.android.systemui.statusbar.AppOpsListener;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.FooterView;
+import com.android.systemui.statusbar.FooterViewButton;
 import com.android.systemui.statusbar.KeyguardIndicationController;
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.NotificationData.Entry;
@@ -88,7 +94,6 @@
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
@@ -97,12 +102,14 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
 import java.io.ByteArrayOutputStream;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.function.Predicate;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
@@ -558,6 +565,68 @@
         verify(mScrimController).setKeyguardOccluded(eq(false));
     }
 
+    @Test
+    public void testInflateFooterView() {
+        mStatusBar.reevaluateStyles();
+        ArgumentCaptor<FooterView> captor = ArgumentCaptor.forClass(FooterView.class);
+        verify(mStackScroller).setFooterView(captor.capture());
+
+        assertNotNull(captor.getValue().findViewById(R.id.manage_text).hasOnClickListeners());
+        assertNotNull(captor.getValue().findViewById(R.id.dismiss_text).hasOnClickListeners());
+    }
+
+    @Test
+    public void testUpdateFooter_noNotifications() {
+        mStatusBar.setBarStateForTest(StatusBarState.SHADE);
+        assertEquals(0, mEntryManager.getNotificationData().getActiveNotifications().size());
+
+        mStatusBar.updateFooter();
+        verify(mStackScroller).updateFooterView(false, false);
+    }
+
+    @Test
+    public void testUpdateFooter_oneClearableNotification() {
+        mStatusBar.setBarStateForTest(StatusBarState.SHADE);
+        ArrayList<Entry> entries = new ArrayList<>();
+        entries.add(mock(Entry.class));
+        when(mNotificationData.getActiveNotifications()).thenReturn(entries);
+
+        ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
+        when(row.canViewBeDismissed()).thenReturn(true);
+        when(mStackScroller.getChildCount()).thenReturn(1);
+        when(mStackScroller.getChildAt(anyInt())).thenReturn(row);
+
+        mStatusBar.updateFooter();
+        verify(mStackScroller).updateFooterView(true, true);
+    }
+
+    @Test
+    public void testUpdateFooter_oneNonClearableNotification() {
+        mStatusBar.setBarStateForTest(StatusBarState.SHADE);
+        ArrayList<Entry> entries = new ArrayList<>();
+        entries.add(mock(Entry.class));
+        when(mNotificationData.getActiveNotifications()).thenReturn(entries);
+
+        mStatusBar.updateFooter();
+        verify(mStackScroller).updateFooterView(true, false);
+    }
+
+    @Test
+    public void testUpdateFooter_atEnd() {
+        // add footer
+        mStatusBar.reevaluateStyles();
+
+        // add notification
+        ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
+        when(row.isClearable()).thenReturn(true);
+        mStackScroller.addContainerView(row);
+
+        mStatusBar.onUpdateRowStates();
+
+        // move footer to end
+        verify(mStackScroller).changeViewPosition(any(FooterView.class), eq(-1 /* end */));
+    }
+
     static class TestableStatusBar extends StatusBar {
         public TestableStatusBar(StatusBarKeyguardViewManager man,
                 UnlockMethodCache unlock, KeyguardIndicationController key,
@@ -587,6 +656,7 @@
             mScrimController = scrimController;
             mFingerprintUnlockController = fingerprintUnlockController;
             mActivityLaunchAnimator = launchAnimator;
+            mClearAllEnabled = true;
         }
 
         private WakefulnessLifecycle createAwakeWakefulnessLifecycle() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
index 2afb48c..ed0f9ab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
@@ -18,7 +18,6 @@
 import android.os.HandlerThread;
 import android.support.test.runner.AndroidJUnit4;
 import android.telephony.SubscriptionInfo;
-import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
@@ -81,7 +80,8 @@
         boolean in = true;
         boolean out = true;
         String description = "Test";
-        mHandler.setWifiIndicators(enabled, status, qs, in, out, description, true);
+        String secondaryLabel = "Secondary label";
+        mHandler.setWifiIndicators(enabled, status, qs, in, out, description, true, secondaryLabel);
         waitForCallbacks();
 
         ArgumentCaptor<Boolean> enableArg = ArgumentCaptor.forClass(Boolean.class);
@@ -91,9 +91,10 @@
         ArgumentCaptor<Boolean> outArg = ArgumentCaptor.forClass(Boolean.class);
         ArgumentCaptor<String> descArg = ArgumentCaptor.forClass(String.class);
         ArgumentCaptor<Boolean> isTransient = ArgumentCaptor.forClass(Boolean.class);
+        ArgumentCaptor<String> secondary = ArgumentCaptor.forClass(String.class);
         Mockito.verify(mSignalCallback).setWifiIndicators(enableArg.capture(),
                 statusArg.capture(), qsArg.capture(), inArg.capture(), outArg.capture(),
-                descArg.capture(), isTransient.capture());
+                descArg.capture(), isTransient.capture(), secondary.capture());
         assertEquals(enabled, (boolean) enableArg.getValue());
         assertEquals(status, statusArg.getValue());
         assertEquals(qs, qsArg.getValue());
@@ -101,6 +102,7 @@
         assertEquals(out, (boolean) outArg.getValue());
         assertEquals(description, descArg.getValue());
         assertTrue(isTransient.getValue());
+        assertEquals(secondaryLabel, secondary.getValue());
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
index fc3de84..d30e777 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
@@ -5,8 +5,6 @@
 import android.net.NetworkInfo;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
-import android.net.wifi.WifiSsid;
-import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
@@ -20,6 +18,7 @@
 
 import static junit.framework.Assert.assertEquals;
 
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Mockito.when;
@@ -39,6 +38,7 @@
         verifyLastWifiIcon(false, WifiIcons.WIFI_NO_NETWORK);
 
         setWifiState(true, testSsid);
+        setWifiLevel(0);
         verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[0][0]);
 
         for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) {
@@ -160,7 +160,8 @@
         ArgumentCaptor<Boolean> outArg = ArgumentCaptor.forClass(Boolean.class);
 
         Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators(
-                anyBoolean(), any(), any(), inArg.capture(), outArg.capture(), any(), anyBoolean());
+                anyBoolean(), any(), any(), inArg.capture(), outArg.capture(), any(), anyBoolean(),
+                any());
         assertEquals("WiFi data in, in quick settings", in, (boolean) inArg.getValue());
         assertEquals("WiFi data out, in quick settings", out, (boolean) outArg.getValue());
     }
@@ -173,7 +174,7 @@
 
         Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators(
                 enabledArg.capture(), any(), iconArg.capture(), anyBoolean(),
-                anyBoolean(), descArg.capture(), anyBoolean());
+                anyBoolean(), descArg.capture(), anyBoolean(), any());
         IconState iconState = iconArg.getValue();
         assertEquals("WiFi enabled, in quick settings", enabled, (boolean) enabledArg.getValue());
         assertEquals("WiFi connected, in quick settings", connected, iconState.visible);
@@ -186,7 +187,7 @@
 
         Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators(
                 anyBoolean(), iconArg.capture(), any(), anyBoolean(), anyBoolean(),
-                any(), anyBoolean());
+                any(), anyBoolean(), any());
         IconState iconState = iconArg.getValue();
         assertEquals("WiFi visible, in status bar", visible, iconState.visible);
         assertEquals("WiFi signal, in status bar", icon, iconState.icon);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java
index 6fa91ff..42069e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java
@@ -23,10 +23,12 @@
 import android.support.test.annotation.UiThreadTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
 
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.EmptyShadeView;
+import com.android.systemui.statusbar.FooterView;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.phone.StatusBar;
@@ -94,4 +96,30 @@
 
         verify(view).setText(R.string.empty_shade_text);
     }
+
+    @Test
+    public void manageNotifications_visible() {
+        FooterView view = mock(FooterView.class);
+        mStackScroller.setFooterView(view);
+        when(view.willBeGone()).thenReturn(true);
+        when(view.isSecondaryVisible()).thenReturn(true);
+
+        mStackScroller.updateFooterView(true, false);
+
+        verify(view).setVisibility(View.VISIBLE);
+        verify(view).performSecondaryVisibilityAnimation(false);
+    }
+
+    @Test
+    public void clearAll_visible() {
+        FooterView view = mock(FooterView.class);
+        mStackScroller.setFooterView(view);
+        when(view.willBeGone()).thenReturn(true);
+        when(view.isSecondaryVisible()).thenReturn(false);
+
+        mStackScroller.updateFooterView(true, true);
+
+        verify(view).setVisibility(View.VISIBLE);
+        verify(view).performSecondaryVisibilityAnimation(true);
+    }
 }
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 9417f04..c6878d7 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5547,6 +5547,21 @@
     // OS: P
     ACTION_ANOMALY_TRIGGERED = 1367;
 
+    // ACTION: Settings > Condition > Device muted
+    // CATEGORY: SETTINGS
+    // OS: P
+    SETTINGS_CONDITION_DEVICE_MUTED = 1368;
+
+    // ACTION: Settings > Condition > Device vibrate
+    // CATEGORY: SETTINGS
+    // OS: P
+    SETTINGS_CONDITION_DEVICE_VIBRATE = 1369;
+
+    // OPEN: Settings > Connected devices > previously connected devices
+    // CATEGORY: SETTINGS
+    // OS: P
+    PREVIOUSLY_CONNECTED_DEVICES = 1370;
+
     // ---- End P Constants, all P constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index 39d0070..9c74188 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -382,6 +382,9 @@
 
   // WifiWake statistics
   optional WifiWakeStats wifi_wake_stats = 94;
+
+  // Histogram counting instances of scans with N many 802.11mc (RTT) supporting APs
+  repeated NumConnectableNetworksBucket observed_80211mc_supporting_aps_in_scan_histogram = 95;
 }
 
 // Information that gets logged for every WiFi connection.
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index 7bb532e..58f78ec 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -180,9 +180,11 @@
      *
      * @param structure Assist structure
      * @param urlBarIds list of ids; only the first id found will be sanitized.
+     *
+     * @return the node containing the URL bar
      */
     @Nullable
-    public static void sanitizeUrlBar(@NonNull AssistStructure structure,
+    public static ViewNode sanitizeUrlBar(@NonNull AssistStructure structure,
             @NonNull String[] urlBarIds) {
         final ViewNode urlBarNode = findViewNode(structure, (node) -> {
             return ArrayUtils.contains(urlBarIds, node.getIdEntry());
@@ -191,7 +193,7 @@
             final String domain = urlBarNode.getText().toString();
             if (domain.isEmpty()) {
                 if (sDebug) Slog.d(TAG, "sanitizeUrlBar(): empty on " + urlBarNode.getIdEntry());
-                return;
+                return null;
             }
             urlBarNode.setWebDomain(domain);
             if (sDebug) {
@@ -199,6 +201,7 @@
                         + urlBarNode.getWebDomain());
             }
         }
+        return urlBarNode;
     }
 
     private interface ViewNodeFilter {
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 1e1de35..bcb0bc4 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -146,6 +146,13 @@
     /** Whether the app being autofilled is running in compat mode. */
     private final boolean mCompatMode;
 
+    /** Node representing the URL bar on compat mode. */
+    @GuardedBy("mLock")
+    private ViewNode mUrlBar;
+
+    @GuardedBy("mLock")
+    private boolean mSaveOnAllViewsInvisible;
+
     @GuardedBy("mLock")
     private final ArrayMap<AutofillId, ViewState> mViewStates = new ArrayMap<>();
 
@@ -280,7 +287,17 @@
                         Slog.d(TAG, "url_bars in compat mode: " + Arrays.toString(urlBarIds));
                     }
                     if (urlBarIds != null) {
-                        Helper.sanitizeUrlBar(structure, urlBarIds);
+                        mUrlBar = Helper.sanitizeUrlBar(structure, urlBarIds);
+                        if (mUrlBar != null) {
+                            final AutofillId urlBarId = mUrlBar.getAutofillId();
+                            if (sDebug) {
+                                Slog.d(TAG, "Setting urlBar as id=" + urlBarId + " and domain "
+                                        + mUrlBar.getWebDomain());
+                            }
+                            final ViewState viewState = new ViewState(Session.this, urlBarId,
+                                    Session.this, ViewState.STATE_URL_BAR);
+                            mViewStates.put(urlBarId, viewState);
+                        }
                     }
                 }
                 structure.sanitizeForParceling(true);
@@ -1878,14 +1895,15 @@
             return;
         }
         if (sVerbose) {
-            Slog.v(TAG, "updateLocked(): id=" + id + ", action=" + action + ", flags=" + flags);
+            Slog.v(TAG, "updateLocked(): id=" + id + ", action=" + actionAsString(action)
+                    + ", flags=" + flags);
         }
         ViewState viewState = mViewStates.get(id);
 
         if (viewState == null) {
             if (action == ACTION_START_SESSION || action == ACTION_VALUE_CHANGED
                     || action == ACTION_VIEW_ENTERED) {
-                if (sVerbose) Slog.v(TAG, "Creating viewState for " + id + " on " + action);
+                if (sVerbose) Slog.v(TAG, "Creating viewState for " + id);
                 boolean isIgnored = isIgnoredLocked(id);
                 viewState = new ViewState(this, id, this,
                         isIgnored ? ViewState.STATE_IGNORED : ViewState.STATE_INITIAL);
@@ -1895,11 +1913,11 @@
                 // detectable, and batch-send them when the session is finished (but that will
                 // require tracking detectable fields on AutofillManager)
                 if (isIgnored) {
-                    if (sDebug) Slog.d(TAG, "updateLocked(): ignoring view " + id);
+                    if (sDebug) Slog.d(TAG, "updateLocked(): ignoring view " + viewState);
                     return;
                 }
             } else {
-                if (sVerbose) Slog.v(TAG, "Ignored action " + action + " for " + id);
+                if (sVerbose) Slog.v(TAG, "Ignoring specific action when viewState=null");
                 return;
             }
         }
@@ -1913,6 +1931,40 @@
                 requestNewFillResponseLocked(flags);
                 break;
             case ACTION_VALUE_CHANGED:
+                if (mCompatMode && (viewState.getState() & ViewState.STATE_URL_BAR) != 0) {
+                    // Must cancel the session if the value of the URL bar changed
+                    final String currentUrl = mUrlBar == null ? null
+                            : mUrlBar.getText().toString().trim();
+                    if (currentUrl == null) {
+                        // Sanity check - shouldn't happen.
+                        wtf(null, "URL bar value changed, but current value is null");
+                        return;
+                    }
+                    if (value == null || ! value.isText()) {
+                        // Sanity check - shouldn't happen.
+                        wtf(null, "URL bar value changed to null or non-text: %s", value);
+                        return;
+                    }
+                    final String newUrl = value.getTextValue().toString();
+                    if (newUrl.equals(currentUrl)) {
+                        if (sDebug) Slog.d(TAG, "Ignoring change on URL bar as it's the same");
+                        return;
+                    }
+                    if (mSaveOnAllViewsInvisible) {
+                        // We cannot cancel the session because it could hinder Save when all views
+                        // are finished, as the URL bar changed callback is usually called before
+                        // the virtual views become invisible.
+                        if (sDebug) {
+                            Slog.d(TAG, "Ignoring change on URL because session will finish when "
+                                    + "views are gone");
+                        }
+                        return;
+                    }
+                    if (sDebug) Slog.d(TAG, "Finishing session because URL bar changed");
+                    forceRemoveSelfLocked(AutofillManager.STATE_UNKNOWN_COMPAT_MODE);
+                    return;
+                }
+
                 if (value != null && !value.equals(viewState.getCurrentValue())) {
                     if (value.isEmpty()
                             && viewState.getCurrentValue() != null
@@ -1953,6 +2005,12 @@
                 if (sVerbose && virtualBounds != null) {
                     Slog.v(TAG, "entered on virtual child " + id + ": " + virtualBounds);
                 }
+
+                if (mCompatMode && (viewState.getState() & ViewState.STATE_URL_BAR) != 0) {
+                    if (sDebug) Slog.d(TAG, "Ignoring VIEW_ENTERED on URL BAR (id=" + id + ")");
+                    return;
+                }
+
                 requestNewFillResponseOnViewEnteredIfNecessaryLocked(id, viewState, flags);
 
                 // Remove the UI if the ViewState has changed.
@@ -2068,7 +2126,7 @@
         if (response == null) return;
 
         ArraySet<AutofillId> trackedViews = null;
-        boolean saveOnAllViewsInvisible = false;
+        mSaveOnAllViewsInvisible = false;
         boolean saveOnFinish = true;
         final SaveInfo saveInfo = response.getSaveInfo();
         final AutofillId saveTriggerId;
@@ -2081,10 +2139,10 @@
             if (mCompatMode) {
                 flags |= SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE;
             }
-            saveOnAllViewsInvisible = (flags & SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE) != 0;
+            mSaveOnAllViewsInvisible = (flags & SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE) != 0;
 
             // We only need to track views if we want to save once they become invisible.
-            if (saveOnAllViewsInvisible) {
+            if (mSaveOnAllViewsInvisible) {
                 if (trackedViews == null) {
                     trackedViews = new ArraySet<>();
                 }
@@ -2129,7 +2187,7 @@
                 Slog.v(TAG, "updateTrackedIdsLocked(): " + trackedViews + " => " + fillableIds
                         + " triggerId: " + saveTriggerId + " saveOnFinish:" + saveOnFinish);
             }
-            mClient.setTrackedViews(id, toArray(trackedViews), saveOnAllViewsInvisible,
+            mClient.setTrackedViews(id, toArray(trackedViews), mSaveOnAllViewsInvisible,
                     saveOnFinish, toArray(fillableIds), saveTriggerId);
         } catch (RemoteException e) {
             Slog.w(TAG, "Cannot set tracked ids", e);
@@ -2421,6 +2479,16 @@
         pw.print(prefix); pw.print("mClientState: "); pw.println(
                 Helper.bundleToString(mClientState));
         pw.print(prefix); pw.print("mCompatMode: "); pw.println(mCompatMode);
+        pw.print(prefix); pw.print("mUrlBar: ");
+        if (mUrlBar == null) {
+            pw.println("N/A");
+        } else {
+            pw.print("id="); pw.print(mUrlBar.getAutofillId());
+            pw.print(" domain="); pw.print(mUrlBar.getWebDomain());
+            pw.print(" text="); Helper.printlnRedactedText(pw, mUrlBar.getText());
+        }
+        pw.print(prefix); pw.print("mSaveOnAllViewsInvisible: "); pw.println(
+                mSaveOnAllViewsInvisible);
         pw.print(prefix); pw.print("mSelectedDatasetIds: "); pw.println(mSelectedDatasetIds);
         mRemoteFillService.dump(prefix, pw);
     }
@@ -2513,6 +2581,11 @@
      */
     @GuardedBy("mLock")
     void forceRemoveSelfLocked() {
+        forceRemoveSelfLocked(AutofillManager.STATE_UNKNOWN);
+    }
+
+    @GuardedBy("mLock")
+    void forceRemoveSelfLocked(int clientState) {
         if (sVerbose) Slog.v(TAG, "forceRemoveSelfLocked(): " + mPendingSaveUi);
 
         final boolean isPendingSaveUi = isSaveUiPendingLocked();
@@ -2521,7 +2594,7 @@
         mUi.destroyAll(mPendingSaveUi, this, false);
         if (!isPendingSaveUi) {
             try {
-                mClient.setSessionFinished(AutofillManager.STATE_UNKNOWN);
+                mClient.setSessionFinished(clientState);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Error notifying client to finish session", e);
             }
@@ -2624,4 +2697,19 @@
             Slog.wtf(TAG, message);
         }
     }
+
+    private static String actionAsString(int action) {
+        switch (action) {
+            case ACTION_START_SESSION:
+                return "START_SESSION";
+            case ACTION_VIEW_ENTERED:
+                return "VIEW_ENTERED";
+            case ACTION_VIEW_EXITED:
+                return "VIEW_EXITED";
+            case ACTION_VALUE_CHANGED:
+                return "VALUE_CHANGED";
+            default:
+                return "UNKNOWN_" + action;
+        }
+    }
 }
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index 03c5850..97ab97b 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -67,6 +67,8 @@
     public static final int STATE_IGNORED = 0x080;
     /** User manually request autofill in this view, after it was already autofilled. */
     public static final int STATE_RESTARTED_SESSION = 0x100;
+    /** View is the URL bar of a package on compat mode. */
+    public  static final int STATE_URL_BAR = 0x200;
 
     public final AutofillId id;
 
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 02b1380..8d10cfa 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -60,6 +60,7 @@
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.util.Slog;
+import android.util.StatsLog;
 
 import com.android.internal.R;
 import com.android.internal.util.DumpUtils;
@@ -632,23 +633,14 @@
             if (DBG) {
                 Slog.d(TAG, "Binder is dead - unregister " + mPackageName);
             }
-            if (isBleAppPresent()) {
-                // Nothing to do, another app is here.
-                return;
-            }
-            if (DBG) {
-                Slog.d(TAG, "Disabling LE only mode after application crash");
-            }
-            try {
-                mBluetoothLock.readLock().lock();
-                if (mBluetooth != null && mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) {
-                    mEnable = false;
-                    mBluetooth.onBrEdrDown();
+
+            for (Map.Entry<IBinder, ClientDeathRecipient> entry : mBleApps.entrySet()) {
+                IBinder token = entry.getKey();
+                ClientDeathRecipient deathRec = entry.getValue();
+                if (deathRec.equals(this)) {
+                    updateBleAppCount(token, false, mPackageName);
+                    break;
                 }
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Unable to call onBrEdrDown", e);
-            } finally {
-                mBluetoothLock.readLock().unlock();
             }
         }
 
@@ -2178,6 +2170,11 @@
             mActiveLogs.add(
                     new ActiveLog(reason, packageName, enable, System.currentTimeMillis()));
         }
+
+        int state = enable ? StatsLog.BLUETOOTH_ENABLED_STATE_CHANGED__STATE__ENABLED :
+                             StatsLog.BLUETOOTH_ENABLED_STATE_CHANGED__STATE__DISABLED;
+        StatsLog.write_non_chained(StatsLog.BLUETOOTH_ENABLED_STATE_CHANGED,
+                Binder.getCallingUid(), null, state, reason, packageName);
     }
 
     private void addCrashLog() {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 5e99189..91d3afb 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -101,6 +101,8 @@
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
 import android.os.ServiceSpecificException;
+import android.os.ShellCallback;
+import android.os.ShellCommand;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -5848,4 +5850,61 @@
     private static int encodeBool(boolean b) {
         return b ? 1 : 0;
     }
-}
+
+    @Override
+    public void onShellCommand(FileDescriptor in, FileDescriptor out,
+            FileDescriptor err, String[] args, ShellCallback callback,
+            ResultReceiver resultReceiver) {
+        (new ShellCmd()).exec(this, in, out, err, args, callback, resultReceiver);
+    }
+
+    private class ShellCmd extends ShellCommand {
+
+        @Override
+        public int onCommand(String cmd) {
+            if (cmd == null) {
+                return handleDefaultCommands(cmd);
+            }
+            final PrintWriter pw = getOutPrintWriter();
+            try {
+                switch (cmd) {
+                    case "airplane-mode":
+                        final String action = getNextArg();
+                        if ("enable".equals(action)) {
+                            setAirplaneMode(true);
+                            return 0;
+                        } else if ("disable".equals(action)) {
+                            setAirplaneMode(false);
+                            return 0;
+                        } else if (action == null) {
+                            final ContentResolver cr = mContext.getContentResolver();
+                            final int enabled = Settings.Global.getInt(cr,
+                                    Settings.Global.AIRPLANE_MODE_ON);
+                            pw.println(enabled == 0 ? "disabled" : "enabled");
+                            return 0;
+                        } else {
+                            onHelp();
+                            return -1;
+                        }
+                    default:
+                        return handleDefaultCommands(cmd);
+                }
+            } catch (Exception e) {
+                pw.println(e);
+            }
+            return -1;
+        }
+
+        @Override
+        public void onHelp() {
+            PrintWriter pw = getOutPrintWriter();
+            pw.println("Connectivity service commands:");
+            pw.println("  help");
+            pw.println("    Print this help text.");
+            pw.println("  airplane-mode [enable|disable]");
+            pw.println("    Turn airplane mode on or off.");
+            pw.println("  airplane-mode");
+            pw.println("    Get airplane mode.");
+        }
+    }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/PruneInstantAppsJobService.java b/services/core/java/com/android/server/PruneInstantAppsJobService.java
index a6c3685..48e3a43 100644
--- a/services/core/java/com/android/server/PruneInstantAppsJobService.java
+++ b/services/core/java/com/android/server/PruneInstantAppsJobService.java
@@ -23,6 +23,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManagerInternal;
+import android.os.AsyncTask;
 
 import java.util.concurrent.TimeUnit;
 
@@ -47,10 +48,12 @@
 
     @Override
     public boolean onStartJob(JobParameters params) {
-        PackageManagerInternal packageManagerInternal = LocalServices.getService(
-                PackageManagerInternal.class);
-        packageManagerInternal.pruneInstantApps();
-        jobFinished(params, false);
+        AsyncTask.execute(() -> {
+            PackageManagerInternal packageManagerInternal = LocalServices.getService(
+                    PackageManagerInternal.class);
+            packageManagerInternal.pruneInstantApps();
+            jobFinished(params, false);
+        });
         return true;
     }
 
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 3d7b21d..379658f 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -2668,6 +2668,9 @@
         final int userId = UserHandle.getUserId(Binder.getCallingUid());
         final UserEnvironment userEnv = new UserEnvironment(userId);
 
+        // Ignore requests to create directories while storage is locked
+        if (!isUserKeyUnlocked(userId)) return;
+
         // Validate that reported package name belongs to caller
         final AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(
                 Context.APP_OPS_SERVICE);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4f0acf7..5131a93 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -281,6 +281,7 @@
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.ApplicationInfo.HiddenApiEnforcementPolicy;
 import android.content.pm.ConfigurationInfo;
 import android.content.pm.IPackageDataObserver;
 import android.content.pm.IPackageManager;
@@ -1266,6 +1267,8 @@
         }
     }
 
+    boolean mSystemProvidersInstalled;
+
     CoreSettingsObserver mCoreSettingsObserver;
 
     FontScaleSettingObserver mFontScaleSettingObserver;
@@ -4183,12 +4186,14 @@
                 runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES;
             }
 
-            if (!app.info.isAllowedToUseHiddenApi() &&
-                    !disableHiddenApiChecks &&
-                    !mHiddenApiBlacklist.isDisabled()) {
-                // This app is not allowed to use undocumented and private APIs, or blacklisting is
-                // enabled. Set up its runtime with the appropriate flag.
-                runtimeFlags |= Zygote.ENABLE_HIDDEN_API_CHECKS;
+            if (!disableHiddenApiChecks && !mHiddenApiBlacklist.isDisabled()) {
+                @HiddenApiEnforcementPolicy int policy =
+                        app.info.getHiddenApiEnforcementPolicy();
+                int policyBits = (policy << Zygote.API_ENFORCEMENT_POLICY_SHIFT);
+                if ((policyBits & Zygote.API_ENFORCEMENT_POLICY_MASK) != policyBits) {
+                    throw new IllegalStateException("Invalid API policy: " + policy);
+                }
+                runtimeFlags |= policyBits;
             }
 
             String invokeWith = null;
@@ -12110,6 +12115,14 @@
                             "Attempt to launch content provider before system ready");
                 }
 
+                // If system providers are not installed yet we aggressively crash to avoid
+                // creating multiple instance of these providers and then bad things happen!
+                if (!mSystemProvidersInstalled && cpi.applicationInfo.isSystemApp()
+                        && "system".equals(cpi.processName)) {
+                    throw new IllegalStateException("Cannot access system provider: '"
+                            + cpi.authority + "' before system providers are installed!");
+                }
+
                 // Make sure that the user who owns this provider is running.  If not,
                 // we don't want to allow it to run.
                 if (!mUserController.isUserRunning(userId, 0)) {
@@ -12663,6 +12676,10 @@
             mSystemThread.installSystemProviders(providers);
         }
 
+        synchronized (this) {
+            mSystemProvidersInstalled = true;
+        }
+
         mConstants.start(mContext.getContentResolver());
         mCoreSettingsObserver = new CoreSettingsObserver(this);
         mFontScaleSettingObserver = new FontScaleSettingObserver();
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index 1335ced..efd8153 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -1243,15 +1243,13 @@
      */
     private int findRemoveIndexForAddTask(TaskRecord task) {
         final int recentsCount = mTasks.size();
-        final int taskActivityType = task.getActivityType();
         final Intent intent = task.intent;
         final boolean document = intent != null && intent.isDocument();
         int maxRecents = task.maxRecents - 1;
         for (int i = 0; i < recentsCount; i++) {
             final TaskRecord tr = mTasks.get(i);
-            final int trActivityType = tr.getActivityType();
             if (task != tr) {
-                if (taskActivityType != trActivityType || task.userId != tr.userId) {
+                if (!task.hasCompatibleActivityType(tr)) {
                     continue;
                 }
                 final Intent trIntent = tr.intent;
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 776e93d..3f39f45 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -368,6 +368,19 @@
         return related;
     }
 
+    /** Check if the user has the given restriction set. Default to true if error occured during
+     * calling UserManager, so it fails safe.
+     */
+    private boolean hasRestriction(String restriction, int userId) {
+        try {
+            return mUm.hasUserRestriction(restriction, userId);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Remote Exception calling UserManager.getUserRestrictions: ", e);
+            // Fails safe
+            return true;
+        }
+    }
+
     void setPrimaryClipInternal(@Nullable ClipData clip, int callingUid) {
         // Push clipboard to host, if any
         if (mHostClipboardMonitor != null) {
@@ -391,13 +404,8 @@
         if (related != null) {
             int size = related.size();
             if (size > 1) { // Related profiles list include the current profile.
-                boolean canCopy = false;
-                try {
-                    canCopy = !mUm.getUserRestrictions(userId).getBoolean(
-                            UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "Remote Exception calling UserManager: " + e);
-                }
+                final boolean canCopy = !hasRestriction(
+                        UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE, userId);
                 // Copy clip data to related users if allowed. If disallowed, then remove
                 // primary clip in related users to prevent pasting stale content.
                 if (!canCopy) {
@@ -416,7 +424,11 @@
                 for (int i = 0; i < size; i++) {
                     int id = related.get(i).id;
                     if (id != userId) {
-                        setPrimaryClipInternal(getClipboard(id), clip, callingUid);
+                        final boolean canCopyIntoProfile = !hasRestriction(
+                                UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, id);
+                        if (canCopyIntoProfile) {
+                            setPrimaryClipInternal(getClipboard(id), clip, callingUid);
+                        }
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index d578e95..e471c7d 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -202,7 +202,9 @@
             // Only using the first package name. There may be multiple names if multiple
             // apps share the same UID, but in that case they also share permissions so
             // querying with any of the names will return the same results.
-            final PackageInfo app = mPackageManager.getPackageInfo(names[0], GET_PERMISSIONS);
+            int userId = UserHandle.getUserId(uid);
+            final PackageInfo app = mPackageManager.getPackageInfoAsUser(
+                    names[0], GET_PERMISSIONS, userId);
             return hasUseBackgroundNetworksPermission(app);
         } catch (NameNotFoundException e) {
             // App not found.
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index 4313d17..711d40b 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -60,8 +60,14 @@
         int[] backlightRange = resources.getIntArray(
                 com.android.internal.R.array.config_screenBrightnessBacklight);
 
+        float[] minimumBrightnessCurveLux = getLuxLevels(resources.getIntArray(
+                com.android.internal.R.array.config_autoBrightnessMinimumBrightnessCurveLux));
+        float[] minimumBrightnessCurveNits = getFloatArray(resources.obtainTypedArray(
+                com.android.internal.R.array.config_autoBrightnessMinimumBrightnessCurveNits));
+
         if (isValidMapping(nitsRange, backlightRange)
-                && isValidMapping(luxLevels, brightnessLevelsNits)) {
+                && isValidMapping(luxLevels, brightnessLevelsNits)
+                && isValidMapping(minimumBrightnessCurveLux, minimumBrightnessCurveNits)) {
             int minimumBacklight = resources.getInteger(
                     com.android.internal.R.integer.config_screenBrightnessSettingMinimum);
             int maximumBacklight = resources.getInteger(
@@ -73,7 +79,8 @@
             }
             BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
             builder.setCurve(luxLevels, brightnessLevelsNits);
-            return new PhysicalMappingStrategy(builder.build(), nitsRange, backlightRange);
+            return new PhysicalMappingStrategy(builder.build(), nitsRange, backlightRange,
+                    minimumBrightnessCurveLux, minimumBrightnessCurveNits);
         } else if (isValidMapping(luxLevels, brightnessLevelsBacklight)) {
             return new SimpleMappingStrategy(luxLevels, brightnessLevelsBacklight);
         } else {
@@ -448,8 +455,11 @@
         private float mUserLux;
         private float mUserBrightness;
 
+        private final Spline mMinimumBrightnessCurve;
+
         public PhysicalMappingStrategy(BrightnessConfiguration config,
-                float[] nits, int[] backlight) {
+                float[] nits, int[] backlight, float[] minimumBrightnessCurveLux,
+                float[] minimumBrightnessCurveNits) {
             Preconditions.checkArgument(nits.length != 0 && backlight.length != 0,
                     "Nits and backlight arrays must not be empty!");
             Preconditions.checkArgument(nits.length == backlight.length,
@@ -469,6 +479,9 @@
                 normalizedBacklight[i] = normalizeAbsoluteBrightness(backlight[i]);
             }
 
+            mMinimumBrightnessCurve = Spline.createSpline(
+                minimumBrightnessCurveLux, minimumBrightnessCurveNits);
+
             mNitsToBacklightSpline = createSpline(nits, normalizedBacklight);
             mBacklightToNitsSpline = createSpline(normalizedBacklight, nits);
 
@@ -484,7 +497,7 @@
             if (config.equals(mConfig)) {
                 return false;
             }
-
+            validateBrightnessConfiguration(config);
             Pair<float[], float[]> curve = config.getCurve();
             mBrightnessSpline = createSpline(curve.first /*lux*/, curve.second /*nits*/);
             mConfig = config;
@@ -549,5 +562,24 @@
             pw.println("  mUserLux=" + mUserLux);
             pw.println("  mUserBrightness=" + mUserBrightness);
         }
+
+        private void validateBrightnessConfiguration(BrightnessConfiguration config) {
+            Pair<float[], float[]> curve = config.getCurve();
+            Spline brightnessSpline = Spline.createSpline(curve.first, curve.second);
+            if (isBrightnessSplineTooDark(brightnessSpline)) {
+                throw new IllegalArgumentException("brightness curve is too dark");
+            }
+        }
+
+        private boolean isBrightnessSplineTooDark(Spline brightnessSpline) {
+            float[] lux = mDefaultConfig.getCurve().first;
+            for (int i = 0; i < lux.length; i++) {
+                if (brightnessSpline.interpolate(lux[i]) <
+                        mMinimumBrightnessCurve.interpolate(lux[i])) {
+                    return true;
+                }
+            }
+            return false;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index ff8b88b..1784ef1 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -500,7 +500,7 @@
     }
 
     public void onSwitchUser(@UserIdInt int newUserId) {
-        handleSettingsChange();
+        handleSettingsChange(true /* userSwitch */);
         mBrightnessTracker.onSwitchUser(newUserId);
     }
 
@@ -1420,8 +1420,12 @@
         mHandler.post(mOnStateChangedRunnable);
     }
 
-    private void handleSettingsChange() {
+    private void handleSettingsChange(boolean userSwitch) {
         mPendingScreenBrightnessSetting = getScreenBrightnessSetting();
+        if (userSwitch) {
+            // Don't treat user switches as user initiated change.
+            mCurrentScreenBrightnessSetting = mPendingScreenBrightnessSetting;
+        }
         mPendingAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting();
         // We don't bother with a pending variable for VR screen brightness since we just
         // immediately adapt to it.
@@ -1735,7 +1739,7 @@
 
         @Override
         public void onChange(boolean selfChange, Uri uri) {
-            handleSettingsChange();
+            handleSettingsChange(false /* userSwitch */);
         }
     }
 
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
index abe55bb..8365fd2 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -160,7 +160,7 @@
     private static boolean isRelaxedSatisfied(JobStatus jobStatus, Network network,
             NetworkCapabilities capabilities, Constants constants) {
         // Only consider doing this for prefetching jobs
-        if ((jobStatus.getJob().getFlags() & JobInfo.FLAG_IS_PREFETCH) == 0) {
+        if (!jobStatus.getJob().isPrefetch()) {
             return false;
         }
 
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 7c56f4d..f617964 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -21,6 +21,7 @@
 import static android.content.Context.KEYGUARD_SERVICE;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
 import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_ENABLED_KEY;
 import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY;
@@ -524,6 +525,10 @@
 
     public void onCleanupUser(int userId) {
         hideEncryptionNotification(new UserHandle(userId));
+        // User is stopped with its CE key evicted. Require strong auth next time to be able to
+        // unlock the user's storage. Use STRONG_AUTH_REQUIRED_AFTER_BOOT since stopping and
+        // restarting a user later is equivalent to rebooting the device.
+        requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_BOOT, userId);
     }
 
     public void onStartUser(final int userId) {
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index 00abb37..e0487ea 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -317,14 +317,35 @@
         mListenersStorage.setSnapshotListener(uid, intent);
     }
 
+    /**
+     * Set the server params for the user's key chain. This is used to uniquely identify a key
+     * chain. Along with the counter ID, it is used to uniquely identify an instance of a vault.
+     */
     public void setServerParams(@NonNull byte[] serverParams) throws RemoteException {
         checkRecoverKeyStorePermission();
         int userId = UserHandle.getCallingUserId();
         int uid = Binder.getCallingUid();
-        long updatedRows = mDatabase.setServerParams(userId, uid, serverParams);
-        if (updatedRows > 0) {
-            mDatabase.setShouldCreateSnapshot(userId, uid, true);
+
+        byte[] currentServerParams = mDatabase.getServerParams(userId, uid);
+
+        if (Arrays.equals(serverParams, currentServerParams)) {
+            Log.v(TAG, "Not updating server params - same as old value.");
+            return;
         }
+
+        long updatedRows = mDatabase.setServerParams(userId, uid, serverParams);
+        if (updatedRows < 1) {
+            throw new ServiceSpecificException(
+                    ERROR_SERVICE_INTERNAL_ERROR, "Database failure trying to set server params.");
+        }
+
+        if (currentServerParams == null) {
+            Log.i(TAG, "Initialized server params.");
+            return;
+        }
+
+        Log.i(TAG, "Updated server params. Snapshot pending.");
+        mDatabase.setShouldCreateSnapshot(userId, uid, true);
     }
 
     /**
@@ -361,10 +382,26 @@
         Preconditions.checkNotNull(secretTypes, "secretTypes is null");
         int userId = UserHandle.getCallingUserId();
         int uid = Binder.getCallingUid();
-        long updatedRows = mDatabase.setRecoverySecretTypes(userId, uid, secretTypes);
-        if (updatedRows > 0) {
-            mDatabase.setShouldCreateSnapshot(userId, uid, true);
+
+        int[] currentSecretTypes = mDatabase.getRecoverySecretTypes(userId, uid);
+        if (Arrays.equals(secretTypes, currentSecretTypes)) {
+            Log.v(TAG, "Not updating secret types - same as old value.");
+            return;
         }
+
+        long updatedRows = mDatabase.setRecoverySecretTypes(userId, uid, secretTypes);
+        if (updatedRows < 1) {
+            throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR,
+                    "Database error trying to set secret types.");
+        }
+
+        if (currentSecretTypes.length == 0) {
+            Log.i(TAG, "Initialized secret types.");
+            return;
+        }
+
+        Log.i(TAG, "Updated secret types. Snapshot pending.");
+        mDatabase.setShouldCreateSnapshot(userId, uid, true);
     }
 
     /**
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 7348b84..01f0d74 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -1532,7 +1532,7 @@
         @Override
         public boolean createSession2(Bundle sessionToken) {
             final int uid = Binder.getCallingUid();
-            final SessionToken2 token = SessionToken2.fromBundle(getContext(), sessionToken);
+            final SessionToken2 token = SessionToken2.fromBundle(sessionToken);
             if (token == null || token.getUid() != uid) {
                 Log.w(TAG, "onSessionCreated failed, expected caller uid=" + token.getUid()
                         + " but from uid=" + uid);
@@ -1571,7 +1571,7 @@
         @Override
         public void destroySession2(Bundle sessionToken) {
             final int uid = Binder.getCallingUid();
-            final SessionToken2 token = SessionToken2.fromBundle(getContext(), sessionToken);
+            final SessionToken2 token = SessionToken2.fromBundle(sessionToken);
             if (token == null || token.getUid() != uid) {
                 Log.w(TAG, "onSessionDestroyed failed, expected caller uid=" + token.getUid()
                         + " but from uid=" + uid);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index efca159..8febecf 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1141,7 +1141,7 @@
         // TODO: support shared UIDs
         if (maxBytes > 0 && maxBytes > totalBytes / 2) {
             final String[] packageNames = mContext.getPackageManager().getPackagesForUid(maxUid);
-            if (packageNames.length == 1) {
+            if (packageNames != null && packageNames.length == 1) {
                 try {
                     return mContext.getPackageManager().getApplicationInfo(packageNames[0],
                             MATCH_ANY_USER | MATCH_DISABLED_COMPONENTS | MATCH_DIRECT_BOOT_AWARE
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistConfig.java b/services/core/java/com/android/server/net/watchlist/WatchlistConfig.java
index 2714d5e..d793842 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistConfig.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistConfig.java
@@ -107,6 +107,10 @@
      * Reload watchlist by reading config file.
      */
     public void reloadConfig() {
+        if (!mXmlFile.exists()) {
+            // No config file
+            return;
+        }
         try (FileInputStream stream = new FileInputStream(mXmlFile)){
             final List<byte[]> crc32DomainList = new ArrayList<>();
             final List<byte[]> sha256DomainList = new ArrayList<>();
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java b/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java
index f5ba889..e20a510 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java
@@ -87,6 +87,10 @@
     }
 
     public void reloadSettings() {
+        if (!mXmlFile.exists()) {
+            // No settings config
+            return;
+        }
         try (FileInputStream stream = mXmlFile.openRead()){
             XmlPullParser parser = Xml.newPullParser();
             parser.setInput(stream, StandardCharsets.UTF_8.name());
@@ -97,7 +101,7 @@
                     mPrivacySecretKey = parseSecretKey(parser);
                 }
             }
-            Log.i(TAG, "Reload watchlist settings done");
+            Slog.i(TAG, "Reload watchlist settings done");
         } catch (IllegalStateException | NullPointerException | NumberFormatException |
                 XmlPullParserException | IOException | IndexOutOfBoundsException e) {
             Slog.e(TAG, "Failed parsing xml", e);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 27eeb93..59cd561 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1877,13 +1877,13 @@
         return newSuppressedVisualEffects;
     }
 
-    // TODO: log visual differences, not just audible ones
     @GuardedBy("mNotificationLock")
     protected void maybeRecordInterruptionLocked(NotificationRecord r) {
         if (r.isInterruptive()) {
             mAppUsageStats.reportInterruptiveNotification(r.sbn.getPackageName(),
                     r.getChannel().getId(),
                     getRealUserId(r.sbn.getUserId()));
+            logRecentLocked(r);
         }
     }
 
@@ -4344,10 +4344,6 @@
 
                     mNotificationsByKey.put(n.getKey(), r);
 
-                    if (!r.isUpdate) {
-                        logRecentLocked(r);
-                    }
-
                     // Ensure if this is a foreground service that the proper additional
                     // flags are set.
                     if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 9e7ad47..61c6be7 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -47,6 +47,8 @@
 
 import dalvik.system.DexFile;
 
+import static android.content.pm.ApplicationInfo.HIDDEN_API_ENFORCEMENT_NONE;
+
 import static com.android.server.pm.Installer.DEXOPT_BOOTCOMPLETE;
 import static com.android.server.pm.Installer.DEXOPT_DEBUGGABLE;
 import static com.android.server.pm.Installer.DEXOPT_PROFILE_GUIDED;
@@ -532,7 +534,10 @@
         int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0;
         // Some apps are executed with restrictions on hidden API usage. If this app is one
         // of them, pass a flag to dexopt to enable the same restrictions during compilation.
-        int hiddenApiFlag = info.isAllowedToUseHiddenApi() ? 0 : DEXOPT_ENABLE_HIDDEN_API_CHECKS;
+        // TODO we should pass the actual flag value to dexopt, rather than assuming blacklist
+        int hiddenApiFlag = info.getHiddenApiEnforcementPolicy() == HIDDEN_API_ENFORCEMENT_NONE
+                ? 0
+                : DEXOPT_ENABLE_HIDDEN_API_CHECKS;
         // Avoid generating CompactDex for modes that are latency critical.
         final int compilationReason = options.getCompilationReason();
         boolean generateCompactDex = true;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 950d8df..5a63f29 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -10355,7 +10355,7 @@
 
         if (Build.IS_DEBUGGABLE &&
                 pkg.isPrivileged() &&
-                !SystemProperties.getBoolean(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB, true)) {
+                SystemProperties.getBoolean(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB, false)) {
             PackageManagerServiceUtils.logPackageHasUncompressedCode(pkg);
         }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 5060c4d..853081a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -331,18 +331,18 @@
                 ZipEntry entry = it.next();
                 if (entry.getName().endsWith(".dex")) {
                     if (entry.getMethod() != ZipEntry.STORED) {
-                        Slog.wtf(TAG, "APK " + fileName + " has compressed dex code " +
+                        Slog.w(TAG, "APK " + fileName + " has compressed dex code " +
                                 entry.getName());
                     } else if ((entry.getDataOffset() & 0x3) != 0) {
-                        Slog.wtf(TAG, "APK " + fileName + " has unaligned dex code " +
+                        Slog.w(TAG, "APK " + fileName + " has unaligned dex code " +
                                 entry.getName());
                     }
                 } else if (entry.getName().endsWith(".so")) {
                     if (entry.getMethod() != ZipEntry.STORED) {
-                        Slog.wtf(TAG, "APK " + fileName + " has compressed native code " +
+                        Slog.w(TAG, "APK " + fileName + " has compressed native code " +
                                 entry.getName());
                     } else if ((entry.getDataOffset() & (0x1000 - 1)) != 0) {
-                        Slog.wtf(TAG, "APK " + fileName + " has unaligned native code " +
+                        Slog.w(TAG, "APK " + fileName + " has unaligned native code " +
                                 entry.getName());
                     }
                 }
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index bd30c5b..f5b52fc 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1505,6 +1505,9 @@
             return EmptyArray.INT;
         }
         for (PackageParser.Package pkg : pkgList) {
+            if (pkg.requestedPermissions == null) {
+                continue;
+            }
             final int requestedPermCount = pkg.requestedPermissions.size();
             for (int j = 0; j < requestedPermCount; j++) {
                 String permission = pkg.requestedPermissions.get(j);
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index dd88cd1..2ffc4e7 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -64,6 +64,7 @@
 import android.os.WorkSource;
 import android.os.WorkSource.WorkChain;
 import android.provider.Settings;
+import android.provider.Settings.Global;
 import android.provider.Settings.SettingNotFoundException;
 import android.service.dreams.DreamManagerInternal;
 import android.service.vr.IVrManager;
@@ -97,6 +98,7 @@
 import com.android.server.lights.LightsManager;
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.power.batterysaver.BatterySaverController;
+import com.android.server.power.batterysaver.BatterySaverStateMachine;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -225,6 +227,7 @@
     private final AmbientDisplayConfiguration mAmbientDisplayConfiguration;
     private final BatterySaverPolicy mBatterySaverPolicy;
     private final BatterySaverController mBatterySaverController;
+    private final BatterySaverStateMachine mBatterySaverStateMachine;
 
     private LightsManager mLightsManager;
     private BatteryManagerInternal mBatteryManagerInternal;
@@ -492,18 +495,6 @@
     // Time when we last logged a warning about calling userActivity() without permission.
     private long mLastWarningAboutUserActivityPermission = Long.MIN_VALUE;
 
-    // If true, the device is in low power mode.
-    private boolean mLowPowerModeEnabled;
-
-    // Current state of the low power mode setting.
-    private boolean mLowPowerModeSetting;
-
-    // Current state of whether the settings are allowing auto low power mode.
-    private boolean mAutoLowPowerModeConfigured;
-
-    // The user turned off low power mode below the trigger level
-    private boolean mAutoLowPowerModeSnoozing;
-
     // True if the battery level is currently considered low.
     private boolean mBatteryLevelLow;
 
@@ -667,6 +658,7 @@
         mBatterySaverPolicy = new BatterySaverPolicy(mHandler);
         mBatterySaverController = new BatterySaverController(mContext,
                 BackgroundThread.get().getLooper(), mBatterySaverPolicy);
+        mBatterySaverStateMachine = new BatterySaverStateMachine(mContext, mBatterySaverController);
 
         synchronized (mLock) {
             mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks");
@@ -704,6 +696,7 @@
         mBatterySaverPolicy = batterySaverPolicy;
         mBatterySaverController = new BatterySaverController(context,
                 BackgroundThread.getHandler().getLooper(), batterySaverPolicy);
+        mBatterySaverStateMachine = new BatterySaverStateMachine(mContext, mBatterySaverController);
     }
 
     @Override
@@ -725,6 +718,8 @@
                 final long now = SystemClock.uptimeMillis();
                 mBootCompleted = true;
                 mDirty |= DIRTY_BOOT_COMPLETED;
+
+                mBatterySaverStateMachine.onBootCompleted();
                 userActivityNoUpdateLocked(
                         now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
                 updatePowerStateLocked();
@@ -820,12 +815,6 @@
                 Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ),
                 false, mSettingsObserver, UserHandle.USER_ALL);
         resolver.registerContentObserver(Settings.Global.getUriFor(
-                Settings.Global.LOW_POWER_MODE),
-                false, mSettingsObserver, UserHandle.USER_ALL);
-        resolver.registerContentObserver(Settings.Global.getUriFor(
-                Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
-                false, mSettingsObserver, UserHandle.USER_ALL);
-        resolver.registerContentObserver(Settings.Global.getUriFor(
                 Settings.Global.THEATER_MODE_ON),
                 false, mSettingsObserver, UserHandle.USER_ALL);
         resolver.registerContentObserver(Settings.Secure.getUriFor(
@@ -953,17 +942,6 @@
                 Settings.System.SCREEN_BRIGHTNESS_MODE,
                 Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, UserHandle.USER_CURRENT);
 
-        final boolean lowPowerModeEnabled = Settings.Global.getInt(resolver,
-                Settings.Global.LOW_POWER_MODE, 0) != 0;
-        final boolean autoLowPowerModeConfigured = Settings.Global.getInt(resolver,
-                Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0) != 0;
-        if (lowPowerModeEnabled != mLowPowerModeSetting
-                || autoLowPowerModeConfigured != mAutoLowPowerModeConfigured) {
-            mLowPowerModeSetting = lowPowerModeEnabled;
-            mAutoLowPowerModeConfigured = autoLowPowerModeConfigured;
-            updateLowPowerModeLocked();
-        }
-
         mDirty |= DIRTY_SETTINGS;
     }
 
@@ -977,29 +955,6 @@
         }
     }
 
-    private void updateLowPowerModeLocked() {
-        if ((mIsPowered || !mBatteryLevelLow && !mBootCompleted) && mLowPowerModeSetting) {
-            if (DEBUG_SPEW) {
-                Slog.d(TAG, "updateLowPowerModeLocked: powered or booting with sufficient battery,"
-                        + " turning setting off");
-            }
-            // Turn setting off if powered
-            Settings.Global.putInt(mContext.getContentResolver(),
-                    Settings.Global.LOW_POWER_MODE, 0);
-            mLowPowerModeSetting = false;
-        }
-        final boolean autoLowPowerModeEnabled = !mIsPowered && mAutoLowPowerModeConfigured
-                && !mAutoLowPowerModeSnoozing && mBatteryLevelLow;
-        final boolean lowPowerModeEnabled = mLowPowerModeSetting || autoLowPowerModeEnabled;
-
-        if (mLowPowerModeEnabled != lowPowerModeEnabled) {
-            mLowPowerModeEnabled = lowPowerModeEnabled;
-
-            postAfterBootCompleted(() ->
-                    mBatterySaverController.enableBatterySaver(mLowPowerModeEnabled));
-        }
-    }
-
     private void handleSettingsChangedLocked() {
         updateSettingsLocked();
         updatePowerStateLocked();
@@ -1751,15 +1706,7 @@
                 }
             }
 
-            if (wasPowered != mIsPowered || oldLevelLow != mBatteryLevelLow) {
-                if (oldLevelLow != mBatteryLevelLow && !mBatteryLevelLow) {
-                    if (DEBUG_SPEW) {
-                        Slog.d(TAG, "updateIsPoweredLocked: resetting low power snooze");
-                    }
-                    mAutoLowPowerModeSnoozing = false;
-                }
-                updateLowPowerModeLocked();
-            }
+            mBatterySaverStateMachine.setBatteryStatus(mIsPowered, mBatteryLevel, mBatteryLevelLow);
         }
     }
 
@@ -2733,36 +2680,20 @@
     }
 
     private boolean isLowPowerModeInternal() {
-        synchronized (mLock) {
-            return mLowPowerModeEnabled;
-        }
+        return mBatterySaverController.isEnabled();
     }
 
-    private boolean setLowPowerModeInternal(boolean mode) {
+    private boolean setLowPowerModeInternal(boolean enabled) {
         synchronized (mLock) {
-            if (DEBUG) Slog.d(TAG, "setLowPowerModeInternal " + mode + " mIsPowered=" + mIsPowered);
+            if (DEBUG) {
+                Slog.d(TAG, "setLowPowerModeInternal " + enabled + " mIsPowered=" + mIsPowered);
+            }
             if (mIsPowered) {
                 return false;
             }
-            Settings.Global.putInt(mContext.getContentResolver(),
-                    Settings.Global.LOW_POWER_MODE, mode ? 1 : 0);
-            mLowPowerModeSetting = mode;
 
-            if (mAutoLowPowerModeConfigured && mBatteryLevelLow) {
-                if (mode && mAutoLowPowerModeSnoozing) {
-                    if (DEBUG_SPEW) {
-                        Slog.d(TAG, "setLowPowerModeInternal: clearing low power mode snooze");
-                    }
-                    mAutoLowPowerModeSnoozing = false;
-                } else if (!mode && !mAutoLowPowerModeSnoozing) {
-                    if (DEBUG_SPEW) {
-                        Slog.d(TAG, "setLowPowerModeInternal: snoozing low power mode");
-                    }
-                    mAutoLowPowerModeSnoozing = true;
-                }
-            }
+            mBatterySaverStateMachine.setBatterySaverEnabledManually(enabled);
 
-            updateLowPowerModeLocked();
             return true;
         }
     }
@@ -2848,7 +2779,8 @@
     @VisibleForTesting
     void updatePowerRequestFromBatterySaverPolicy(DisplayPowerRequest displayPowerRequest) {
         PowerSaveState state = mBatterySaverPolicy.
-                getBatterySaverPolicy(ServiceType.SCREEN_BRIGHTNESS, mLowPowerModeEnabled);
+                getBatterySaverPolicy(ServiceType.SCREEN_BRIGHTNESS,
+                        mBatterySaverController.isEnabled());
         displayPowerRequest.lowPowerMode = state.batterySaverEnabled;
         displayPowerRequest.screenLowPowerBrightnessFactor = state.brightnessFactor;
     }
@@ -3325,7 +3257,6 @@
             pw.println("  mRequestWaitForNegativeProximity=" + mRequestWaitForNegativeProximity);
             pw.println("  mSandmanScheduled=" + mSandmanScheduled);
             pw.println("  mSandmanSummoned=" + mSandmanSummoned);
-            pw.println("  mLowPowerModeEnabled=" + mLowPowerModeEnabled);
             pw.println("  mBatteryLevelLow=" + mBatteryLevelLow);
             pw.println("  mLightDeviceIdleMode=" + mLightDeviceIdleMode);
             pw.println("  mDeviceIdleMode=" + mDeviceIdleMode);
@@ -3378,9 +3309,6 @@
             pw.println("  mDreamsActivateOnSleepSetting=" + mDreamsActivateOnSleepSetting);
             pw.println("  mDreamsActivateOnDockSetting=" + mDreamsActivateOnDockSetting);
             pw.println("  mDozeAfterScreenOff=" + mDozeAfterScreenOff);
-            pw.println("  mLowPowerModeSetting=" + mLowPowerModeSetting);
-            pw.println("  mAutoLowPowerModeConfigured=" + mAutoLowPowerModeConfigured);
-            pw.println("  mAutoLowPowerModeSnoozing=" + mAutoLowPowerModeSnoozing);
             pw.println("  mMinimumScreenOffTimeoutConfig=" + mMinimumScreenOffTimeoutConfig);
             pw.println("  mMaximumScreenDimDurationConfig=" + mMaximumScreenDimDurationConfig);
             pw.println("  mMaximumScreenDimRatioConfig=" + mMaximumScreenDimRatioConfig);
@@ -3456,6 +3384,7 @@
             pw.println("Display Power: " + mDisplayPowerCallbacks);
 
             mBatterySaverPolicy.dump(pw);
+            mBatterySaverStateMachine.dump(pw);
 
             pw.println();
             final int numProfiles = mProfilePowerState.size();
@@ -3557,7 +3486,6 @@
                     mRequestWaitForNegativeProximity);
             proto.write(PowerManagerServiceDumpProto.IS_SANDMAN_SCHEDULED, mSandmanScheduled);
             proto.write(PowerManagerServiceDumpProto.IS_SANDMAN_SUMMONED, mSandmanSummoned);
-            proto.write(PowerManagerServiceDumpProto.IS_LOW_POWER_MODE_ENABLED, mLowPowerModeEnabled);
             proto.write(PowerManagerServiceDumpProto.IS_BATTERY_LEVEL_LOW, mBatteryLevelLow);
             proto.write(PowerManagerServiceDumpProto.IS_LIGHT_DEVICE_IDLE_MODE, mLightDeviceIdleMode);
             proto.write(PowerManagerServiceDumpProto.IS_DEVICE_IDLE_MODE, mDeviceIdleMode);
@@ -3663,15 +3591,6 @@
                     PowerServiceSettingsAndConfigurationDumpProto.IS_DOZE_AFTER_SCREEN_OFF_CONFIG,
                     mDozeAfterScreenOff);
             proto.write(
-                    PowerServiceSettingsAndConfigurationDumpProto.IS_LOW_POWER_MODE_SETTING,
-                    mLowPowerModeSetting);
-            proto.write(
-                    PowerServiceSettingsAndConfigurationDumpProto.IS_AUTO_LOW_POWER_MODE_CONFIGURED,
-                    mAutoLowPowerModeConfigured);
-            proto.write(
-                    PowerServiceSettingsAndConfigurationDumpProto.IS_AUTO_LOW_POWER_MODE_SNOOZING,
-                    mAutoLowPowerModeSnoozing);
-            proto.write(
                     PowerServiceSettingsAndConfigurationDumpProto
                             .MINIMUM_SCREEN_OFF_TIMEOUT_CONFIG_MS,
                     mMinimumScreenOffTimeoutConfig);
@@ -3792,6 +3711,9 @@
                 proto.end(uIDToken);
             }
 
+            mBatterySaverStateMachine.dumpProto(proto,
+                    PowerManagerServiceDumpProto.BATTERY_SAVER_STATE_MACHINE);
+
             mHandler.getLooper().writeToProto(proto, PowerManagerServiceDumpProto.LOOPER);
 
             for (WakeLock wl : mWakeLocks) {
@@ -4432,12 +4354,12 @@
         }
 
         @Override // Binder call
-        public boolean setPowerSaveMode(boolean mode) {
+        public boolean setPowerSaveMode(boolean enabled) {
             mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.DEVICE_POWER, null);
             final long ident = Binder.clearCallingIdentity();
             try {
-                return setLowPowerModeInternal(mode);
+                return setLowPowerModeInternal(enabled);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -4752,7 +4674,8 @@
         @Override
         public PowerSaveState getLowPowerState(@ServiceType int serviceType) {
             synchronized (mLock) {
-                return mBatterySaverPolicy.getBatterySaverPolicy(serviceType, mLowPowerModeEnabled);
+                return mBatterySaverPolicy.getBatterySaverPolicy(serviceType,
+                        mBatterySaverController.isEnabled());
             }
         }
 
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
new file mode 100644
index 0000000..5b3182e
--- /dev/null
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.power.batterysaver;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.provider.Settings.Global;
+import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.power.BatterySaverPolicy;
+import com.android.server.power.BatterySaverStateMachineProto;
+
+import java.io.PrintWriter;
+
+/**
+ * Decides when to enable / disable battery saver.
+ *
+ * (n.b. This isn't really implemented as a "state machine" though.)
+ *
+ * Test:
+  atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
+ */
+public class BatterySaverStateMachine {
+    private static final String TAG = "BatterySaverStateMachine";
+    private final Object mLock = new Object();
+
+    private static final boolean DEBUG = BatterySaverPolicy.DEBUG;
+
+    private final Context mContext;
+    private final BatterySaverController mBatterySaverController;
+
+    /** Whether the system has booted. */
+    @GuardedBy("mLock")
+    private boolean mBootCompleted;
+
+    /** Whether global settings have been loaded already. */
+    @GuardedBy("mLock")
+    private boolean mSettingsLoaded;
+
+    /** Whether the first battery status has arrived. */
+    @GuardedBy("mLock")
+    private boolean mBatteryStatusSet;
+
+    /** Whether the device is connected to any power source. */
+    @GuardedBy("mLock")
+    private boolean mIsPowered;
+
+    /** Current battery level in %, 0-100. (Currently only used in dumpsys.) */
+    @GuardedBy("mLock")
+    private int mBatteryLevel;
+
+    /** Whether the battery level is considered to be "low" or not.*/
+    @GuardedBy("mLock")
+    private boolean mIsBatteryLevelLow;
+
+    /** Previously known value of Global.LOW_POWER_MODE. */
+    @GuardedBy("mLock")
+    private boolean mSettingBatterySaverEnabled;
+
+    /** Previously known value of Global.LOW_POWER_MODE_STICKY. */
+    @GuardedBy("mLock")
+    private boolean mSettingBatterySaverEnabledSticky;
+
+    /**
+     * Previously known value of Global.LOW_POWER_MODE_TRIGGER_LEVEL.
+     * (Currently only used in dumpsys.)
+     */
+    @GuardedBy("mLock")
+    private int mSettingBatterySaverTriggerThreshold;
+
+    /**
+     * Whether BS has been manually disabled while the battery level is low, in which case we
+     * shouldn't auto re-enable it until the battery level is not low.
+     */
+    @GuardedBy("mLock")
+    private boolean mBatterySaverSnoozing;
+
+    private final ContentObserver mSettingsObserver = new ContentObserver(null) {
+        @Override
+        public void onChange(boolean selfChange) {
+            synchronized (mLock) {
+                refreshSettingsLocked();
+            }
+        }
+    };
+
+    public BatterySaverStateMachine(
+            Context context, BatterySaverController batterySaverController) {
+        mContext = context;
+        mBatterySaverController = batterySaverController;
+    }
+
+    private boolean isBatterySaverEnabled() {
+        return mBatterySaverController.isEnabled();
+    }
+
+    private boolean isAutoBatterySaverConfigured() {
+        return mSettingBatterySaverTriggerThreshold > 0;
+    }
+
+    /**
+     * {@link com.android.server.power.PowerManagerService} calls it when the system is booted.
+     */
+    public void onBootCompleted() {
+        if (DEBUG) {
+            Slog.d(TAG, "onBootCompleted");
+        }
+        synchronized (mLock) {
+
+            final ContentResolver cr = mContext.getContentResolver();
+            cr.registerContentObserver(Settings.Global.getUriFor(
+                    Settings.Global.LOW_POWER_MODE),
+                    false, mSettingsObserver, UserHandle.USER_SYSTEM);
+            cr.registerContentObserver(Settings.Global.getUriFor(
+                    Settings.Global.LOW_POWER_MODE_STICKY),
+                    false, mSettingsObserver, UserHandle.USER_SYSTEM);
+            cr.registerContentObserver(Settings.Global.getUriFor(
+                    Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
+                    false, mSettingsObserver, UserHandle.USER_SYSTEM);
+
+            mBootCompleted = true;
+
+            refreshSettingsLocked();
+
+            doAutoBatterySaverLocked();
+        }
+    }
+
+    void refreshSettingsLocked() {
+        final ContentResolver cr = mContext.getContentResolver();
+
+        final boolean lowPowerModeEnabled = getGlobalSetting(
+                Settings.Global.LOW_POWER_MODE, 0) != 0;
+        final boolean lowPowerModeEnabledSticky = getGlobalSetting(
+                Settings.Global.LOW_POWER_MODE_STICKY, 0) != 0;
+        final int lowPowerModeTriggerLevel = getGlobalSetting(
+                Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
+
+        setSettingsLocked(lowPowerModeEnabled, lowPowerModeEnabledSticky,
+                lowPowerModeTriggerLevel);
+    }
+
+    /**
+     * {@link com.android.server.power.PowerManagerService} calls it when relevant global settings
+     * have changed.
+     *
+     * Note this will be called before {@link #onBootCompleted} too.
+     */
+    @VisibleForTesting
+    void setSettingsLocked(boolean batterySaverEnabled, boolean batterySaverEnabledSticky,
+            int batterySaverTriggerThreshold) {
+        if (DEBUG) {
+            Slog.d(TAG, "setSettings: enabled=" + batterySaverEnabled
+                    + " sticky=" + batterySaverEnabledSticky
+                    + " threshold=" + batterySaverTriggerThreshold);
+        }
+
+        mSettingsLoaded = true;
+
+        final boolean enabledChanged = mSettingBatterySaverEnabled != batterySaverEnabled;
+        final boolean stickyChanged =
+                mSettingBatterySaverEnabledSticky != batterySaverEnabledSticky;
+        final boolean thresholdChanged
+                = mSettingBatterySaverTriggerThreshold != batterySaverTriggerThreshold;
+
+        if (!(enabledChanged || stickyChanged || thresholdChanged)) {
+            return;
+        }
+
+        mSettingBatterySaverEnabled = batterySaverEnabled;
+        mSettingBatterySaverEnabledSticky = batterySaverEnabledSticky;
+        mSettingBatterySaverTriggerThreshold = batterySaverTriggerThreshold;
+
+        if (enabledChanged) {
+            final String reason = batterySaverEnabled
+                    ? "Global.low_power changed to 1" : "Global.low_power changed to 0";
+            enableBatterySaverLocked(/*enable=*/ batterySaverEnabled, /*manual=*/ true,
+                    reason);
+        }
+    }
+
+    /**
+     * {@link com.android.server.power.PowerManagerService} calls it when battery state changes.
+     *
+     * Note this may be called before {@link #onBootCompleted} too.
+     */
+    public void setBatteryStatus(boolean newPowered, int newLevel, boolean newBatteryLevelLow) {
+        if (DEBUG) {
+            Slog.d(TAG, "setBatteryStatus: powered=" + newPowered + " level=" + newLevel
+                    + " low=" + newBatteryLevelLow);
+        }
+        synchronized (mLock) {
+            mBatteryStatusSet = true;
+
+            final boolean poweredChanged = mIsPowered != newPowered;
+            final boolean levelChanged = mBatteryLevel != newLevel;
+            final boolean lowChanged = mIsBatteryLevelLow != newBatteryLevelLow;
+
+            if (!(poweredChanged || levelChanged || lowChanged)) {
+                return;
+            }
+
+            mIsPowered = newPowered;
+            mBatteryLevel = newLevel;
+            mIsBatteryLevelLow = newBatteryLevelLow;
+
+            doAutoBatterySaverLocked();
+        }
+    }
+
+    /**
+     * Decide whether to auto-start / stop battery saver.
+     */
+    private void doAutoBatterySaverLocked() {
+        if (DEBUG) {
+            Slog.d(TAG, "doAutoBatterySaverLocked: mBootCompleted=" + mBootCompleted
+                    + " mSettingsLoaded=" + mSettingsLoaded
+                    + " mBatteryStatusSet=" + mBatteryStatusSet
+                    + " mIsBatteryLevelLow=" + mIsBatteryLevelLow
+                    + " mBatterySaverSnoozing=" + mBatterySaverSnoozing
+                    + " mIsPowered=" + mIsPowered
+                    + " mSettingBatterySaverEnabledSticky=" + mSettingBatterySaverEnabledSticky);
+        }
+        if (!(mBootCompleted && mSettingsLoaded && mBatteryStatusSet)) {
+            return; // Not fully initialized yet.
+        }
+        if (!mIsBatteryLevelLow) {
+            updateSnoozingLocked(false, "Battery not low");
+        }
+        if (mIsPowered) {
+            updateSnoozingLocked(false, "Plugged in");
+            enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false, "Plugged in");
+
+        } else if (mSettingBatterySaverEnabledSticky) {
+            // Re-enable BS.
+            enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ true, "Sticky restore");
+
+        } else if (mIsBatteryLevelLow) {
+            if (!mBatterySaverSnoozing && isAutoBatterySaverConfigured()) {
+                enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ false, "Auto ON");
+            }
+        } else { // Battery not low
+            enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false, "Auto OFF");
+        }
+    }
+
+    /**
+     * {@link com.android.server.power.PowerManagerService} calls it when
+     * {@link android.os.PowerManager#setPowerSaveMode} is called.
+     *
+     * Note this could? be called before {@link #onBootCompleted} too.
+     */
+    public void setBatterySaverEnabledManually(boolean enabled) {
+        if (DEBUG) {
+            Slog.d(TAG, "setBatterySaverEnabledManually: enabled=" + enabled);
+        }
+        synchronized (mLock) {
+            enableBatterySaverLocked(/*enable=*/ enabled, /*manual=*/ true,
+                    (enabled ? "Manual ON" : "Manual OFF"));
+        }
+    }
+
+    /**
+     * Actually enable / disable battery saver. Write the new state to the global settings
+     * and propagate it to {@link #mBatterySaverController}.
+     */
+    private void enableBatterySaverLocked(boolean enable, boolean manual, String reason) {
+        if (DEBUG) {
+            Slog.d(TAG, "enableBatterySaver: enable=" + enable + " manual=" + manual
+                    + " reason=" + reason);
+        }
+        final boolean wasEnabled = mBatterySaverController.isEnabled();
+
+        if (wasEnabled == enable) {
+            if (DEBUG) {
+                Slog.d(TAG, "Already " + (enable ? "enabled" : "disabled"));
+            }
+            return;
+        }
+        if (enable && mIsPowered) {
+            if (DEBUG) Slog.d(TAG, "Can't enable: isPowered");
+            return;
+        }
+
+        if (manual) {
+            if (enable) {
+                updateSnoozingLocked(false, "Manual snooze OFF");
+            } else {
+                // When battery saver is disabled manually (while battery saver is enabled)
+                // when the battery level is low, we "snooze" BS -- i.e. disable auto battery saver.
+                // We resume auto-BS once the battery level is not low, or the device is plugged in.
+                if (isBatterySaverEnabled() && mIsBatteryLevelLow) {
+                    updateSnoozingLocked(true, "Manual snooze");
+                }
+            }
+        }
+
+        mSettingBatterySaverEnabled = enable;
+        putGlobalSetting(Global.LOW_POWER_MODE, enable ? 1 : 0);
+
+        if (manual) {
+            mSettingBatterySaverEnabledSticky = enable;
+            putGlobalSetting(Global.LOW_POWER_MODE_STICKY, enable ? 1 : 0);
+        }
+        mBatterySaverController.enableBatterySaver(enable);
+
+        if (DEBUG) {
+            Slog.d(TAG, "Battery saver: Enabled=" + enable
+                    + " manual=" + manual
+                    + " reason=" + reason);
+        }
+    }
+
+    private void updateSnoozingLocked(boolean snoozing, String reason) {
+        if (mBatterySaverSnoozing == snoozing) {
+            return;
+        }
+        if (DEBUG) Slog.d(TAG, "Snooze: " + (snoozing ? "start" : "stop")  + " reason=" + reason);
+        mBatterySaverSnoozing = snoozing;
+    }
+
+    @VisibleForTesting
+    protected void putGlobalSetting(String key, int value) {
+        Global.putInt(mContext.getContentResolver(), key, value);
+    }
+
+    @VisibleForTesting
+    protected int getGlobalSetting(String key, int defValue) {
+        return Global.getInt(mContext.getContentResolver(), key, defValue);
+    }
+
+    public void dump(PrintWriter pw) {
+        synchronized (mLock) {
+            pw.println();
+            pw.println("Battery saver state machine:");
+
+            pw.print("  Enabled=");
+            pw.println(mBatterySaverController.isEnabled());
+
+            pw.print("  mBootCompleted=");
+            pw.println(mBootCompleted);
+            pw.print("  mSettingsLoaded=");
+            pw.println(mSettingsLoaded);
+            pw.print("  mBatteryStatusSet=");
+            pw.println(mBatteryStatusSet);
+
+            pw.print("  mBatterySaverSnoozing=");
+            pw.println(mBatterySaverSnoozing);
+
+            pw.print("  mIsPowered=");
+            pw.println(mIsPowered);
+            pw.print("  mBatteryLevel=");
+            pw.println(mBatteryLevel);
+            pw.print("  mIsBatteryLevelLow=");
+            pw.println(mIsBatteryLevelLow);
+
+            pw.print("  mSettingBatterySaverEnabled=");
+            pw.println(mSettingBatterySaverEnabled);
+            pw.print("  mSettingBatterySaverEnabledSticky=");
+            pw.println(mSettingBatterySaverEnabledSticky);
+            pw.print("  mSettingBatterySaverTriggerThreshold=");
+            pw.println(mSettingBatterySaverTriggerThreshold);
+        }
+    }
+
+    public void dumpProto(ProtoOutputStream proto, long tag) {
+        synchronized (mLock) {
+            final long token = proto.start(tag);
+
+            proto.write(BatterySaverStateMachineProto.ENABLED,
+                    mBatterySaverController.isEnabled());
+
+            proto.write(BatterySaverStateMachineProto.BOOT_COMPLETED, mBootCompleted);
+            proto.write(BatterySaverStateMachineProto.SETTINGS_LOADED, mSettingsLoaded);
+            proto.write(BatterySaverStateMachineProto.BATTERY_STATUS_SET, mBatteryStatusSet);
+
+            proto.write(BatterySaverStateMachineProto.BATTERY_SAVER_SNOOZING,
+                    mBatterySaverSnoozing);
+
+            proto.write(BatterySaverStateMachineProto.IS_POWERED, mIsPowered);
+            proto.write(BatterySaverStateMachineProto.BATTERY_LEVEL, mBatteryLevel);
+            proto.write(BatterySaverStateMachineProto.IS_BATTERY_LEVEL_LOW, mIsBatteryLevelLow);
+
+            proto.write(BatterySaverStateMachineProto.SETTING_BATTERY_SAVER_ENABLED,
+                    mSettingBatterySaverEnabled);
+            proto.write(BatterySaverStateMachineProto.SETTING_BATTERY_SAVER_ENABLED_STICKY,
+                    mSettingBatterySaverEnabledSticky);
+            proto.write(BatterySaverStateMachineProto.SETTING_BATTERY_SAVER_TRIGGER_THRESHOLD,
+                    mSettingBatterySaverTriggerThreshold);
+
+            proto.end(token);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 74c5ee9..b3d28fc 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -972,10 +972,13 @@
     public void triggerUidSnapshot() {
         enforceCallingPermission();
         synchronized (sStatsdLock) {
+            final long token = Binder.clearCallingIdentity();
             try {
                 informAllUidsLocked(mContext);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Failed to trigger uid snapshot.", e);
+            } finally {
+                restoreCallingIdentity(token);
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 3e47ea6..a7eac55 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -385,6 +385,11 @@
      */
     private int mSurfaceSize;
 
+    /**
+     * Sequence number for the current layout pass.
+     */
+    int mLayoutSeq = 0;
+
     /** Temporary float array to retrieve 3x3 matrix values. */
     private final float[] mTmpFloats = new float[9];
 
@@ -554,7 +559,7 @@
                 w.prelayout();
                 final boolean firstLayout = !w.isLaidOut();
                 mService.mPolicy.layoutWindowLw(w, null, mDisplayFrames);
-                w.mLayoutSeq = mService.mLayoutSeq;
+                w.mLayoutSeq = mLayoutSeq;
 
                 // If this is the first layout, we need to initialize the last inset values as
                 // otherwise we'd immediately cause an unnecessary resize.
@@ -593,7 +598,7 @@
                 w.mLayoutNeeded = false;
                 w.prelayout();
                 mService.mPolicy.layoutWindowLw(w, w.getParentWindow(), mDisplayFrames);
-                w.mLayoutSeq = mService.mLayoutSeq;
+                w.mLayoutSeq = mLayoutSeq;
                 if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.mFrame
                         + " mContainingFrame=" + w.mContainingFrame
                         + " mDisplayFrame=" + w.mDisplayFrame);
@@ -2219,6 +2224,9 @@
             pw.println(" mTouchExcludeRegion=" + mTouchExcludeRegion);
 
         pw.println();
+        pw.print(prefix); pw.print("mLayoutSeq="); pw.println(mLayoutSeq);
+
+        pw.println();
         pw.println(prefix + "Application tokens in top down Z order:");
         for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
             final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx);
@@ -2927,9 +2935,9 @@
             mService.mScreenRect.set(0, 0, dw, dh);
         }
 
-        int seq = mService.mLayoutSeq + 1;
+        int seq = mLayoutSeq + 1;
         if (seq < 0) seq = 0;
-        mService.mLayoutSeq = seq;
+        mLayoutSeq = seq;
 
         // Used to indicate that we have processed the dream window and all additional windows are
         // behind it.
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 19d6691..87a7a74 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -51,6 +51,7 @@
 import com.google.android.collect.Sets;
 
 import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
+import com.android.server.wm.utils.InsetUtils;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -400,9 +401,11 @@
             if (mainWindow == null) {
                 return null;
             }
+            final Rect insets = new Rect(mainWindow.mContentInsets);
+            InsetUtils.addInsets(insets, mainWindow.mAppToken.getLetterboxInsets());
             mTarget = new RemoteAnimationTarget(mTask.mTaskId, MODE_CLOSING, mCapturedLeash,
                     !mTask.fillsParent(), mainWindow.mWinAnimator.mLastClipRect,
-                    mainWindow.mContentInsets, mTask.getPrefixOrderIndex(), position, bounds,
+                    insets, mTask.getPrefixOrderIndex(), position, bounds,
                     mTask.getWindowConfiguration(), mIsRecentTaskInvisible);
             return mTarget;
         }
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index c590067..3e7feda 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -16,14 +16,15 @@
 
 package com.android.server.wm;
 
+import static com.android.server.wm.AnimationAdapterProto.REMOTE;
+import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.AnimationAdapterProto.REMOTE;
-import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
 
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.os.Binder;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -37,6 +38,7 @@
 
 import com.android.internal.util.FastPrintWriter;
 import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
+import com.android.server.wm.utils.InsetUtils;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -194,12 +196,17 @@
 
         @Override
         public void onAnimationFinished() throws RemoteException {
-            if (mOuter != null) {
-                mOuter.onAnimationFinished();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                if (mOuter != null) {
+                    mOuter.onAnimationFinished();
 
-                // In case the client holds on to the finish callback, make sure we don't leak
-                // RemoteAnimationController which in turn would leak the runner on the client.
-                mOuter = null;
+                    // In case the client holds on to the finish callback, make sure we don't leak
+                    // RemoteAnimationController which in turn would leak the runner on the client.
+                    mOuter = null;
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
         }
 
@@ -235,9 +242,11 @@
                     || mCapturedLeash == null) {
                 return null;
             }
+            final Rect insets = new Rect(mainWindow.mContentInsets);
+            InsetUtils.addInsets(insets, mAppWindowToken.getLetterboxInsets());
             mTarget = new RemoteAnimationTarget(task.mTaskId, getMode(),
                     mCapturedLeash, !mAppWindowToken.fillsParent(),
-                    mainWindow.mWinAnimator.mLastClipRect, mainWindow.mContentInsets,
+                    mainWindow.mWinAnimator.mLastClipRect, insets,
                     mAppWindowToken.getPrefixOrderIndex(), mPosition, mStackBounds,
                     task.getWindowConfiguration(), false /*isNotInRecents*/);
             return mTarget;
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 970a8d7..5f9d679 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -27,7 +27,6 @@
 import android.app.ActivityManager.TaskSnapshot;
 import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
-import android.graphics.Color;
 import android.graphics.GraphicBuffer;
 import android.graphics.Rect;
 import android.os.Environment;
@@ -45,6 +44,7 @@
 import com.android.server.policy.WindowManagerPolicy.ScreenOffListener;
 import com.android.server.policy.WindowManagerPolicy.StartingSurface;
 import com.android.server.wm.TaskSnapshotSurface.SystemBarBackgroundPainter;
+import com.android.server.wm.utils.InsetUtils;
 
 import com.google.android.collect.Sets;
 
@@ -273,7 +273,7 @@
             return null;
         }
         return new TaskSnapshot(buffer, top.getConfiguration().orientation,
-                getInsetsFromTaskBounds(mainWindow, task),
+                getInsets(mainWindow),
                 isLowRamDevice /* reduced */, scaleFraction /* scale */,
                 true /* isRealSnapshot */);
     }
@@ -282,11 +282,11 @@
         return mIsRunningOnWear || mIsRunningOnTv || mIsRunningOnIoT;
     }
 
-    private Rect getInsetsFromTaskBounds(WindowState state, Task task) {
+    private Rect getInsets(WindowState state) {
         // XXX(b/72757033): These are insets relative to the window frame, but we're really
         // interested in the insets relative to the task bounds.
-        Rect insets = minRect(state.mContentInsets, state.mStableInsets);
-        insets = maxRect(insets, state.mAppToken.getLetterboxInsets());
+        final Rect insets = minRect(state.mContentInsets, state.mStableInsets);
+        InsetUtils.addInsets(insets, state.mAppToken.getLetterboxInsets());
         return insets;
     }
 
@@ -297,13 +297,6 @@
                 Math.min(rect1.bottom, rect2.bottom));
     }
 
-    private Rect maxRect(Rect rect1, Rect rect2) {
-        return new Rect(Math.max(rect1.left, rect2.left),
-                Math.max(rect1.top, rect2.top),
-                Math.max(rect1.right, rect2.right),
-                Math.max(rect1.bottom, rect2.bottom));
-    }
-
     /**
      * Retrieves all closing tasks based on the list of closing apps during an app transition.
      */
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 56b314f..449aa2c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -596,8 +596,6 @@
     boolean mClientFreezingScreen = false;
     int mAppsFreezingScreen = 0;
 
-    int mLayoutSeq = 0;
-
     // Last systemUiVisibility we received from status bar.
     int mLastStatusBarVisibility = 0;
     // Last systemUiVisibility we dispatched to windows.
@@ -6344,8 +6342,7 @@
         if (mInputMethodTarget != null) {
             pw.print("  mInputMethodTarget="); pw.println(mInputMethodTarget);
         }
-        pw.print("  mInTouchMode="); pw.print(mInTouchMode);
-                pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
+        pw.print("  mInTouchMode="); pw.println(mInTouchMode);
         pw.print("  mLastDisplayFreezeDuration=");
                 TimeUtils.formatDuration(mLastDisplayFreezeDuration, pw);
                 if ( mLastFinishedFreezeSource != null) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 993556f..30bbfe0 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1236,7 +1236,7 @@
      */
     void updateResizingWindowIfNeeded() {
         final WindowStateAnimator winAnimator = mWinAnimator;
-        if (!mHasSurface || mService.mLayoutSeq != mLayoutSeq || isGoneForLayoutLw()) {
+        if (!mHasSurface || getDisplayContent().mLayoutSeq != mLayoutSeq || isGoneForLayoutLw()) {
             return;
         }
 
@@ -1360,6 +1360,15 @@
         return mToken.getDisplayContent();
     }
 
+    @Override
+    void onDisplayChanged(DisplayContent dc) {
+        super.onDisplayChanged(dc);
+        // Window was not laid out for this display yet, so make sure mLayoutSeq does not match.
+        if (dc != null) {
+            mLayoutSeq = dc.mLayoutSeq - 1;
+        }
+    }
+
     DisplayInfo getDisplayInfo() {
         final DisplayContent displayContent = getDisplayContent();
         return displayContent != null ? displayContent.getDisplayInfo() : null;
diff --git a/services/core/java/com/android/server/wm/utils/InsetUtils.java b/services/core/java/com/android/server/wm/utils/InsetUtils.java
new file mode 100644
index 0000000..b4a998a
--- /dev/null
+++ b/services/core/java/com/android/server/wm/utils/InsetUtils.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm.utils;
+
+import android.graphics.Rect;
+
+/**
+ * Utility methods to handle insets represented as rects.
+ */
+public class InsetUtils {
+
+    private InsetUtils() {
+    }
+
+    /**
+     * Adds {@code insetsToAdd} to {@code inOutInsets}.
+     */
+    public static void addInsets(Rect inOutInsets, Rect insetsToAdd) {
+        inOutInsets.left += insetsToAdd.left;
+        inOutInsets.top += insetsToAdd.top;
+        inOutInsets.right += insetsToAdd.right;
+        inOutInsets.bottom += insetsToAdd.bottom;
+    }
+}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 427b9d2..89efe12 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -86,6 +86,7 @@
         "libhardware_legacy",
         "libhidlbase",
         "libkeystore_binder",
+        "libmtp",
         "libnativehelper",
         "libutils",
         "libui",
diff --git a/services/core/jni/com_android_server_UsbDeviceManager.cpp b/services/core/jni/com_android_server_UsbDeviceManager.cpp
index f37f870..ff1ec04 100644
--- a/services/core/jni/com_android_server_UsbDeviceManager.cpp
+++ b/services/core/jni/com_android_server_UsbDeviceManager.cpp
@@ -21,6 +21,7 @@
 #include <nativehelper/JNIHelp.h>
 #include "android_runtime/AndroidRuntime.h"
 #include "android_runtime/Log.h"
+#include "MtpDescriptors.h"
 
 #include <stdio.h>
 #include <asm/byteorder.h>
@@ -118,6 +119,38 @@
     return result;
 }
 
+static jobject android_server_UsbDeviceManager_openControl(JNIEnv *env, jobject /* thiz */, jstring jFunction) {
+    const char *function = env->GetStringUTFChars(jFunction, NULL);
+    bool ptp = false;
+    int fd = -1;
+    if (!strcmp(function, "ptp")) {
+        ptp = true;
+    }
+    if (!strcmp(function, "mtp") || ptp) {
+        fd = TEMP_FAILURE_RETRY(open(ptp ? FFS_PTP_EP0 : FFS_MTP_EP0, O_RDWR));
+        if (fd < 0) {
+            ALOGE("could not open control for %s %s", function, strerror(errno));
+            goto error;
+        }
+        if (!writeDescriptors(fd, ptp)) {
+            goto error;
+        }
+    }
+
+    if (function != NULL) {
+        env->ReleaseStringUTFChars(jFunction, function);
+    }
+    return jniCreateFileDescriptor(env, fd);
+error:
+    if (fd != -1) {
+        close(fd);
+    }
+    if (function != NULL) {
+        env->ReleaseStringUTFChars(jFunction, function);
+    }
+    return NULL;
+}
+
 static const JNINativeMethod method_table[] = {
     { "nativeGetAccessoryStrings",  "()[Ljava/lang/String;",
                                     (void*)android_server_UsbDeviceManager_getAccessoryStrings },
@@ -127,6 +160,8 @@
                                     (void*)android_server_UsbDeviceManager_isStartRequested },
     { "nativeGetAudioMode",         "()I",
                                     (void*)android_server_UsbDeviceManager_getAudioMode },
+    { "nativeOpenControl",          "(Ljava/lang/String;)Ljava/io/FileDescriptor;",
+                                    (void*)android_server_UsbDeviceManager_openControl },
 };
 
 int register_android_server_UsbDeviceManager(JNIEnv *env)
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 2e07703..1e216a3 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -566,9 +566,7 @@
     }
 
     public static class DevicePolicyData {
-        @NonNull PasswordMetrics mActivePasswordMetrics = new PasswordMetrics();
         int mFailedPasswordAttempts = 0;
-        boolean mPasswordStateHasBeenSetSinceBoot = false;
         boolean mPasswordValidAtLastCheckpoint = true;
 
         int mUserHandle;
@@ -628,6 +626,8 @@
     }
 
     final SparseArray<DevicePolicyData> mUserData = new SparseArray<>();
+    @GuardedBy("DevicePolicyManagerService.this")
+    final SparseArray<PasswordMetrics> mUserPasswordMetrics = new SparseArray<>();
 
     final Handler mHandler;
     final Handler mBackgroundHandler;
@@ -2158,6 +2158,16 @@
     }
 
     /**
+     * Provides PasswordMetrics object corresponding to the given user.
+     * @param userHandle the user for whom to provide metrics.
+     * @return the user password metrics, or {@code null} if none have been associated with
+     * the user yet (for example, if the device has booted but not been unlocked).
+     */
+    PasswordMetrics getUserPasswordMetricsLocked(int userHandle) {
+        return mUserPasswordMetrics.get(userHandle);
+    }
+
+    /**
      * Creates and loads the policy data from xml for data that is shared between
      * various profiles of a user. In contrast to {@link #getUserData(int)}
      * it allows access to data of users other than the calling user.
@@ -2191,6 +2201,10 @@
             if (policy != null) {
                 mUserData.remove(userHandle);
             }
+            if (mUserPasswordMetrics.get(userHandle) != null) {
+                mUserPasswordMetrics.remove(userHandle);
+            }
+
             File policyFile = new File(mInjector.environmentGetUserSystemDirectory(userHandle),
                     DEVICE_POLICIES_XML);
             policyFile.delete();
@@ -3907,9 +3921,15 @@
     private void updatePasswordValidityCheckpointLocked(int userHandle, boolean parent) {
         final int credentialOwner = getCredentialOwner(userHandle, parent);
         DevicePolicyData policy = getUserData(credentialOwner);
+        PasswordMetrics metrics = getUserPasswordMetricsLocked(credentialOwner);
+        if (metrics == null) {
+            Slog.wtf(LOG_TAG, "Should have had a valid password metrics for updating checkpoint " +
+                    "validity.");
+            metrics = new PasswordMetrics();
+        }
         policy.mPasswordValidAtLastCheckpoint =
                 isPasswordSufficientForUserWithoutCheckpointLocked(
-                        policy.mActivePasswordMetrics, userHandle, parent);
+                        metrics, userHandle, parent);
 
         saveSettingsLocked(credentialOwner);
     }
@@ -4532,8 +4552,11 @@
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
             getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
-            DevicePolicyData policy = getUserDataUnchecked(getCredentialOwner(userHandle, parent));
-            return isActivePasswordSufficientForUserLocked(policy, userHandle, parent);
+            int credentialOwner = getCredentialOwner(userHandle, parent);
+            DevicePolicyData policy = getUserDataUnchecked(credentialOwner);
+            PasswordMetrics metrics = getUserPasswordMetricsLocked(credentialOwner);
+            return isActivePasswordSufficientForUserLocked(
+                    policy.mPasswordValidAtLastCheckpoint, metrics, userHandle, parent);
         }
     }
 
@@ -4559,25 +4582,31 @@
         synchronized (this) {
             final int targetUser = getProfileParentId(userHandle);
             enforceUserUnlocked(targetUser, false);
-            DevicePolicyData policy = getUserDataUnchecked(getCredentialOwner(userHandle, false));
-            return isActivePasswordSufficientForUserLocked(policy, targetUser, false);
+            int credentialOwner = getCredentialOwner(userHandle, false);
+            DevicePolicyData policy = getUserDataUnchecked(credentialOwner);
+            PasswordMetrics metrics = getUserPasswordMetricsLocked(credentialOwner);
+            return isActivePasswordSufficientForUserLocked(
+                    policy.mPasswordValidAtLastCheckpoint, metrics, targetUser, false);
         }
     }
 
     private boolean isActivePasswordSufficientForUserLocked(
-            DevicePolicyData policy, int userHandle, boolean parent) {
-        if (!mInjector.storageManagerIsFileBasedEncryptionEnabled()
-                && !policy.mPasswordStateHasBeenSetSinceBoot) {
+            boolean passwordValidAtLastCheckpoint, PasswordMetrics metrics, int userHandle,
+            boolean parent) {
+        if (!mInjector.storageManagerIsFileBasedEncryptionEnabled() && (metrics == null)) {
             // Before user enters their password for the first time after a reboot, return the
             // value of this flag, which tells us whether the password was valid the last time
             // settings were saved.  If DPC changes password requirements on boot so that the
             // current password no longer meets the requirements, this value will be stale until
             // the next time the password is entered.
-            return policy.mPasswordValidAtLastCheckpoint;
+            return passwordValidAtLastCheckpoint;
         }
 
-        return isPasswordSufficientForUserWithoutCheckpointLocked(
-                policy.mActivePasswordMetrics, userHandle, parent);
+        if (metrics == null) {
+            Slog.wtf(LOG_TAG, "FBE device, should have been unlocked and had valid metrics.");
+            metrics = new PasswordMetrics();
+        }
+        return isPasswordSufficientForUserWithoutCheckpointLocked(metrics, userHandle, parent);
     }
 
     /**
@@ -6123,10 +6152,8 @@
         }
 
         validateQualityConstant(metrics.quality);
-        DevicePolicyData policy = getUserData(userHandle);
         synchronized (this) {
-            policy.mActivePasswordMetrics = metrics;
-            policy.mPasswordStateHasBeenSetSinceBoot = true;
+            mUserPasswordMetrics.put(userHandle, metrics);
         }
     }
 
@@ -7640,6 +7667,7 @@
         if (!mHasFeature) {
             return DevicePolicyManager.STATE_USER_UNMANAGED;
         }
+        enforceManageUsers();
         int userHandle = mInjector.userHandleGetCallingUserId();
         return getUserProvisioningState(userHandle);
     }
@@ -7833,8 +7861,7 @@
             ApplicationInfo appInfo = userContext.getApplicationInfo();
             CharSequence result = null;
             if (appInfo != null) {
-                PackageManager pm = userContext.getPackageManager();
-                result = pm.getApplicationLabel(appInfo);
+                result = appInfo.loadUnsafeLabel(userContext.getPackageManager());
             }
             return result != null ? result.toString() : null;
         } finally {
@@ -11816,6 +11843,7 @@
 
     @Override
     public boolean isDeviceProvisioned() {
+        enforceManageUsers();
         synchronized (this) {
             return getUserDataUnchecked(UserHandle.USER_SYSTEM).mUserSetupComplete;
         }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index 0268519..8366114 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -723,6 +723,11 @@
                 mSystemUpdatePolicy.saveToXml(out);
                 out.endTag(null, TAG_SYSTEM_UPDATE_POLICY);
             }
+
+            if (mSystemUpdateInfo != null) {
+                mSystemUpdateInfo.writeToXml(out, TAG_PENDING_OTA_INFO);
+            }
+
             if (mSystemUpdateFreezeStart != null || mSystemUpdateFreezeEnd != null) {
                 out.startTag(null, TAG_FREEZE_PERIOD_RECORD);
                 if (mSystemUpdateFreezeStart != null) {
diff --git a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
index 376f5b1..7765387 100644
--- a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
@@ -42,11 +42,13 @@
 import android.app.ActivityManager;
 import android.app.ActivityManager.RecentTaskInfo;
 import android.app.ActivityManager.RunningTaskInfo;
+import android.app.WindowConfiguration;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.UserInfo;
+import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Debug;
@@ -101,8 +103,8 @@
     private TestRecentTasks mRecentTasks;
     private TestRunningTasks mRunningTasks;
 
-    private static ArrayList<TaskRecord> mTasks = new ArrayList<>();
-    private static ArrayList<TaskRecord> mSameDocumentTasks = new ArrayList<>();
+    private ArrayList<TaskRecord> mTasks;
+    private ArrayList<TaskRecord> mSameDocumentTasks;
 
     private CallbacksRecorder mCallbacksRecorder;
 
@@ -155,12 +157,14 @@
         mRecentTasks.registerCallback(mCallbacksRecorder);
         QUIET_USER_INFO.flags = UserInfo.FLAG_MANAGED_PROFILE | UserInfo.FLAG_QUIET_MODE;
 
+        mTasks = new ArrayList<>();
         mTasks.add(createTaskBuilder(".Task1").build());
         mTasks.add(createTaskBuilder(".Task2").build());
         mTasks.add(createTaskBuilder(".Task3").build());
         mTasks.add(createTaskBuilder(".Task4").build());
         mTasks.add(createTaskBuilder(".Task5").build());
 
+        mSameDocumentTasks = new ArrayList<>();
         mSameDocumentTasks.add(createDocumentTask(".DocumentTask1"));
         mSameDocumentTasks.add(createDocumentTask(".DocumentTask1"));
     }
@@ -294,7 +298,32 @@
         assertTrue(mCallbacksRecorder.added.contains(task2));
         assertTrue(mCallbacksRecorder.trimmed.isEmpty());
         assertTrue(mCallbacksRecorder.removed.isEmpty());
+    }
 
+    @Test
+    public void testAddTaskCompatibleActivityType_expectRemove() throws Exception {
+        Configuration config1 = new Configuration();
+        config1.windowConfiguration.setActivityType(ACTIVITY_TYPE_UNDEFINED);
+        TaskRecord task1 = createTaskBuilder(".Task1")
+                .setFlags(FLAG_ACTIVITY_NEW_TASK)
+                .setStack(mStack)
+                .build();
+        task1.onConfigurationChanged(config1);
+        assertTrue(task1.getActivityType() == ACTIVITY_TYPE_UNDEFINED);
+        mRecentTasks.add(task1);
+        mCallbacksRecorder.clear();
+
+        TaskRecord task2 = createTaskBuilder(".Task1")
+                .setFlags(FLAG_ACTIVITY_NEW_TASK)
+                .setStack(mStack)
+                .build();
+        assertTrue(task2.getActivityType() == ACTIVITY_TYPE_STANDARD);
+        mRecentTasks.add(task2);
+        assertTrue(mCallbacksRecorder.added.size() == 1);
+        assertTrue(mCallbacksRecorder.added.contains(task2));
+        assertTrue(mCallbacksRecorder.trimmed.isEmpty());
+        assertTrue(mCallbacksRecorder.removed.size() == 1);
+        assertTrue(mCallbacksRecorder.removed.contains(task1));
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java b/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java
index ea207f1..9e6055d 100644
--- a/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java
@@ -29,6 +29,9 @@
 import java.io.File;
 import java.util.Random;
 
+/**
+ * atest FrameworksServicesTests:TaskPersisterTest
+ */
 public class TaskPersisterTest extends AndroidTestCase {
     private static final String TEST_USER_NAME = "AM-Test-User";
 
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 43490d3..a64efb7 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -2387,12 +2387,12 @@
     }
 
     public void testGetUserProvisioningState_defaultResult() {
+        mContext.callerPermissions.add(permission.MANAGE_USERS);
         assertEquals(DevicePolicyManager.STATE_USER_UNMANAGED, dpm.getUserProvisioningState());
     }
 
     public void testSetUserProvisioningState_permission() throws Exception {
         setupProfileOwner();
-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
 
         exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE,
                 DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
@@ -2407,6 +2407,7 @@
 
     public void testSetUserProvisioningState_noManagement() {
         mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        mContext.callerPermissions.add(permission.MANAGE_USERS);
         assertExpectException(IllegalStateException.class,
                 /* messageRegex= */ "change provisioning state unless a .* owner is set",
                 () -> dpm.setUserProvisioningState(DevicePolicyManager.STATE_USER_SETUP_FINALIZED,
@@ -2417,7 +2418,6 @@
     public void testSetUserProvisioningState_deviceOwnerFromSetupWizard() throws Exception {
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         setupDeviceOwner();
-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
 
         exerciseUserProvisioningTransitions(UserHandle.USER_SYSTEM,
                 DevicePolicyManager.STATE_USER_SETUP_COMPLETE,
@@ -2428,7 +2428,6 @@
             throws Exception {
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         setupDeviceOwner();
-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
 
         exerciseUserProvisioningTransitions(UserHandle.USER_SYSTEM,
                 DevicePolicyManager.STATE_USER_SETUP_INCOMPLETE,
@@ -2438,7 +2437,6 @@
     public void testSetUserProvisioningState_deviceOwnerWithoutSetupWizard() throws Exception {
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         setupDeviceOwner();
-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
 
         exerciseUserProvisioningTransitions(UserHandle.USER_SYSTEM,
                 DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
@@ -2447,7 +2445,6 @@
     public void testSetUserProvisioningState_managedProfileFromSetupWizard_primaryUser()
             throws Exception {
         setupProfileOwner();
-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
 
         exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE,
                 DevicePolicyManager.STATE_USER_PROFILE_COMPLETE,
@@ -2457,7 +2454,6 @@
     public void testSetUserProvisioningState_managedProfileFromSetupWizard_managedProfile()
             throws Exception {
         setupProfileOwner();
-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
 
         exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE,
                 DevicePolicyManager.STATE_USER_SETUP_COMPLETE,
@@ -2466,7 +2462,6 @@
 
     public void testSetUserProvisioningState_managedProfileWithoutSetupWizard() throws Exception {
         setupProfileOwner();
-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
 
         exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE,
                 DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
@@ -2474,7 +2469,6 @@
 
     public void testSetUserProvisioningState_illegalTransitionOutOfFinalized1() throws Exception {
         setupProfileOwner();
-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
 
         assertExpectException(IllegalStateException.class,
                 /* messageRegex= */ "Cannot move to user provisioning state",
@@ -2486,7 +2480,6 @@
     public void testSetUserProvisioningState_illegalTransitionToAnotherInProgressState()
             throws Exception {
         setupProfileOwner();
-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
 
         assertExpectException(IllegalStateException.class,
                 /* messageRegex= */ "Cannot move to user provisioning state",
@@ -2496,6 +2489,9 @@
     }
 
     private void exerciseUserProvisioningTransitions(int userId, int... states) {
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        mContext.callerPermissions.add(permission.MANAGE_USERS);
+
         assertEquals(DevicePolicyManager.STATE_USER_UNMANAGED, dpm.getUserProvisioningState());
         for (int state : states) {
             dpm.setUserProvisioningState(state, userId);
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
index fb25cf3..d922df3 100644
--- a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
@@ -85,6 +85,9 @@
         255
     };
 
+    private static final int[] MINIMUM_BRIGHTNESS_CURVE_LUX = { 2000, 4000 };
+    private static final float[] MINIMUM_BRIGHTNESS_CURVE_NITS = { 1.0f, 50.0f, 90.0f };
+
     private static final float[] DISPLAY_RANGE_NITS = { 2.685f, 478.5f };
     private static final int[] BACKLIGHT_RANGE = { 1, 255 };
 
@@ -381,6 +384,19 @@
                 com.android.internal.R.array.config_autoBrightnessDisplayValuesNits))
                 .thenReturn(mockBrightnessLevelNits);
 
+        int[] mockMinimumBrightnessCurveLux = new int[MINIMUM_BRIGHTNESS_CURVE_LUX.length];
+        for (int i = 0; i < mockMinimumBrightnessCurveLux.length; i++) {
+            mockMinimumBrightnessCurveLux[i] = (int) MINIMUM_BRIGHTNESS_CURVE_LUX[i];
+        }
+        when(mockResources.getIntArray(
+                com.android.internal.R.array.config_autoBrightnessMinimumBrightnessCurveLux))
+                .thenReturn(mockMinimumBrightnessCurveLux);
+        TypedArray mockMinimumBrightnessCurveNits = createFloatTypedArray(
+                MINIMUM_BRIGHTNESS_CURVE_NITS);
+        when(mockResources.obtainTypedArray(
+                com.android.internal.R.array.config_autoBrightnessMinimumBrightnessCurveNits))
+                .thenReturn(mockMinimumBrightnessCurveNits);
+
         TypedArray mockNitsRange = createFloatTypedArray(nitsRange);
         when(mockResources.obtainTypedArray(
                 com.android.internal.R.array.config_screenBrightnessNits))
@@ -419,4 +435,78 @@
         return mockArray;
     }
 
+    private float[] getNearMinimumNits(float epsilon) {
+        float[] lux = new float[MINIMUM_BRIGHTNESS_CURVE_LUX.length + 1];
+        for (int i = 0; i < MINIMUM_BRIGHTNESS_CURVE_LUX.length; i++) {
+            lux[i+1] = MINIMUM_BRIGHTNESS_CURVE_LUX[i];
+        }
+        Spline minimumBrightnessCurve = Spline.createSpline(lux, MINIMUM_BRIGHTNESS_CURVE_NITS);
+        float[] nits = new float[LUX_LEVELS.length];
+        for (int i = 0; i < nits.length; i++) {
+            nits[i] = minimumBrightnessCurve.interpolate(LUX_LEVELS[i]) + epsilon;
+        }
+        return nits;
+    }
+
+    @Test
+    public void testCreateWithTooDarkBrightnessConfigurationThrowsException() {
+        float[] nits = getNearMinimumNits(-0.1f);
+        Resources res = createResources(LUX_LEVELS, nits, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
+        Exception thrown = null;
+        try {
+            BrightnessMappingStrategy.create(res);
+        } catch (IllegalArgumentException e) {
+            thrown = e;
+        }
+        assertNotNull("Failed to throw IllegalArgumentException", thrown);
+    }
+
+    @Test
+    public void testCreationWithBrightEnoughBrightnessConfigurationDoesNotThrowException() {
+        float[] nits = getNearMinimumNits(0);
+        Resources res = createResources(LUX_LEVELS, nits, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
+        assertNotNull("Failed to create BrightnessMappingStrategy",
+                BrightnessMappingStrategy.create(res));
+    }
+
+    @Test
+    public void testSettingTooDarkBrightnessConfigurationThrowsException() {
+        Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS,
+                BACKLIGHT_RANGE);
+        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res);
+        assertNotNull("Failed to create BrightnessMappingStrategy", strategy);
+        float[] lux = new float[LUX_LEVELS.length];
+        for (int i = 0; i < lux.length; i++) {
+            lux[i] = LUX_LEVELS[i];
+        }
+        float[] nits = getNearMinimumNits(-0.1f);
+        BrightnessConfiguration config = new BrightnessConfiguration.Builder()
+                .setCurve(lux, nits)
+                .build();
+        Exception thrown = null;
+        try {
+            strategy.setBrightnessConfiguration(config);
+        } catch (IllegalArgumentException e) {
+            thrown = e;
+        }
+        assertNotNull("Failed to throw IllegalArgumentException", thrown);
+    }
+
+    @Test
+    public void testSettingBrightEnouhgBrightnessConfigurationDoesNotThrowException() {
+        Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS,
+                BACKLIGHT_RANGE);
+        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res);
+        assertNotNull("Failed to create BrightnessMappingStrategy", strategy);
+        float[] lux = new float[LUX_LEVELS.length];
+        for (int i = 0; i < lux.length; i++) {
+            lux[i] = LUX_LEVELS[i];
+        }
+        float[] nits = getNearMinimumNits(0);
+        BrightnessConfiguration config = new BrightnessConfiguration.Builder()
+                .setCurve(lux, nits)
+                .build();
+        assertTrue("failed to set brightness configuration",
+            strategy.setBrightnessConfiguration(config));
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index fc2da39..06b94cb 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -144,6 +144,13 @@
     private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
     private static final String WRAPPING_KEY_ALIAS = "RecoverableKeyStoreManagerTest/WrappingKey";
     private static final String TEST_ROOT_CERT_ALIAS = "";
+    private static final KeyChainProtectionParams TEST_PROTECTION_PARAMS =
+    new KeyChainProtectionParams.Builder()
+            .setUserSecretType(TYPE_LOCKSCREEN)
+            .setLockScreenUiFormat(UI_FORMAT_PASSWORD)
+            .setKeyDerivationParams(KeyDerivationParams.createSha256Params(TEST_SALT))
+            .setSecret(TEST_SECRET)
+            .build();
 
     @Mock private Context mMockContext;
     @Mock private RecoverySnapshotListenersStorage mMockListenersStorage;
@@ -459,12 +466,7 @@
                 TEST_PUBLIC_KEY,
                 TEST_VAULT_PARAMS,
                 TEST_VAULT_CHALLENGE,
-                ImmutableList.of(
-                        new KeyChainProtectionParams(
-                                TYPE_LOCKSCREEN,
-                                UI_FORMAT_PASSWORD,
-                                KeyDerivationParams.createSha256Params(TEST_SALT),
-                                TEST_SECRET)));
+                ImmutableList.of(TEST_PROTECTION_PARAMS));
 
         verify(mMockContext, times(1))
                 .enforceCallingOrSelfPermission(
@@ -481,12 +483,7 @@
                 RecoveryCertPath.createRecoveryCertPath(TestData.CERT_PATH_1),
                 TEST_VAULT_PARAMS,
                 TEST_VAULT_CHALLENGE,
-                ImmutableList.of(
-                        new KeyChainProtectionParams(
-                                TYPE_LOCKSCREEN,
-                                UI_FORMAT_PASSWORD,
-                                KeyDerivationParams.createSha256Params(TEST_SALT),
-                                TEST_SECRET)));
+                ImmutableList.of(TEST_PROTECTION_PARAMS));
 
         assertEquals(1, mRecoverySessionStorage.size());
         RecoverySessionStorage.Entry entry =
@@ -503,12 +500,7 @@
                 RecoveryCertPath.createRecoveryCertPath(TestData.CERT_PATH_1),
                 TEST_VAULT_PARAMS,
                 TEST_VAULT_CHALLENGE,
-                ImmutableList.of(
-                        new KeyChainProtectionParams(
-                                TYPE_LOCKSCREEN,
-                                UI_FORMAT_PASSWORD,
-                                KeyDerivationParams.createSha256Params(TEST_SALT),
-                                TEST_SECRET)));
+                ImmutableList.of(TEST_PROTECTION_PARAMS));
 
         verify(mMockContext, times(2))
                 .enforceCallingOrSelfPermission(
@@ -522,12 +514,7 @@
                 TEST_PUBLIC_KEY,
                 TEST_VAULT_PARAMS,
                 TEST_VAULT_CHALLENGE,
-                ImmutableList.of(
-                        new KeyChainProtectionParams(
-                                TYPE_LOCKSCREEN,
-                                UI_FORMAT_PASSWORD,
-                                KeyDerivationParams.createSha256Params(TEST_SALT),
-                                TEST_SECRET)));
+                ImmutableList.of(TEST_PROTECTION_PARAMS));
 
         assertEquals(1, mRecoverySessionStorage.size());
         RecoverySessionStorage.Entry entry =
@@ -543,12 +530,7 @@
                 TEST_PUBLIC_KEY,
                 TEST_VAULT_PARAMS,
                 TEST_VAULT_CHALLENGE,
-                ImmutableList.of(
-                        new KeyChainProtectionParams(
-                                TYPE_LOCKSCREEN,
-                                UI_FORMAT_PASSWORD,
-                                KeyDerivationParams.createSha256Params(TEST_SALT),
-                                TEST_SECRET)));
+                ImmutableList.of(TEST_PROTECTION_PARAMS));
 
         mRecoverableKeyStoreManager.closeSession(TEST_SESSION_ID);
 
@@ -562,12 +544,7 @@
                 TEST_PUBLIC_KEY,
                 TEST_VAULT_PARAMS,
                 TEST_VAULT_CHALLENGE,
-                ImmutableList.of(
-                        new KeyChainProtectionParams(
-                                TYPE_LOCKSCREEN,
-                                UI_FORMAT_PASSWORD,
-                                KeyDerivationParams.createSha256Params(TEST_SALT),
-                                TEST_SECRET)));
+                ImmutableList.of(TEST_PROTECTION_PARAMS));
 
         mRecoverableKeyStoreManager.closeSession("some random session");
 
@@ -604,18 +581,14 @@
     public void startRecoverySession_throwsIfPublicKeysMismatch() throws Exception {
         byte[] vaultParams = TEST_VAULT_PARAMS.clone();
         vaultParams[1] ^= (byte) 1;  // Flip 1 bit
+
         try {
             mRecoverableKeyStoreManager.startRecoverySession(
                     TEST_SESSION_ID,
                     TEST_PUBLIC_KEY,
                     vaultParams,
                     TEST_VAULT_CHALLENGE,
-                    ImmutableList.of(
-                            new KeyChainProtectionParams(
-                                    TYPE_LOCKSCREEN,
-                                    UI_FORMAT_PASSWORD,
-                                    KeyDerivationParams.createSha256Params(TEST_SALT),
-                                    TEST_SECRET)));
+                    ImmutableList.of(TEST_PROTECTION_PARAMS));
             fail("should have thrown");
         } catch (ServiceSpecificException e) {
             assertThat(e.getMessage()).contains("do not match");
@@ -650,12 +623,7 @@
                     RecoveryCertPath.createRecoveryCertPath(TestData.CERT_PATH_1),
                     vaultParams,
                     TEST_VAULT_CHALLENGE,
-                    ImmutableList.of(
-                            new KeyChainProtectionParams(
-                                    TYPE_LOCKSCREEN,
-                                    UI_FORMAT_PASSWORD,
-                                    KeyDerivationParams.createSha256Params(TEST_SALT),
-                                    TEST_SECRET)));
+                    ImmutableList.of(TEST_PROTECTION_PARAMS));
             fail("should have thrown");
         } catch (ServiceSpecificException e) {
             assertThat(e.getMessage()).contains("do not match");
@@ -673,12 +641,7 @@
                     RecoveryCertPath.createRecoveryCertPath(emptyCertPath),
                     TEST_VAULT_PARAMS,
                     TEST_VAULT_CHALLENGE,
-                    ImmutableList.of(
-                            new KeyChainProtectionParams(
-                                    TYPE_LOCKSCREEN,
-                                    UI_FORMAT_PASSWORD,
-                                    KeyDerivationParams.createSha256Params(TEST_SALT),
-                                    TEST_SECRET)));
+                    ImmutableList.of(TEST_PROTECTION_PARAMS));
             fail("should have thrown");
         } catch (ServiceSpecificException e) {
             assertThat(e.getMessage()).contains("empty");
@@ -698,12 +661,7 @@
                     RecoveryCertPath.createRecoveryCertPath(shortCertPath),
                     TEST_VAULT_PARAMS,
                     TEST_VAULT_CHALLENGE,
-                    ImmutableList.of(
-                            new KeyChainProtectionParams(
-                                    TYPE_LOCKSCREEN,
-                                    UI_FORMAT_PASSWORD,
-                                    KeyDerivationParams.createSha256Params(TEST_SALT),
-                                    TEST_SECRET)));
+                    ImmutableList.of(TEST_PROTECTION_PARAMS));
             fail("should have thrown");
         } catch (ServiceSpecificException e) {
             // expected
@@ -734,11 +692,7 @@
                 TEST_PUBLIC_KEY,
                 TEST_VAULT_PARAMS,
                 TEST_VAULT_CHALLENGE,
-                ImmutableList.of(new KeyChainProtectionParams(
-                        TYPE_LOCKSCREEN,
-                        UI_FORMAT_PASSWORD,
-                        KeyDerivationParams.createSha256Params(TEST_SALT),
-                        TEST_SECRET)));
+                ImmutableList.of(TEST_PROTECTION_PARAMS));
 
         try {
             mRecoverableKeyStoreManager.recoverKeyChainSnapshot(
@@ -758,11 +712,7 @@
                 TEST_PUBLIC_KEY,
                 TEST_VAULT_PARAMS,
                 TEST_VAULT_CHALLENGE,
-                ImmutableList.of(new KeyChainProtectionParams(
-                        TYPE_LOCKSCREEN,
-                        UI_FORMAT_PASSWORD,
-                        KeyDerivationParams.createSha256Params(TEST_SALT),
-                        TEST_SECRET)));
+                ImmutableList.of(TEST_PROTECTION_PARAMS));
         byte[] keyClaimant = mRecoverySessionStorage.get(Binder.getCallingUid(), TEST_SESSION_ID)
                 .getKeyClaimant();
         SecretKey recoveryKey = randomRecoveryKey();
@@ -792,11 +742,7 @@
                 TEST_PUBLIC_KEY,
                 TEST_VAULT_PARAMS,
                 TEST_VAULT_CHALLENGE,
-                ImmutableList.of(new KeyChainProtectionParams(
-                        TYPE_LOCKSCREEN,
-                        UI_FORMAT_PASSWORD,
-                        KeyDerivationParams.createSha256Params(TEST_SALT),
-                        TEST_SECRET)));
+                ImmutableList.of(TEST_PROTECTION_PARAMS));
         byte[] keyClaimant = mRecoverySessionStorage.get(Binder.getCallingUid(), TEST_SESSION_ID)
                 .getKeyClaimant();
         SecretKey recoveryKey = randomRecoveryKey();
@@ -816,11 +762,7 @@
                 TEST_PUBLIC_KEY,
                 TEST_VAULT_PARAMS,
                 TEST_VAULT_CHALLENGE,
-                ImmutableList.of(new KeyChainProtectionParams(
-                        TYPE_LOCKSCREEN,
-                        UI_FORMAT_PASSWORD,
-                        KeyDerivationParams.createSha256Params(TEST_SALT),
-                        TEST_SECRET)));
+                ImmutableList.of(TEST_PROTECTION_PARAMS));
         byte[] keyClaimant = mRecoverySessionStorage.get(Binder.getCallingUid(), TEST_SESSION_ID)
                 .getKeyClaimant();
         SecretKey recoveryKey = randomRecoveryKey();
@@ -850,11 +792,7 @@
                 TEST_PUBLIC_KEY,
                 TEST_VAULT_PARAMS,
                 TEST_VAULT_CHALLENGE,
-                ImmutableList.of(new KeyChainProtectionParams(
-                        TYPE_LOCKSCREEN,
-                        UI_FORMAT_PASSWORD,
-                        KeyDerivationParams.createSha256Params(TEST_SALT),
-                        TEST_SECRET)));
+                ImmutableList.of(TEST_PROTECTION_PARAMS));
         byte[] keyClaimant = mRecoverySessionStorage.get(Binder.getCallingUid(), TEST_SESSION_ID)
                 .getKeyClaimant();
         SecretKey recoveryKey = randomRecoveryKey();
@@ -896,7 +834,52 @@
     }
 
     @Test
-    public void setRecoverySecretTypes() throws Exception {
+    public void setServerParams_updatesServerParams() throws Exception {
+        int uid = Binder.getCallingUid();
+        int userId = UserHandle.getCallingUserId();
+        byte[] serverParams = new byte[] { 1 };
+
+        mRecoverableKeyStoreManager.setServerParams(serverParams);
+
+        assertThat(mRecoverableKeyStoreDb.getServerParams(userId, uid)).isEqualTo(serverParams);
+    }
+
+    @Test
+    public void setServerParams_doesNotSetSnapshotPendingIfInitializing() throws Exception {
+        int uid = Binder.getCallingUid();
+        int userId = UserHandle.getCallingUserId();
+        byte[] serverParams = new byte[] { 1 };
+
+        mRecoverableKeyStoreManager.setServerParams(serverParams);
+
+        assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isFalse();
+    }
+
+    @Test
+    public void setServerParams_doesNotSetSnapshotPendingIfSettingSameValue() throws Exception {
+        int uid = Binder.getCallingUid();
+        int userId = UserHandle.getCallingUserId();
+        byte[] serverParams = new byte[] { 1 };
+
+        mRecoverableKeyStoreManager.setServerParams(serverParams);
+        mRecoverableKeyStoreManager.setServerParams(serverParams);
+
+        assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isFalse();
+    }
+
+    @Test
+    public void setServerParams_setsSnapshotPendingIfUpdatingValue() throws Exception {
+        int uid = Binder.getCallingUid();
+        int userId = UserHandle.getCallingUserId();
+
+        mRecoverableKeyStoreManager.setServerParams(new byte[] { 1 });
+        mRecoverableKeyStoreManager.setServerParams(new byte[] { 2 });
+
+        assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isTrue();
+    }
+
+    @Test
+    public void setRecoverySecretTypes_updatesSecretTypes() throws Exception {
         int[] types1 = new int[]{11, 2000};
         int[] types2 = new int[]{1, 2, 3};
         int[] types3 = new int[]{};
@@ -915,6 +898,41 @@
     }
 
     @Test
+    public void setRecoverySecretTypes_doesNotSetSnapshotPendingIfIniting() throws Exception {
+        int uid = Binder.getCallingUid();
+        int userId = UserHandle.getCallingUserId();
+        int[] secretTypes = new int[] { 101 };
+
+        mRecoverableKeyStoreManager.setRecoverySecretTypes(secretTypes);
+
+        assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isFalse();
+    }
+
+    @Test
+    public void setRecoverySecretTypes_doesNotSetSnapshotPendingIfSettingSameValue()
+            throws Exception {
+        int uid = Binder.getCallingUid();
+        int userId = UserHandle.getCallingUserId();
+        int[] secretTypes = new int[] { 101 };
+
+        mRecoverableKeyStoreManager.setRecoverySecretTypes(secretTypes);
+        mRecoverableKeyStoreManager.setRecoverySecretTypes(secretTypes);
+
+        assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isFalse();
+    }
+
+    @Test
+    public void setRecoverySecretTypes_setsSnapshotPendingIfUpdatingValue() throws Exception {
+        int uid = Binder.getCallingUid();
+        int userId = UserHandle.getCallingUserId();
+
+        mRecoverableKeyStoreManager.setRecoverySecretTypes(new int[] { 101 });
+        mRecoverableKeyStoreManager.setRecoverySecretTypes(new int[] { 102 });
+
+        assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isTrue();
+    }
+
+    @Test
     public void setRecoverySecretTypes_throwsIfNullTypes() throws Exception {
         try {
             mRecoverableKeyStoreManager.setRecoverySecretTypes(/*types=*/ null);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java
index d61a294..c772956 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java
@@ -7,14 +7,19 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
+import com.android.server.locksettings.recoverablekeystore.TestData;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.security.cert.CertificateException;
 import java.util.ArrayList;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class RecoverySnapshotStorageTest {
+    private static final KeyChainSnapshot MINIMAL_KEYCHAIN_SNAPSHOT =
+            createMinimalKeyChainSnapshot();
 
     private final RecoverySnapshotStorage mRecoverySnapshotStorage = new RecoverySnapshotStorage();
 
@@ -26,28 +31,36 @@
     @Test
     public void get_returnsSetSnapshot() {
         int userId = 1000;
-        KeyChainSnapshot keyChainSnapshot = new KeyChainSnapshot(
-                /*snapshotVersion=*/ 1,
-                new ArrayList<>(),
-                new ArrayList<>(),
-                new byte[0]);
-        mRecoverySnapshotStorage.put(userId, keyChainSnapshot);
 
-        assertEquals(keyChainSnapshot, mRecoverySnapshotStorage.get(userId));
+        mRecoverySnapshotStorage.put(userId, MINIMAL_KEYCHAIN_SNAPSHOT);
+
+        assertEquals(MINIMAL_KEYCHAIN_SNAPSHOT, mRecoverySnapshotStorage.get(userId));
     }
 
     @Test
     public void remove_removesSnapshots() {
         int userId = 1000;
-        KeyChainSnapshot keyChainSnapshot = new KeyChainSnapshot(
-                /*snapshotVersion=*/ 1,
-                new ArrayList<>(),
-                new ArrayList<>(),
-                new byte[0]);
-        mRecoverySnapshotStorage.put(userId, keyChainSnapshot);
 
+        mRecoverySnapshotStorage.put(userId, MINIMAL_KEYCHAIN_SNAPSHOT);
         mRecoverySnapshotStorage.remove(userId);
 
         assertNull(mRecoverySnapshotStorage.get(1000));
     }
+
+    private static KeyChainSnapshot createMinimalKeyChainSnapshot() {
+        try {
+            return new KeyChainSnapshot.Builder()
+                    .setCounterId(1)
+                    .setSnapshotVersion(1)
+                    .setServerParams(new byte[0])
+                    .setMaxAttempts(10)
+                    .setEncryptedRecoveryKeyBlob(new byte[0])
+                    .setKeyChainProtectionParams(new ArrayList<>())
+                    .setWrappedApplicationKeys(new ArrayList<>())
+                    .setTrustedHardwareCertPath(TestData.CERT_PATH_1)
+                    .build();
+        } catch (CertificateException e) {
+            throw new RuntimeException(e);
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
new file mode 100644
index 0000000..ab640d6
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
@@ -0,0 +1,532 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.power.batterysaver;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.ContentResolver;
+import android.provider.Settings.Global;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.mock.MockContext;
+
+import com.google.common.base.Objects;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashMap;
+
+/**
+ atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BatterySaverStateMachineTest {
+
+    private MyMockContext mMockContext;
+    private ContentResolver mMockContextResolver;
+    private BatterySaverController mMockBatterySaverController;
+    private Device mDevice;
+    private TestableBatterySaverStateMachine mTarget;
+
+    private class MyMockContext extends MockContext {
+        @Override
+        public ContentResolver getContentResolver() {
+            return mMockContextResolver;
+        }
+    }
+
+    private DevicePersistedState mPersistedState;
+
+    private class DevicePersistedState {
+        // Current battery level.
+        public int batteryLevel = 100;
+
+        // Whether battery level is currently low or not.
+        public boolean batteryLow = false;
+
+        // Whether the device is plugged in or not.
+        public boolean powered = false;
+
+        // Global settings.
+        public final HashMap<String, Integer> global = new HashMap<>();
+    }
+
+    /**
+     * This class simulates a device's volatile status that will be reset by {@link #initDevice()}.
+     */
+    private class Device {
+        public boolean batterySaverEnabled = false;
+
+        public int getLowPowerModeTriggerLevel() {
+            return mPersistedState.global.getOrDefault(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
+        }
+
+        public void setBatteryLevel(int level) {
+            mPersistedState.batteryLevel = level;
+            if (mPersistedState.batteryLevel <= Math.max(15, getLowPowerModeTriggerLevel())) {
+                mPersistedState.batteryLow = true;
+            } else if (mPersistedState.batteryLow
+                    && (mPersistedState.batteryLevel >= (getLowPowerModeTriggerLevel() + 5))) {
+                mPersistedState.batteryLow = false;
+            }
+            pushBatteryStatus();
+        }
+
+        public void setPowered(boolean newPowered) {
+            mPersistedState.powered = newPowered;
+            pushBatteryStatus();
+        }
+
+        public void pushBatteryStatus() {
+            mTarget.setBatteryStatus(mPersistedState.powered, mPersistedState.batteryLevel,
+                    mPersistedState.batteryLow);
+        }
+
+        public void pushGlobalSettings() {
+            mTarget.setSettingsLocked(
+                    mPersistedState.global.getOrDefault(Global.LOW_POWER_MODE, 0) != 0,
+                    mPersistedState.global.getOrDefault(Global.LOW_POWER_MODE_STICKY, 0) != 0,
+                    mDevice.getLowPowerModeTriggerLevel());
+        }
+
+        public void putGlobalSetting(String key, int value) {
+            mPersistedState.global.put(key, value);
+            pushGlobalSettings();
+        }
+
+        public int getGlobalSetting(String key, int defValue) {
+            return mPersistedState.global.getOrDefault(key, defValue);
+        }
+    }
+
+    /**
+     * Test target class.
+     */
+    private class TestableBatterySaverStateMachine extends BatterySaverStateMachine {
+        public TestableBatterySaverStateMachine() {
+            super(mMockContext, mMockBatterySaverController);
+        }
+
+        @Override
+        protected void putGlobalSetting(String key, int value) {
+            if (Objects.equal(mPersistedState.global.get(key), value)) {
+                return;
+            }
+            mDevice.putGlobalSetting(key, value);
+        }
+
+        @Override
+        protected int getGlobalSetting(String key, int defValue) {
+            return mDevice.getGlobalSetting(key, defValue);
+        }
+    }
+
+    @Before
+    public void setUp() {
+        mMockContext = new MyMockContext();
+        mMockContextResolver = mock(ContentResolver.class);
+        mMockBatterySaverController = mock(BatterySaverController.class);
+
+        doAnswer((inv) -> mDevice.batterySaverEnabled = inv.getArgument(0))
+                .when(mMockBatterySaverController).enableBatterySaver(anyBoolean());
+        when(mMockBatterySaverController.isEnabled())
+                .thenAnswer((inv) -> mDevice.batterySaverEnabled);
+
+        mPersistedState = new DevicePersistedState();
+        initDevice();
+    }
+
+    private void initDevice() {
+        mDevice = new Device();
+
+        mTarget = new TestableBatterySaverStateMachine();
+
+        mDevice.pushBatteryStatus();
+        mDevice.pushGlobalSettings();
+        mTarget.onBootCompleted();
+    }
+
+    @Test
+    public void testNoAutoBatterySaver() {
+        assertEquals(0, mDevice.getLowPowerModeTriggerLevel());
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(100, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(90);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(50);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(50, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(16);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(16, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // When LOW_POWER_MODE_TRIGGER_LEVEL is 0, 15% will still trigger low-battery, but
+        // BS wont be enabled.
+        mDevice.setBatteryLevel(15);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(15, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(10);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(10, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        // Manually enable BS.
+        mTarget.setBatterySaverEnabledManually(true);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(10, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(50);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(50, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Start charging. It'll disable BS.
+        mDevice.setPowered(true);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(50, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(60);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(60, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Unplug.
+        mDevice.setPowered(false);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(60, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(10);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(10, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(80);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(80, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Reboot the device.
+        initDevice();
+
+        assertEquals(true, mDevice.batterySaverEnabled); // Sticky.
+        assertEquals(80, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(30);
+        initDevice();
+
+        assertEquals(true, mDevice.batterySaverEnabled); // Still sticky.
+        assertEquals(30, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mTarget.setBatterySaverEnabledManually(false);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        initDevice(); // reboot.
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+    }
+
+    @Test
+    public void testAutoBatterySaver() {
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(100, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(90);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(51);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(51, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Hit the threshold. BS should be enabled.
+        mDevice.setBatteryLevel(50);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(50, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        // Battery goes up, but until it hits 55%, we still keep BS on.
+        mDevice.setBatteryLevel(54);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(54, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        // 50% + 5%, now BS will be off.
+        mDevice.setBatteryLevel(55);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(55, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(40);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(40, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setPowered(true);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(40, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setPowered(false);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(40, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(40, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(30);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        // Plug in and out, snooze will reset.
+        mDevice.setPowered(true);
+        mDevice.setPowered(false);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setPowered(true);
+        mDevice.setBatteryLevel(60);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(60, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setPowered(false);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(60, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(50);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(50, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(70);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(70, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Bump ump the threshold.
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 70);
+        mDevice.setBatteryLevel(mPersistedState.batteryLevel);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(70, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        // Then down.
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 60);
+        mDevice.setBatteryLevel(mPersistedState.batteryLevel);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(70, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Reboot in low state -> automatically enable BS.
+        mDevice.setPowered(false);
+        mDevice.setBatteryLevel(30);
+        mTarget.setBatterySaverEnabledManually(false);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        initDevice();
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+    }
+
+    @Test
+    public void testAutoBatterySaver_withSticky() {
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
+
+        mTarget.setBatterySaverEnabledManually(true);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(100, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(30);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(80);
+
+        assertEquals(true, mDevice.batterySaverEnabled); // Still enabled.
+        assertEquals(80, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setPowered(true);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(80, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(30);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setPowered(false);
+
+        assertEquals(true, mDevice.batterySaverEnabled); // Restores BS.
+        assertEquals(30, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setPowered(true);
+        mDevice.setBatteryLevel(90);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        initDevice();
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setPowered(false);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mTarget.setBatterySaverEnabledManually(false);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        initDevice();
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+    }
+
+    @Test
+    public void testNoAutoBatterySaver_fromAdb() {
+
+        assertEquals(0, mDevice.getLowPowerModeTriggerLevel());
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(100, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(90);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Enable
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE, 1);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Disable
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE, 0);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Enable again
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE, 1);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Reboot -- setting BS from adb is also sticky.
+        initDevice();
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 552c915..601999d 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -19,6 +19,7 @@
 import static android.app.usage.UsageEvents.Event.NOTIFICATION_SEEN;
 import static android.app.usage.UsageEvents.Event.SLICE_PINNED;
 import static android.app.usage.UsageEvents.Event.SLICE_PINNED_PRIV;
+import static android.app.usage.UsageEvents.Event.SYSTEM_INTERACTION;
 import static android.app.usage.UsageEvents.Event.USER_INTERACTION;
 import static android.app.usage.UsageStatsManager.REASON_MAIN_DEFAULT;
 import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED;
@@ -569,6 +570,31 @@
     }
 
     @Test
+    public void testSystemInteractionTimeout() throws Exception {
+        setChargingState(mController, false);
+
+        reportEvent(mController, USER_INTERACTION, 0);
+        // Fast forward to RARE
+        mInjector.mElapsedRealtime = RARE_THRESHOLD + 100;
+        mController.checkIdleStates(USER_ID);
+        assertBucket(STANDBY_BUCKET_RARE);
+
+        // Trigger a SYSTEM_INTERACTION and verify bucket
+        reportEvent(mController, SYSTEM_INTERACTION, mInjector.mElapsedRealtime);
+        assertBucket(STANDBY_BUCKET_ACTIVE);
+
+        // Verify it's still in ACTIVE close to end of timeout
+        mInjector.mElapsedRealtime += mController.mSystemInteractionTimeoutMillis - 100;
+        mController.checkIdleStates(USER_ID);
+        assertBucket(STANDBY_BUCKET_ACTIVE);
+
+        // Verify bucket moves to RARE after timeout
+        mInjector.mElapsedRealtime += 200;
+        mController.checkIdleStates(USER_ID);
+        assertBucket(STANDBY_BUCKET_RARE);
+    }
+
+    @Test
     public void testPredictionNotOverridden() throws Exception {
         setChargingState(mController, false);
 
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index b645700..7f1bcac 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -30,8 +30,10 @@
 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
+import static org.hamcrest.Matchers.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -436,6 +438,20 @@
     }
 
     @Test
+    public void testLayoutSeq_assignedDuringLayout() throws Exception {
+        synchronized (sWm.getWindowManagerLock()) {
+
+            final DisplayContent dc = createNewDisplay();
+            final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
+
+            dc.setLayoutNeeded();
+            dc.performLayout(true /* initial */, false /* updateImeWindows */);
+
+            assertThat(win.mLayoutSeq, is(dc.mLayoutSeq));
+        }
+    }
+
+    @Test
     @SuppressLint("InlinedApi")
     public void testOrientationDefinedByKeyguard() {
         final DisplayContent dc = createNewDisplay();
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
index 56b7d9f..1248eae 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
@@ -40,9 +40,12 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -312,6 +315,17 @@
         assertTrue(child2.isSelfOrAncestorWindowAnimatingExit());
     }
 
+    @Test
+    public void testLayoutSeqResetOnReparent() throws Exception {
+        final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+        app.mLayoutSeq = 1;
+        mDisplayContent.mLayoutSeq = 1;
+
+        app.onDisplayChanged(mDisplayContent);
+
+        assertThat(app.mLayoutSeq, not(is(mDisplayContent.mLayoutSeq)));
+    }
+
     private void testPrepareWindowToDisplayDuringRelayout(boolean wasVisible) {
         reset(mPowerManagerWrapper);
         final WindowState root = createWindow(null, TYPE_APPLICATION, "root");
diff --git a/services/tests/servicestests/src/com/android/server/wm/utils/InsetUtilsTest.java b/services/tests/servicestests/src/com/android/server/wm/utils/InsetUtilsTest.java
new file mode 100644
index 0000000..d0f0fe3
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/utils/InsetUtilsTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm.utils;
+
+import static junit.framework.Assert.assertEquals;
+
+import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Pair;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class InsetUtilsTest {
+
+    @Test
+    public void testAdd() throws Exception {
+        final Rect rect1 = new Rect(10, 20, 30, 40);
+        final Rect rect2 = new Rect(50, 60, 70, 80);
+        InsetUtils.addInsets(rect1, rect2);
+        assertEquals(new Rect(60, 80, 100, 120), rect1);
+    }
+}
+
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 1af5f46..9139a4c 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -198,6 +198,10 @@
     long mSystemUpdateUsageTimeoutMillis;
     /** Maximum time to wait for a prediction before using simple timeouts to downgrade buckets. */
     long mPredictionTimeoutMillis;
+    /** Maximum time a sync adapter associated with a CP should keep the buckets elevated. */
+    long mSyncAdapterTimeoutMillis;
+    /** Maximum time a system interaction should keep the buckets elevated. */
+    long mSystemInteractionTimeoutMillis;
 
     volatile boolean mAppIdleEnabled;
     boolean mAppIdleTempParoled;
@@ -357,8 +361,8 @@
                     synchronized (mAppIdleLock) {
                         AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId,
                                 STANDBY_BUCKET_ACTIVE, REASON_SUB_USAGE_SYNC_ADAPTER,
-                                elapsedRealtime,
-                                elapsedRealtime + mStrongUsageTimeoutMillis);
+                                0,
+                                elapsedRealtime + mSyncAdapterTimeoutMillis);
                         maybeInformListeners(packageName, userId, elapsedRealtime,
                                 appUsage.currentBucket, appUsage.bucketingReason, false);
                     }
@@ -708,7 +712,11 @@
                             STANDBY_BUCKET_WORKING_SET, subReason,
                             0, elapsedRealtime + mNotificationSeenTimeoutMillis);
                     nextCheckTime = mNotificationSeenTimeoutMillis;
-
+                } else if (event.mEventType == UsageEvents.Event.SYSTEM_INTERACTION) {
+                    mAppIdleHistory.reportUsage(appHistory, event.mPackage,
+                            STANDBY_BUCKET_ACTIVE, subReason,
+                            0, elapsedRealtime + mSystemInteractionTimeoutMillis);
+                    nextCheckTime = mSystemInteractionTimeoutMillis;
                 } else {
                     mAppIdleHistory.reportUsage(appHistory, event.mPackage,
                             STANDBY_BUCKET_ACTIVE, subReason,
@@ -1523,6 +1531,14 @@
         private static final String KEY_SYSTEM_UPDATE_HOLD_DURATION =
                 "system_update_usage_duration";
         private static final String KEY_PREDICTION_TIMEOUT = "prediction_timeout";
+        private static final String KEY_SYNC_ADAPTER_HOLD_DURATION = "sync_adapter_duration";
+        private static final String KEY_SYSTEM_INTERACTION_HOLD_DURATION =
+                "system_interaction_duration";
+        public static final long DEFAULT_STRONG_USAGE_TIMEOUT = 1 * ONE_HOUR;
+        public static final long DEFAULT_NOTIFICATION_TIMEOUT = 12 * ONE_HOUR;
+        public static final long DEFAULT_SYSTEM_UPDATE_TIMEOUT = 2 * ONE_HOUR;
+        public static final long DEFAULT_SYSTEM_INTERACTION_TIMEOUT = 10 * ONE_MINUTE;
+        public static final long DEFAULT_SYNC_ADAPTER_TIMEOUT = 10 * ONE_MINUTE;
 
         private final KeyValueListParser mParser = new KeyValueListParser(',');
 
@@ -1585,16 +1601,22 @@
                         COMPRESS_TIME ? ONE_MINUTE : 4 * 60 * ONE_MINUTE); // 4 hours
                 mStrongUsageTimeoutMillis = mParser.getDurationMillis
                         (KEY_STRONG_USAGE_HOLD_DURATION,
-                                COMPRESS_TIME ? ONE_MINUTE : 1 * ONE_HOUR);
+                                COMPRESS_TIME ? ONE_MINUTE : DEFAULT_STRONG_USAGE_TIMEOUT);
                 mNotificationSeenTimeoutMillis = mParser.getDurationMillis
                         (KEY_NOTIFICATION_SEEN_HOLD_DURATION,
-                                COMPRESS_TIME ? 12 * ONE_MINUTE : 12 * ONE_HOUR);
+                                COMPRESS_TIME ? 12 * ONE_MINUTE : DEFAULT_NOTIFICATION_TIMEOUT);
                 mSystemUpdateUsageTimeoutMillis = mParser.getDurationMillis
                         (KEY_SYSTEM_UPDATE_HOLD_DURATION,
-                                COMPRESS_TIME ? 2 * ONE_MINUTE : 2 * ONE_HOUR);
+                                COMPRESS_TIME ? 2 * ONE_MINUTE : DEFAULT_SYSTEM_UPDATE_TIMEOUT);
                 mPredictionTimeoutMillis = mParser.getDurationMillis
                         (KEY_PREDICTION_TIMEOUT,
                                 COMPRESS_TIME ? 10 * ONE_MINUTE : DEFAULT_PREDICTION_TIMEOUT);
+                mSyncAdapterTimeoutMillis = mParser.getDurationMillis
+                        (KEY_SYNC_ADAPTER_HOLD_DURATION,
+                                COMPRESS_TIME ? ONE_MINUTE : DEFAULT_SYNC_ADAPTER_TIMEOUT);
+                mSystemInteractionTimeoutMillis = mParser.getDurationMillis
+                        (KEY_SYSTEM_INTERACTION_HOLD_DURATION,
+                                COMPRESS_TIME ? ONE_MINUTE : DEFAULT_SYSTEM_INTERACTION_TIMEOUT);
             }
         }
 
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index ef0780a..9f8042c 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -83,6 +83,7 @@
 import com.android.server.LocalServices;
 
 import java.io.File;
+import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.HashMap;
@@ -181,6 +182,7 @@
     private final UEventObserver mUEventObserver;
 
     private static Set<Integer> sBlackListedInterfaces;
+    private HashMap<Long, FileDescriptor> mControlFds;
 
     static {
         sBlackListedInterfaces = new HashSet<>();
@@ -270,6 +272,18 @@
             Slog.i(TAG, "USB GADGET HAL not present in the device", e);
         }
 
+        mControlFds = new HashMap<>();
+        FileDescriptor mtpFd = nativeOpenControl(UsbManager.USB_FUNCTION_MTP);
+        if (mtpFd == null) {
+            Slog.e(TAG, "Failed to open control for mtp");
+        }
+        mControlFds.put(UsbManager.FUNCTION_MTP, mtpFd);
+        FileDescriptor ptpFd = nativeOpenControl(UsbManager.USB_FUNCTION_PTP);
+        if (mtpFd == null) {
+            Slog.e(TAG, "Failed to open control for mtp");
+        }
+        mControlFds.put(UsbManager.FUNCTION_PTP, ptpFd);
+
         boolean secureAdbEnabled = SystemProperties.getBoolean("ro.adb.secure", false);
         boolean dataEncrypted = "1".equals(SystemProperties.get("vold.decrypt"));
         if (secureAdbEnabled && !dataEncrypted) {
@@ -704,8 +718,7 @@
             return false;
         }
 
-        protected void updateUsbStateBroadcastIfNeeded(long functions,
-                boolean configChanged) {
+        protected void updateUsbStateBroadcastIfNeeded(long functions) {
             // send a sticky broadcast containing current USB state
             Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
             intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
@@ -716,7 +729,6 @@
             intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured);
             intent.putExtra(UsbManager.USB_DATA_UNLOCKED,
                     isUsbTransferAllowed() && isUsbDataTransferActive(mCurrentFunctions));
-            intent.putExtra(UsbManager.USB_CONFIG_CHANGED, configChanged);
 
             long remainingFunctions = functions;
             while (remainingFunctions != 0) {
@@ -726,7 +738,7 @@
             }
 
             // send broadcast intent only if the USB state has changed
-            if (!isUsbStateChanged(intent) && !configChanged) {
+            if (!isUsbStateChanged(intent)) {
                 if (DEBUG) {
                     Slog.d(TAG, "skip broadcasting " + intent + " extras: " + intent.getExtras());
                 }
@@ -798,8 +810,7 @@
                     updateUsbNotification(false);
                     updateAdbNotification(false);
                     if (mBootCompleted) {
-                        updateUsbStateBroadcastIfNeeded(getAppliedFunctions(mCurrentFunctions),
-                                false);
+                        updateUsbStateBroadcastIfNeeded(getAppliedFunctions(mCurrentFunctions));
                     }
                     if ((mCurrentFunctions & UsbManager.FUNCTION_ACCESSORY) != 0) {
                         updateCurrentAccessory();
@@ -812,7 +823,7 @@
                                     && mScreenUnlockedFunctions != UsbManager.FUNCTION_NONE) {
                                 setScreenUnlockedFunctions();
                             } else {
-                                setEnabledFunctions(UsbManager.FUNCTION_NONE, !mAdbEnabled);
+                                setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
                             }
                         }
                         updateUsbFunctions();
@@ -847,8 +858,7 @@
                     updateUsbNotification(false);
                     if (mBootCompleted) {
                         if (mHostConnected || prevHostConnected) {
-                            updateUsbStateBroadcastIfNeeded(getAppliedFunctions(mCurrentFunctions),
-                                    false);
+                            updateUsbStateBroadcastIfNeeded(getAppliedFunctions(mCurrentFunctions));
                         }
                     } else {
                         mPendingBootBroadcast = true;
@@ -994,7 +1004,7 @@
         protected void finishBoot() {
             if (mBootCompleted && mCurrentUsbFunctionsReceived && mSystemReady) {
                 if (mPendingBootBroadcast) {
-                    updateUsbStateBroadcastIfNeeded(getAppliedFunctions(mCurrentFunctions), false);
+                    updateUsbStateBroadcastIfNeeded(getAppliedFunctions(mCurrentFunctions));
                     mPendingBootBroadcast = false;
                 }
                 if (!mScreenLocked
@@ -1597,7 +1607,7 @@
                     /**
                      * Start up dependent services.
                      */
-                    updateUsbStateBroadcastIfNeeded(getAppliedFunctions(mCurrentFunctions), true);
+                    updateUsbStateBroadcastIfNeeded(getAppliedFunctions(mCurrentFunctions));
                 }
 
                 if (!waitForState(oemFunctions)) {
@@ -1943,7 +1953,7 @@
 
                 if (mBootCompleted && isUsbDataTransferActive(functions)) {
                     // Start up dependent services.
-                    updateUsbStateBroadcastIfNeeded(functions, true);
+                    updateUsbStateBroadcastIfNeeded(functions);
                 }
             }
         }
@@ -1979,6 +1989,22 @@
         return mHandler.getEnabledFunctions();
     }
 
+    /**
+     * Returns a dup of the control file descriptor for the given function.
+     */
+    public ParcelFileDescriptor getControlFd(long usbFunction) {
+        FileDescriptor fd = mControlFds.get(usbFunction);
+        if (fd == null) {
+            return null;
+        }
+        try {
+            return ParcelFileDescriptor.dup(fd);
+        } catch (IOException e) {
+            Slog.e(TAG, "Could not dup fd for " + usbFunction);
+            return null;
+        }
+    }
+
     public long getScreenUnlockedFunctions() {
         return mHandler.getScreenUnlockedFunctions();
     }
@@ -2063,6 +2089,8 @@
 
     private native ParcelFileDescriptor nativeOpenAccessory();
 
+    private native FileDescriptor nativeOpenControl(String usbFunction);
+
     private native boolean nativeIsStartRequested();
 
     private native int nativeGetAudioMode();
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 0fcd075..67ad090 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -54,6 +54,7 @@
 public class UsbHostManager {
     private static final String TAG = UsbHostManager.class.getSimpleName();
     private static final boolean DEBUG = false;
+    private static final int LINUX_FOUNDATION_VID = 0x1d6b;
 
     private final Context mContext;
 
@@ -267,7 +268,6 @@
     }
 
     private boolean isBlackListed(String deviceAddress) {
-        Slog.i(TAG, "isBlackListed(" + deviceAddress + ")");
         int count = mHostBlacklist.length;
         for (int i = 0; i < count; i++) {
             if (deviceAddress.startsWith(mHostBlacklist[i])) {
@@ -279,7 +279,6 @@
 
     /* returns true if the USB device should not be accessible by applications */
     private boolean isBlackListed(int clazz, int subClass) {
-        Slog.i(TAG, "isBlackListed(" + clazz + ", " + subClass + ")");
         // blacklist hubs
         if (clazz == UsbConstants.USB_CLASS_HUB) return true;
 
@@ -302,6 +301,40 @@
         }
     }
 
+    private void logUsbDevice(UsbDescriptorParser descriptorParser) {
+        int vid = 0;
+        int pid = 0;
+        String mfg = "<unknown>";
+        String product = "<unknown>";
+        String version = "<unknown>";
+        String serial = "<unknown>";
+
+        UsbDeviceDescriptor deviceDescriptor = descriptorParser.getDeviceDescriptor();
+        if (deviceDescriptor != null) {
+            vid = deviceDescriptor.getVendorID();
+            pid = deviceDescriptor.getProductID();
+            mfg = deviceDescriptor.getMfgString(descriptorParser);
+            product = deviceDescriptor.getProductString(descriptorParser);
+            version = deviceDescriptor.getDeviceReleaseString();
+            serial = deviceDescriptor.getSerialString(descriptorParser);
+        }
+
+        if (vid == LINUX_FOUNDATION_VID) {
+            return;  // don't care about OS-constructed virtual USB devices.
+        }
+        boolean hasAudio = descriptorParser.hasAudioInterface();
+        boolean hasHid = descriptorParser.hasHIDInterface();
+        boolean hasStorage = descriptorParser.hasStorageInterface();
+
+        String attachedString = "USB device attached: ";
+        attachedString += String.format("vidpid %04x:%04x", vid, pid);
+        attachedString += String.format(" mfg/product/ver/serial %s/%s/%s/%s",
+                                        mfg, product, version, serial);
+        attachedString += String.format(" hasAudio/HID/Storage: %b/%b/%b",
+                                        hasAudio, hasHid, hasStorage);
+        Slog.d(TAG, attachedString);
+    }
+
     /* Called from JNI in monitorUsbHostBus() to report new USB devices
        Returns true if successful, i.e. the USB Audio device descriptors are
        correctly parsed and the unique device is added to the audio device list.
@@ -313,10 +346,18 @@
             Slog.d(TAG, "usbDeviceAdded(" + deviceAddress + ") - start");
         }
 
-        // check class/subclass first as it is more likely to be blacklisted
-        if (isBlackListed(deviceClass, deviceSubclass) || isBlackListed(deviceAddress)) {
+        if (isBlackListed(deviceAddress)) {
             if (DEBUG) {
-                Slog.d(TAG, "device is black listed");
+                Slog.d(TAG, "device address is black listed");
+            }
+            return false;
+        }
+        UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress, descriptors);
+        logUsbDevice(parser);
+
+        if (isBlackListed(deviceClass, deviceSubclass)) {
+            if (DEBUG) {
+                Slog.d(TAG, "device class is black listed");
             }
             return false;
         }
@@ -329,40 +370,31 @@
                 return false;
             }
 
-            UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress);
-            if (parser.parseDescriptors(descriptors)) {
-
-                UsbDevice newDevice = parser.toAndroidUsbDevice();
-                if (newDevice == null) {
-                    Slog.e(TAG, "Couldn't create UsbDevice object.");
-                    // Tracking
-                    addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT_BADDEVICE,
-                            parser.getRawDescriptors());
-                } else {
-                    mDevices.put(deviceAddress, newDevice);
-
-                    // It is fine to call this only for the current user as all broadcasts are
-                    // sent to all profiles of the user and the dialogs should only show once.
-                    ComponentName usbDeviceConnectionHandler = getUsbDeviceConnectionHandler();
-                    if (usbDeviceConnectionHandler == null) {
-                        getCurrentUserSettings().deviceAttached(newDevice);
-                    } else {
-                        getCurrentUserSettings().deviceAttachedForFixedHandler(newDevice,
-                                usbDeviceConnectionHandler);
-                    }
-
-                    mUsbAlsaManager.usbDeviceAdded(deviceAddress, newDevice, parser);
-
-                    // Tracking
-                    addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT,
-                            parser.getRawDescriptors());
-                }
-            } else {
-                Slog.e(TAG, "Error parsing USB device descriptors for " + deviceAddress);
+            UsbDevice newDevice = parser.toAndroidUsbDevice();
+            if (newDevice == null) {
+                Slog.e(TAG, "Couldn't create UsbDevice object.");
                 // Tracking
-                addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT_BADPARSE,
+                addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT_BADDEVICE,
                         parser.getRawDescriptors());
-                return false;
+            } else {
+                mDevices.put(deviceAddress, newDevice);
+                Slog.d(TAG, "Added device " + newDevice);
+
+                // It is fine to call this only for the current user as all broadcasts are
+                // sent to all profiles of the user and the dialogs should only show once.
+                ComponentName usbDeviceConnectionHandler = getUsbDeviceConnectionHandler();
+                if (usbDeviceConnectionHandler == null) {
+                    getCurrentUserSettings().deviceAttached(newDevice);
+                } else {
+                    getCurrentUserSettings().deviceAttachedForFixedHandler(newDevice,
+                            usbDeviceConnectionHandler);
+                }
+
+                mUsbAlsaManager.usbDeviceAdded(deviceAddress, newDevice, parser);
+
+                // Tracking
+                addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT,
+                        parser.getRawDescriptors());
             }
         }
 
@@ -376,18 +408,18 @@
     /* Called from JNI in monitorUsbHostBus to report USB device removal */
     @SuppressWarnings("unused")
     private void usbDeviceRemoved(String deviceAddress) {
-        if (DEBUG) {
-            Slog.d(TAG, "usbDeviceRemoved(" + deviceAddress + ") - start");
-        }
         synchronized (mLock) {
             UsbDevice device = mDevices.remove(deviceAddress);
             if (device != null) {
+                Slog.d(TAG, "Removed device at " + deviceAddress + ": " + device.getProductName());
                 mUsbAlsaManager.usbDeviceRemoved(deviceAddress/*device*/);
                 mSettingsManager.usbDeviceRemoved(device);
                 getCurrentUserSettings().usbDeviceRemoved(device);
 
                 // Tracking
                 addConnectionRecord(deviceAddress, ConnectionRecord.DISCONNECT, null);
+            } else {
+                Slog.d(TAG, "Removed device at " + deviceAddress + " was already gone");
             }
         }
     }
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index c1a7591..e92bd74 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -304,6 +304,13 @@
         return null;
     }
 
+    /* Returns a dup of the control file descriptor for the given function. */
+    @Override
+    public ParcelFileDescriptor getControlFd(long function) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_MTP, null);
+        return mDeviceManager.getControlFd(function);
+    }
+
     @Override
     public void setDevicePackage(UsbDevice device, String packageName, int userId) {
         device = Preconditions.checkNotNull(device);
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
index 956efc0..e615428 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
@@ -43,11 +43,6 @@
     // Obtained from the first AudioClass Header descriptor.
     private int mACInterfacesSpec = UsbDeviceDescriptor.USBSPEC_1_0;
 
-    public UsbDescriptorParser(String deviceAddr) {
-        mDeviceAddr = deviceAddr;
-        mDescriptors = new ArrayList<UsbDescriptor>(DESCRIPTORS_ALLOC_SIZE);
-    }
-
     /**
      * Connect this parser to an existing set of already parsed descriptors.
      * This is useful for reporting.
@@ -214,7 +209,7 @@
     /**
      * @hide
      */
-    public boolean parseDescriptors(byte[] descriptors) {
+    public void parseDescriptors(byte[] descriptors) {
         if (DEBUG) {
             Log.d(TAG, "parseDescriptors() - start");
         }
@@ -248,17 +243,6 @@
         if (DEBUG) {
             Log.d(TAG, "parseDescriptors() - end " + mDescriptors.size() + " descriptors.");
         }
-        return true;
-    }
-
-    /**
-     * @hide
-     */
-    public boolean parseDevice() {
-        byte[] rawDescriptors = getRawDescriptors();
-
-        return rawDescriptors != null
-            ? parseDescriptors(rawDescriptors) : false;
     }
 
     public byte[] getRawDescriptors() {
@@ -491,9 +475,18 @@
     }
 
     /**
+     *@ hide
+     */
+    public boolean hasAudioInterface() {
+        ArrayList<UsbDescriptor> descriptors =
+                getInterfaceDescriptorsForClass(UsbDescriptor.CLASSID_AUDIO);
+        return !descriptors.isEmpty();
+    }
+
+    /**
      * @hide
      */
-    public boolean hasHIDDescriptor() {
+    public boolean hasHIDInterface() {
         ArrayList<UsbDescriptor> descriptors =
                 getInterfaceDescriptorsForClass(UsbDescriptor.CLASSID_HID);
         return !descriptors.isEmpty();
@@ -502,6 +495,15 @@
     /**
      * @hide
      */
+    public boolean hasStorageInterface() {
+        ArrayList<UsbDescriptor> descriptors =
+                getInterfaceDescriptorsForClass(UsbDescriptor.CLASSID_STORAGE);
+        return !descriptors.isEmpty();
+    }
+
+    /**
+     * @hide
+     */
     public boolean hasMIDIInterface() {
         ArrayList<UsbDescriptor> descriptors =
                 getInterfaceDescriptorsForClass(UsbDescriptor.CLASSID_AUDIO);
@@ -540,7 +542,7 @@
             probability += 0.75f;
         }
 
-        if (hasMic && hasHIDDescriptor()) {
+        if (hasMic && hasHIDInterface()) {
             probability += 0.25f;
         }
 
@@ -593,7 +595,7 @@
             probability += 0.75f;
         }
 
-        if (hasSpeaker && hasHIDDescriptor()) {
+        if (hasSpeaker && hasHIDInterface()) {
             probability += 0.25f;
         }
 
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java
index e31e3a3..fae594a 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java
@@ -48,7 +48,7 @@
     private int mDeviceRelease; // 12:2 Device Release number - BCD
     private byte mMfgIndex;     // 14:1 Index of Manufacturer String Descriptor
     private byte mProductIndex; // 15:1 Index of Product String Descriptor
-    private byte mSerialNum;    // 16:1 Index of Serial Number String Descriptor
+    private byte mSerialIndex;  // 16:1 Index of Serial Number String Descriptor
     private byte mNumConfigs;   // 17:1 Number of Possible Configurations
 
     private ArrayList<UsbConfigDescriptor> mConfigDescriptors =
@@ -91,16 +91,37 @@
         return mDeviceRelease;
     }
 
+    // mDeviceRelease is binary-coded decimal, format DD.DD
+    public String getDeviceReleaseString() {
+        int hundredths = mDeviceRelease & 0xF;
+        int tenths = (mDeviceRelease & 0xF0) >> 4;
+        int ones = (mDeviceRelease & 0xF00) >> 8;
+        int tens = (mDeviceRelease & 0xF000) >> 12;
+        return String.format("%d.%d%d", tens * 10 + ones, tenths, hundredths);
+    }
+
     public byte getMfgIndex() {
         return mMfgIndex;
     }
 
+    public String getMfgString(UsbDescriptorParser p) {
+        return p.getDescriptorString(mMfgIndex);
+    }
+
     public byte getProductIndex() {
         return mProductIndex;
     }
 
-    public byte getSerialNum() {
-        return mSerialNum;
+    public String getProductString(UsbDescriptorParser p) {
+        return p.getDescriptorString(mProductIndex);
+    }
+
+    public byte getSerialIndex() {
+        return mSerialIndex;
+    }
+
+    public String getSerialString(UsbDescriptorParser p) {
+        return p.getDescriptorString(mSerialIndex);
     }
 
     public byte getNumConfigs() {
@@ -119,16 +140,14 @@
             Log.d(TAG, "toAndroid()");
         }
 
-        String mfgName = parser.getDescriptorString(mMfgIndex);
-        String prodName = parser.getDescriptorString(mProductIndex);
+        String mfgName = getMfgString(parser);
+        String prodName = getProductString(parser);
         if (DEBUG) {
             Log.d(TAG, "  mfgName:" + mfgName + " prodName:" + prodName);
         }
 
-        // Create version string in "%.%" format
-        String versionString =
-                Integer.toString(mDeviceRelease >> 8) + "." + (mDeviceRelease & 0xFF);
-        String serialStr = parser.getDescriptorString(mSerialNum);
+        String versionString = getDeviceReleaseString();
+        String serialStr = getSerialString(parser);
         if (DEBUG) {
             Log.d(TAG, "  versionString:" + versionString + " serialStr:" + serialStr);
         }
@@ -159,7 +178,7 @@
         mDeviceRelease = stream.unpackUsbShort();
         mMfgIndex = stream.getByte();
         mProductIndex = stream.getByte();
-        mSerialNum = stream.getByte();
+        mSerialIndex = stream.getByte();
         mNumConfigs = stream.getByte();
 
         return mLength;
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index 08f8bb6..890a6ea 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -18,11 +18,14 @@
 
 import android.annotation.CallSuper;
 import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.TextUtils;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
 
 /**
  * CellIdentity represents the identity of a unique cell. This is the base class for
@@ -84,8 +87,16 @@
     /** @hide */
     protected final String mMncStr;
 
+    // long alpha Operator Name String or Enhanced Operator Name String
     /** @hide */
-    protected CellIdentity(String tag, int type, String mcc, String mnc) {
+    protected final String mAlphaLong;
+    // short alpha Operator Name String or Enhanced Operator Name String
+    /** @hide */
+    protected final String mAlphaShort;
+
+    /** @hide */
+    protected CellIdentity(String tag, int type, String mcc, String mnc, String alphal,
+                           String alphas) {
         mTag = tag;
         mType = type;
 
@@ -113,6 +124,8 @@
             mMncStr = null;
             log("invalid MNC format: " + mnc);
         }
+        mAlphaLong = alphal;
+        mAlphaShort = alphas;
     }
 
     /** Implement the Parcelable interface */
@@ -138,6 +151,40 @@
     }
 
     /**
+     * @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.
+     */
+    @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.
+     */
+    @Nullable
+    public CharSequence getOperatorAlphaShort() {
+        return mAlphaShort;
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof CellIdentity)) {
+            return false;
+        }
+
+        CellIdentity o = (CellIdentity) other;
+        return TextUtils.equals(mAlphaLong, o.mAlphaLong)
+                && TextUtils.equals(mAlphaShort, o.mAlphaShort);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mAlphaLong, mAlphaShort, mMccStr, mMncStr, mType);
+    }
+
+    /**
      * Used by child classes for parceling.
      *
      * @hide
@@ -147,6 +194,8 @@
         dest.writeInt(type);
         dest.writeString(mMccStr);
         dest.writeString(mMncStr);
+        dest.writeString(mAlphaLong);
+        dest.writeString(mAlphaShort);
     }
 
     /**
@@ -154,7 +203,8 @@
      * @hide
      */
     protected CellIdentity(String tag, int type, Parcel source) {
-        this(tag, type, source.readString(), source.readString());
+        this(tag, type, source.readString(), source.readString(),
+                source.readString(), source.readString());
     }
 
     /** Implement the Parcelable interface */
diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java
index 713ac00..58a2c45 100644
--- a/telephony/java/android/telephony/CellIdentityCdma.java
+++ b/telephony/java/android/telephony/CellIdentityCdma.java
@@ -49,23 +49,17 @@
      * to +90 degrees).
      */
     private final int mLatitude;
-    // 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
      */
     public CellIdentityCdma() {
-        super(TAG, TYPE_CDMA, null, null);
+        super(TAG, TYPE_CDMA, null, null, null, null);
         mNetworkId = Integer.MAX_VALUE;
         mSystemId = Integer.MAX_VALUE;
         mBasestationId = Integer.MAX_VALUE;
         mLongitude = Integer.MAX_VALUE;
         mLatitude = Integer.MAX_VALUE;
-        mAlphaLong = null;
-        mAlphaShort = null;
     }
 
     /**
@@ -100,7 +94,7 @@
      */
     public CellIdentityCdma(int nid, int sid, int bid, int lon, int lat, String alphal,
                              String alphas) {
-        super(TAG, TYPE_CDMA, null, null);
+        super(TAG, TYPE_CDMA, null, null, alphal, alphas);
         mNetworkId = nid;
         mSystemId = sid;
         mBasestationId = bid;
@@ -110,8 +104,6 @@
         } else {
             mLongitude = mLatitude = Integer.MAX_VALUE;
         }
-        mAlphaLong = alphal;
-        mAlphaShort = alphas;
     }
 
     private CellIdentityCdma(CellIdentityCdma cid) {
@@ -178,28 +170,10 @@
         return mLatitude;
     }
 
-    /**
-     * @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.
-     */
-    @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.
-     */
-    @Nullable
-    public CharSequence getOperatorAlphaShort() {
-        return mAlphaShort;
-    }
-
     @Override
     public int hashCode() {
         return Objects.hash(mNetworkId, mSystemId, mBasestationId, mLatitude, mLongitude,
-                mAlphaLong, mAlphaShort);
+                super.hashCode());
     }
 
     @Override
@@ -219,8 +193,7 @@
                 && mBasestationId == o.mBasestationId
                 && mLatitude == o.mLatitude
                 && mLongitude == o.mLongitude
-                && TextUtils.equals(mAlphaLong, o.mAlphaLong)
-                && TextUtils.equals(mAlphaShort, o.mAlphaShort);
+                && super.equals(other);
     }
 
     @Override
@@ -246,8 +219,6 @@
         dest.writeInt(mBasestationId);
         dest.writeInt(mLongitude);
         dest.writeInt(mLatitude);
-        dest.writeString(mAlphaLong);
-        dest.writeString(mAlphaShort);
     }
 
     /** Construct from Parcel, type has already been processed */
@@ -258,8 +229,6 @@
         mBasestationId = in.readInt();
         mLongitude = in.readInt();
         mLatitude = in.readInt();
-        mAlphaLong = in.readString();
-        mAlphaShort = in.readString();
 
         if (DBG) log(toString());
     }
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index aae7929..c697880 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -37,22 +37,16 @@
     private final int mArfcn;
     // 6-bit Base Station Identity Code
     private final int mBsic;
-    // 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
      */
     public CellIdentityGsm() {
-        super(TAG, TYPE_GSM, null, null);
+        super(TAG, TYPE_GSM, null, null, null, null);
         mLac = Integer.MAX_VALUE;
         mCid = Integer.MAX_VALUE;
         mArfcn = Integer.MAX_VALUE;
         mBsic = Integer.MAX_VALUE;
-        mAlphaLong = null;
-        mAlphaShort = null;
     }
     /**
      * public constructor
@@ -98,16 +92,13 @@
      */
     public CellIdentityGsm(int lac, int cid, int arfcn, int bsic, String mccStr,
                             String mncStr, String alphal, String alphas) {
-        super(TAG, TYPE_GSM, mccStr, mncStr);
+        super(TAG, TYPE_GSM, mccStr, mncStr, alphal, alphas);
         mLac = lac;
         mCid = cid;
         mArfcn = arfcn;
         // In RIL BSIC is a UINT8, so 0xFF is the 'INVALID' designator
         // for inbound parcels
         mBsic = (bsic == 0xFF) ? Integer.MAX_VALUE : bsic;
-
-        mAlphaLong = alphal;
-        mAlphaShort = alphas;
     }
 
     private CellIdentityGsm(CellIdentityGsm cid) {
@@ -188,24 +179,6 @@
         return mMncStr;
     }
 
-    /**
-     * @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.
-     */
-    @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.
-     */
-    @Nullable
-    public CharSequence getOperatorAlphaShort() {
-        return mAlphaShort;
-    }
-
     /** @hide */
     @Override
     public int getChannelNumber() {
@@ -223,7 +196,7 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(mMccStr, mMncStr, mLac, mCid, mAlphaLong, mAlphaShort);
+        return Objects.hash(mLac, mCid, super.hashCode());
     }
 
     @Override
@@ -243,8 +216,7 @@
                 && mBsic == o.mBsic
                 && TextUtils.equals(mMccStr, o.mMccStr)
                 && TextUtils.equals(mMncStr, o.mMncStr)
-                && TextUtils.equals(mAlphaLong, o.mAlphaLong)
-                && TextUtils.equals(mAlphaShort, o.mAlphaShort);
+                && super.equals(other);
     }
 
     @Override
@@ -270,8 +242,6 @@
         dest.writeInt(mCid);
         dest.writeInt(mArfcn);
         dest.writeInt(mBsic);
-        dest.writeString(mAlphaLong);
-        dest.writeString(mAlphaShort);
     }
 
     /** Construct from Parcel, type has already been processed */
@@ -281,8 +251,6 @@
         mCid = in.readInt();
         mArfcn = in.readInt();
         mBsic = in.readInt();
-        mAlphaLong = in.readString();
-        mAlphaShort = in.readString();
 
         if (DBG) log(toString());
     }
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 9b3ef56..177fced 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -37,10 +37,6 @@
     private final int mTac;
     // 18-bit Absolute RF Channel Number
     private final int mEarfcn;
-    // 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;
     // cell bandwidth, in kHz
     private final int mBandwidth;
 
@@ -48,14 +44,12 @@
      * @hide
      */
     public CellIdentityLte() {
-        super(TAG, TYPE_LTE, null, null);
+        super(TAG, TYPE_LTE, null, null, null, null);
         mCi = Integer.MAX_VALUE;
         mPci = Integer.MAX_VALUE;
         mTac = Integer.MAX_VALUE;
         mEarfcn = Integer.MAX_VALUE;
         mBandwidth = Integer.MAX_VALUE;
-        mAlphaLong = null;
-        mAlphaShort = null;
     }
 
     /**
@@ -105,14 +99,12 @@
      */
     public CellIdentityLte(int ci, int pci, int tac, int earfcn, int bandwidth, String mccStr,
             String mncStr, String alphal, String alphas) {
-        super(TAG, TYPE_LTE, mccStr, mncStr);
+        super(TAG, TYPE_LTE, mccStr, mncStr, alphal, alphas);
         mCi = ci;
         mPci = pci;
         mTac = tac;
         mEarfcn = earfcn;
         mBandwidth = bandwidth;
-        mAlphaLong = alphal;
-        mAlphaShort = alphas;
     }
 
     private CellIdentityLte(CellIdentityLte cid) {
@@ -198,24 +190,6 @@
         return (mMccStr == null || mMncStr == null) ? null : mMccStr + mMncStr;
     }
 
-    /**
-     * @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.
-     */
-    @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.
-     */
-    @Nullable
-    public CharSequence getOperatorAlphaShort() {
-        return mAlphaShort;
-    }
-
     /** @hide */
     @Override
     public int getChannelNumber() {
@@ -224,7 +198,7 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(mMccStr, mMncStr, mCi, mPci, mTac, mAlphaLong, mAlphaShort);
+        return Objects.hash(mCi, mPci, mTac, super.hashCode());
     }
 
     @Override
@@ -245,8 +219,7 @@
                 && mBandwidth == o.mBandwidth
                 && TextUtils.equals(mMccStr, o.mMccStr)
                 && TextUtils.equals(mMncStr, o.mMncStr)
-                && TextUtils.equals(mAlphaLong, o.mAlphaLong)
-                && TextUtils.equals(mAlphaShort, o.mAlphaShort);
+                && super.equals(other);
     }
 
     @Override
@@ -274,8 +247,6 @@
         dest.writeInt(mTac);
         dest.writeInt(mEarfcn);
         dest.writeInt(mBandwidth);
-        dest.writeString(mAlphaLong);
-        dest.writeString(mAlphaShort);
     }
 
     /** Construct from Parcel, type has already been processed */
@@ -286,8 +257,6 @@
         mTac = in.readInt();
         mEarfcn = in.readInt();
         mBandwidth = in.readInt();
-        mAlphaLong = in.readString();
-        mAlphaShort = in.readString();
 
         if (DBG) log(toString());
     }
diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java
index 7475c74..18ab6d4 100644
--- a/telephony/java/android/telephony/CellIdentityTdscdma.java
+++ b/telephony/java/android/telephony/CellIdentityTdscdma.java
@@ -35,21 +35,15 @@
     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
      */
     public CellIdentityTdscdma() {
-        super(TAG, TYPE_TDSCDMA, null, null);
+        super(TAG, TYPE_TDSCDMA, null, null, null, null);
         mLac = Integer.MAX_VALUE;
         mCid = Integer.MAX_VALUE;
         mCpid = Integer.MAX_VALUE;
-        mAlphaLong = null;
-        mAlphaShort = null;
     }
 
     /**
@@ -76,12 +70,10 @@
      * @hide
      */
     public CellIdentityTdscdma(String mcc, String mnc, int lac, int cid, int cpid) {
-        super(TAG, TYPE_TDSCDMA, mcc, mnc);
+        super(TAG, TYPE_TDSCDMA, mcc, mnc, null, null);
         mLac = lac;
         mCid = cid;
         mCpid = cpid;
-        mAlphaLong = null;
-        mAlphaShort = null;
     }
 
     /**
@@ -97,12 +89,10 @@
      */
     public CellIdentityTdscdma(String mcc, String mnc, int lac, int cid, int cpid,
             String alphal, String alphas) {
-        super(TAG, TYPE_TDSCDMA, mcc, mnc);
+        super(TAG, TYPE_TDSCDMA, mcc, mnc, alphal, alphas);
         mLac = lac;
         mCid = cid;
         mCpid = cpid;
-        mAlphaLong = alphal;
-        mAlphaShort = alphas;
     }
 
     private CellIdentityTdscdma(CellIdentityTdscdma cid) {
@@ -151,31 +141,9 @@
         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, mAlphaLong, mAlphaShort);
+        return Objects.hash(mLac, mCid, mCpid, super.hashCode());
     }
 
     @Override
@@ -194,8 +162,7 @@
                 && mLac == o.mLac
                 && mCid == o.mCid
                 && mCpid == o.mCpid
-                && mAlphaLong == o.mAlphaLong
-                && mAlphaShort == o.mAlphaShort;
+                && super.equals(other);
     }
 
     @Override
@@ -219,8 +186,6 @@
         dest.writeInt(mLac);
         dest.writeInt(mCid);
         dest.writeInt(mCpid);
-        dest.writeString(mAlphaLong);
-        dest.writeString(mAlphaShort);
     }
 
     /** Construct from Parcel, type has already been processed */
@@ -229,8 +194,6 @@
         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/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
index 52fa54f..984483e 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -37,22 +37,16 @@
     private final int mPsc;
     // 16-bit UMTS Absolute RF Channel Number
     private final int mUarfcn;
-    // 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
      */
     public CellIdentityWcdma() {
-        super(TAG, TYPE_TDSCDMA, null, null);
+        super(TAG, TYPE_TDSCDMA, null, null, null, null);
         mLac = Integer.MAX_VALUE;
         mCid = Integer.MAX_VALUE;
         mPsc = Integer.MAX_VALUE;
         mUarfcn = Integer.MAX_VALUE;
-        mAlphaLong = null;
-        mAlphaShort = null;
     }
     /**
      * public constructor
@@ -99,13 +93,11 @@
      */
     public CellIdentityWcdma (int lac, int cid, int psc, int uarfcn,
                               String mccStr, String mncStr, String alphal, String alphas) {
-        super(TAG, TYPE_WCDMA, mccStr, mncStr);
+        super(TAG, TYPE_WCDMA, mccStr, mncStr, alphal, alphas);
         mLac = lac;
         mCid = cid;
         mPsc = psc;
         mUarfcn = uarfcn;
-        mAlphaLong = alphal;
-        mAlphaShort = alphas;
     }
 
     private CellIdentityWcdma(CellIdentityWcdma cid) {
@@ -179,27 +171,9 @@
         return (mMccStr == null || mMncStr == null) ? null : mMccStr + mMncStr;
     }
 
-    /**
-     * @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.
-     */
-    @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.
-     */
-    @Nullable
-    public CharSequence getOperatorAlphaShort() {
-        return mAlphaShort;
-    }
-
     @Override
     public int hashCode() {
-        return Objects.hash(mMccStr, mMncStr, mLac, mCid, mPsc, mAlphaLong, mAlphaShort);
+        return Objects.hash(mLac, mCid, mPsc, super.hashCode());
     }
 
     /**
@@ -232,8 +206,7 @@
                 && mUarfcn == o.mUarfcn
                 && TextUtils.equals(mMccStr, o.mMccStr)
                 && TextUtils.equals(mMncStr, o.mMncStr)
-                && TextUtils.equals(mAlphaLong, o.mAlphaLong)
-                && TextUtils.equals(mAlphaShort, o.mAlphaShort);
+                && super.equals(other);
     }
 
     @Override
@@ -259,8 +232,6 @@
         dest.writeInt(mCid);
         dest.writeInt(mPsc);
         dest.writeInt(mUarfcn);
-        dest.writeString(mAlphaLong);
-        dest.writeString(mAlphaShort);
     }
 
     /** Construct from Parcel, type has already been processed */
@@ -270,8 +241,6 @@
         mCid = in.readInt();
         mPsc = in.readInt();
         mUarfcn = in.readInt();
-        mAlphaLong = in.readString();
-        mAlphaShort = in.readString();
         if (DBG) log(toString());
     }
 
diff --git a/telephony/java/android/telephony/LocationAccessPolicy.java b/telephony/java/android/telephony/LocationAccessPolicy.java
index 26ffe32..6480aab 100644
--- a/telephony/java/android/telephony/LocationAccessPolicy.java
+++ b/telephony/java/android/telephony/LocationAccessPolicy.java
@@ -21,31 +21,25 @@
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.location.LocationManager;
 import android.os.Binder;
-import android.os.Build;
 import android.os.Process;
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.provider.Settings;
-import android.util.SparseBooleanArray;
+import android.util.Log;
 
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 /**
  * Helper for performing location access checks.
  * @hide
  */
 public final class LocationAccessPolicy {
+    private static final String LOG_TAG = LocationAccessPolicy.class.getSimpleName();
     /**
      * API to determine if the caller has permissions to get cell location.
      *
@@ -94,10 +88,12 @@
     }
 
     private static boolean isLocationModeEnabled(@NonNull Context context, @UserIdInt int userId) {
-        int locationMode = Settings.Secure.getIntForUser(context.getContentResolver(),
-                Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF, userId);
-        return locationMode != Settings.Secure.LOCATION_MODE_OFF
-                && locationMode != Settings.Secure.LOCATION_MODE_SENSORS_ONLY;
+        LocationManager locationManager = context.getSystemService(LocationManager.class);
+        if (locationManager == null) {
+            Log.w(LOG_TAG, "Couldn't get location manager, denying location access");
+            return false;
+        }
+        return locationManager.isLocationEnabledForUser(UserHandle.of(userId));
     }
 
     private static boolean checkInteractAcrossUsersFull(@NonNull Context context) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index c5386ef..a12a7a0 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -40,6 +40,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.PersistableBundle;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
@@ -214,6 +215,10 @@
         return ActivityThread.currentOpPackageName();
     }
 
+    private boolean isSystemProcess() {
+        return Process.myUid() == Process.SYSTEM_UID;
+    }
+
     /**
      * Returns the multi SIM variant
      * Returns DSDS for Dual SIM Dual Standby
@@ -2866,15 +2871,18 @@
             IPhoneSubInfo info = getSubscriberInfo();
             if (info == null) {
                 Rlog.e(TAG, "IMSI error: Subscriber Info is null");
+                if (!isSystemProcess()) {
+                    throw new RuntimeException("IMSI error: Subscriber Info is null");
+                }
                 return;
             }
             int subId = getSubId(SubscriptionManager.getDefaultDataSubscriptionId());
             info.resetCarrierKeysForImsiEncryption(subId, mContext.getOpPackageName());
         } catch (RemoteException ex) {
             Rlog.e(TAG, "getCarrierInfoForImsiEncryption RemoteException" + ex);
-        } catch (NullPointerException ex) {
-            // This could happen before phone restarts due to crashing
-            Rlog.e(TAG, "getCarrierInfoForImsiEncryption NullPointerException" + ex);
+            if (!isSystemProcess()) {
+                ex.rethrowAsRuntimeException();
+            }
         }
     }
 
@@ -3863,11 +3871,18 @@
     public void sendDialerSpecialCode(String inputCode) {
         try {
             final ITelephony telephony = getITelephony();
+            if (telephony == null) {
+                if (!isSystemProcess()) {
+                    throw new RuntimeException("Telephony service unavailable");
+                }
+                return;
+            }
             telephony.sendDialerSpecialCode(mContext.getOpPackageName(), inputCode);
         } catch (RemoteException ex) {
             // This could happen if binder process crashes.
-        } catch (NullPointerException ex) {
-            // This could happen before phone restarts due to crashing
+            if (!isSystemProcess()) {
+                ex.rethrowAsRuntimeException();
+            }
         }
     }
 
@@ -7836,6 +7851,9 @@
             }
         } catch (RemoteException ex) {
             // This could happen if binder process crashes.
+            if (!isSystemProcess()) {
+                ex.rethrowAsRuntimeException();
+            }
         }
     }
 }
diff --git a/tests/UsbTests/res/raw/usbdescriptors_massstorage.bin b/tests/UsbTests/res/raw/usbdescriptors_massstorage.bin
new file mode 100644
index 0000000..1790369
--- /dev/null
+++ b/tests/UsbTests/res/raw/usbdescriptors_massstorage.bin
Binary files differ
diff --git a/tests/UsbTests/src/com/android/server/usb/UsbDescriptorParserTests.java b/tests/UsbTests/src/com/android/server/usb/UsbDescriptorParserTests.java
index f323952..ea027d7 100644
--- a/tests/UsbTests/src/com/android/server/usb/UsbDescriptorParserTests.java
+++ b/tests/UsbTests/src/com/android/server/usb/UsbDescriptorParserTests.java
@@ -18,6 +18,7 @@
 
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
 import android.content.Context;
@@ -28,6 +29,7 @@
 import android.support.test.runner.AndroidJUnit4;
 
 import com.android.server.usb.descriptors.UsbDescriptorParser;
+import com.android.server.usb.descriptors.UsbDeviceDescriptor;
 import com.google.common.io.ByteStreams;
 
 import java.io.InputStream;
@@ -61,14 +63,24 @@
         }
 
         // Testing same codepath as UsbHostManager.java:usbDeviceAdded
-        UsbDescriptorParser parser = new UsbDescriptorParser("test-usb-addr");
-        if (!parser.parseDescriptors(descriptors)) {
-            fail("failed to parse descriptors.");
-        }
+        UsbDescriptorParser parser = new UsbDescriptorParser("test-usb-addr", descriptors);
         return parser;
     }
 
-    // A Headset has a microphone and a speaker and is a headset.
+    /** A Headset has a microphone and a speaker and is a headset.
+     * Descriptors for this example show up on lsusb -v with:
+     *   bcdDevice           22.80
+     * and a UAC1 audio device with the following control interface:
+     *       bInterfaceClass         1 Audio
+     * ...
+     *       bDescriptorSubtype      2 (INPUT_TERMINAL)
+     *       bTerminalID             1
+     *       wTerminalType      0x0201 Microphone
+     * ...
+     *       bDescriptorSubtype      3 (OUTPUT_TERMINAL)
+     *       bTerminalID            15
+     *       wTerminalType      0x0302 Headphones
+     */
     @Test
     @SmallTest
     public void testHeadsetDescriptorParser() {
@@ -77,9 +89,24 @@
         assertTrue(parser.hasOutput());
         assertTrue(parser.isInputHeadset());
         assertTrue(parser.isOutputHeadset());
+
+        assertTrue(parser.hasAudioInterface());
+        assertTrue(parser.hasHIDInterface());
+        assertFalse(parser.hasStorageInterface());
+
+        assertEquals(parser.getDeviceDescriptor().getDeviceReleaseString(), "22.80");
     }
 
-    // Headphones have no microphones but are considered a headset.
+    /** Headphones have no microphones but are considered a headset.
+     * Descriptors for this example show up on lsusb -v with:
+     *   bcdDevice           22.80
+     * and a UAC1 audio device with the following control interface:
+     *       bInterfaceClass         1 Audio
+     * ...
+     *       bDescriptorSubtype      3 (OUTPUT_TERMINAL)
+     *       bTerminalID            15
+     *       wTerminalType      0x0302 Headphones
+     */
     @Test
     @SmallTest
     public void testHeadphoneDescriptorParser() {
@@ -88,9 +115,24 @@
         assertTrue(parser.hasOutput());
         assertFalse(parser.isInputHeadset());
         assertTrue(parser.isOutputHeadset());
+
+        assertTrue(parser.hasAudioInterface());
+        assertTrue(parser.hasHIDInterface());
+        assertFalse(parser.hasStorageInterface());
+
+        assertEquals(parser.getDeviceDescriptor().getDeviceReleaseString(), "22.80");
     }
 
-    // Line out has no microphones and aren't considered a headset.
+    /** Line out with no microphones aren't considered a headset.
+     * Descriptors for this example show up on lsusb -v with:
+     *     bcdDevice           22.80
+     * and the following UAC1 audio control interface
+     *  bInterfaceClass         1 Audio
+     *  ...
+     *   bDescriptorSubtype      3 (OUTPUT_TERMINAL)
+     *   bTerminalID            15
+     *   wTerminalType      0x0603 Line Connector
+     */
     @Test
     @SmallTest
     public void testLineoutDescriptorParser() {
@@ -99,9 +141,20 @@
         assertTrue(parser.hasOutput());
         assertFalse(parser.isInputHeadset());
         assertFalse(parser.isOutputHeadset());
+
+        assertTrue(parser.hasAudioInterface());
+        assertTrue(parser.hasHIDInterface());
+        assertFalse(parser.hasStorageInterface());
+
+        assertEquals(parser.getDeviceDescriptor().getDeviceReleaseString(), "22.80");
     }
 
-    // An HID-only device shouldn't be considered anything at all.
+    /** An HID-only device shouldn't be considered anything at all.
+    /* Descriptors show up on lsusb -v with:
+     *   bcdDevice           22.80
+     * and a single HID interface,
+     *   bInterfaceClass         3 Human Interface Device
+     */
     @Test
     @SmallTest
     public void testNothingDescriptorParser() {
@@ -110,6 +163,34 @@
         assertFalse(parser.hasOutput());
         assertFalse(parser.isInputHeadset());
         assertFalse(parser.isOutputHeadset());
+
+        assertFalse(parser.hasAudioInterface());
+        assertTrue(parser.hasHIDInterface());
+        assertFalse(parser.hasStorageInterface());
+
+        assertEquals(parser.getDeviceDescriptor().getDeviceReleaseString(), "22.80");
+    }
+
+    /** A USB mass-storage device.
+     * Shows up on lsusb -v with:
+     *    bcdDevice            2.08
+     * and a single interface descriptor,
+     *    bInterfaceClass         8 Mass Storage
+     */
+    @Test
+    @SmallTest
+    public void testMassStorageDescriptorParser() {
+        UsbDescriptorParser parser = loadParser(R.raw.usbdescriptors_massstorage);
+        assertFalse(parser.hasInput());
+        assertFalse(parser.hasOutput());
+        assertFalse(parser.isInputHeadset());
+        assertFalse(parser.isOutputHeadset());
+
+        assertFalse(parser.hasAudioInterface());
+        assertFalse(parser.hasHIDInterface());
+        assertTrue(parser.hasStorageInterface());
+
+        assertEquals(parser.getDeviceDescriptor().getDeviceReleaseString(), "2.08");
     }
 
 }
diff --git a/tools/stringslint/stringslint.py b/tools/stringslint/stringslint.py
new file mode 100644
index 0000000..d637ff3
--- /dev/null
+++ b/tools/stringslint/stringslint.py
@@ -0,0 +1,162 @@
+#!/usr/bin/env python
+
+# 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.
+
+"""
+Enforces common Android string best-practices.  It ignores lint messages from
+a previous strings file, if provided.
+
+Usage: stringslint.py strings.xml
+Usage: stringslint.py strings.xml old_strings.xml
+"""
+
+import re, sys
+import lxml.etree as ET
+
+BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
+
+def format(fg=None, bg=None, bright=False, bold=False, dim=False, reset=False):
+    # manually derived from http://en.wikipedia.org/wiki/ANSI_escape_code#Codes
+    codes = []
+    if reset: codes.append("0")
+    else:
+        if not fg is None: codes.append("3%d" % (fg))
+        if not bg is None:
+            if not bright: codes.append("4%d" % (bg))
+            else: codes.append("10%d" % (bg))
+        if bold: codes.append("1")
+        elif dim: codes.append("2")
+        else: codes.append("22")
+    return "\033[%sm" % (";".join(codes))
+
+warnings = None
+
+def warn(tag, msg, actual, expected):
+    global warnings
+    key = "%s:%d" % (tag.attrib["name"], hash(msg))
+    value = "%sLine %d: '%s':%s %s" % (format(fg=YELLOW, bold=True),
+                                       tag.sourceline,
+                                       tag.attrib["name"],
+                                       format(reset=True),
+                                       msg)
+    if not actual is None: value += "\n\tActual: %s%s%s" % (format(dim=True),
+                                                            actual,
+                                                            format(reset=True))
+    if not expected is None: value += "\n\tExample: %s%s%s" % (format(dim=True),
+                                                               expected,
+                                                               format(reset=True))
+    warnings[key] = value
+
+def lint(path):
+    global warnings
+    warnings = {}
+
+    with open(path) as f:
+        raw = f.read()
+        if len(raw.strip()) == 0:
+            return warnings
+        tree = ET.fromstring(raw)
+        root = tree #tree.getroot()
+
+    last_comment = None
+    for child in root:
+        # TODO: handle plurals
+        if isinstance(child, ET._Comment):
+            last_comment = child
+        elif child.tag == "string":
+            # We always consume comment
+            comment = last_comment
+            last_comment = None
+
+            # Validate comment
+            if comment is None:
+                warn(child, "Missing string comment to aid translation",
+                     None, None)
+                continue
+            if "do not translate" in comment.text.lower():
+                continue
+            if "translatable" in child.attrib and child.attrib["translatable"].lower() == "false":
+                continue
+            if re.search("CHAR[ _-]LIMIT=(\d+|NONE|none)", comment.text) is None:
+                warn(child, "Missing CHAR LIMIT to aid translation",
+                     repr(comment), "<!-- Description of string [CHAR LIMIT=32] -->")
+
+            # Look for common mistakes/substitutions
+            text = "".join(child.itertext()).strip()
+            if "'" in text:
+                warn(child, "Turned quotation mark glyphs are more polished",
+                     text, "This doesn\u2019t need to \u2018happen\u2019 today")
+            if '"' in text and not text.startswith('"') and text.endswith('"'):
+                warn(child, "Turned quotation mark glyphs are more polished",
+                     text, "This needs to \u201chappen\u201d today")
+            if "..." in text:
+                warn(child, "Ellipsis glyph is more polished",
+                     text, "Loading\u2026")
+            if "wi-fi" in text.lower():
+                warn(child, "Non-breaking glyph is more polished",
+                     text, "Wi\u2011Fi")
+            if "wifi" in text.lower():
+                warn(child, "Using non-standard spelling",
+                     text, "Wi\u2011Fi")
+            if re.search("\d-\d", text):
+                warn(child, "Ranges should use en dash glyph",
+                     text, "You will find this material in chapters 8\u201312")
+            if "--" in text:
+                warn(child, "Phrases should use em dash glyph",
+                     text, "Upon discovering errors\u2014all 124 of them\u2014they recalled.")
+            if ".  " in text:
+                warn(child, "Only use single space between sentences",
+                     text, "First idea. Second idea.")
+
+            # When more than one substitution, require indexes
+            if len(re.findall("%[^%]", text)) > 1:
+                if len(re.findall("%[^\d]", text)) > 0:
+                    warn(child, "Substitutions must be indexed",
+                         text, "Add %1$s to %2$s")
+
+            # Require xliff substitutions
+            for gc in child.iter():
+                badsub = False
+                if gc.tail and re.search("%[^%]", gc.tail): badsub = True
+                if re.match("{.*xliff.*}g", gc.tag):
+                    if "id" not in gc.attrib:
+                        warn(child, "Substitutions must define id attribute",
+                             None, "<xliff:g id=\"domain\" example=\"example.com\">%1$s</xliff:g>")
+                    if "example" not in gc.attrib:
+                        warn(child, "Substitutions must define example attribute",
+                             None, "<xliff:g id=\"domain\" example=\"example.com\">%1$s</xliff:g>")
+                else:
+                    if gc.text and re.search("%[^%]", gc.text): badsub = True
+                if badsub:
+                    warn(child, "Substitutions must be inside xliff tags",
+                         text, "<xliff:g id=\"domain\" example=\"example.com\">%1$s</xliff:g>")
+
+    return warnings
+
+if len(sys.argv) > 2:
+    before = lint(sys.argv[2])
+else:
+    before = {}
+after = lint(sys.argv[1])
+
+for b in before:
+    if b in after:
+        del after[b]
+
+if len(after) > 0:
+    for a in sorted(after.keys()):
+        print after[a]
+        print
+    sys.exit(1)
diff --git a/tools/stringslint/stringslint_sha.sh b/tools/stringslint/stringslint_sha.sh
new file mode 100755
index 0000000..c79ba04
--- /dev/null
+++ b/tools/stringslint/stringslint_sha.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+git show --name-only --pretty=format: $1 | grep values/strings.xml | while read file; do
+    python $ANDROID_BUILD_TOP/frameworks/base/tools/stringslint/stringslint.py <(git show $1:$file) <(git show $1^:$file)
+done