Merge "Import translations. DO NOT MERGE" into pi-dev
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index 133f33b..49de1ac 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -31,9 +31,8 @@
 namespace os {
 namespace statsd {
 
-// TODO: Get rid of bucketNumbers, and return to the original circular array method.
 AnomalyTracker::AnomalyTracker(const Alert& alert, const ConfigKey& configKey)
-    : mAlert(alert), mConfigKey(configKey), mNumOfPastBuckets(mAlert.num_buckets() - 1) {
+        : mAlert(alert), mConfigKey(configKey), mNumOfPastBuckets(mAlert.num_buckets() - 1) {
     VLOG("AnomalyTracker() called");
     if (mAlert.num_buckets() <= 0) {
         ALOGE("Cannot create AnomalyTracker with %lld buckets", (long long)mAlert.num_buckets());
@@ -60,85 +59,102 @@
 
 size_t AnomalyTracker::index(int64_t bucketNum) const {
     if (bucketNum < 0) {
-        // To support this use-case, we can easily modify index to wrap around. But currently
-        // AnomalyTracker should never need this, so if it happens, it's a bug we should log.
-        // TODO: Audit this.
         ALOGE("index() was passed a negative bucket number (%lld)!", (long long)bucketNum);
     }
     return bucketNum % mNumOfPastBuckets;
 }
 
-void AnomalyTracker::flushPastBuckets(const int64_t& latestPastBucketNum) {
-    VLOG("addPastBucket() called.");
-    if (latestPastBucketNum <= mMostRecentBucketNum - mNumOfPastBuckets) {
-        ALOGE("Cannot add a past bucket %lld units in past", (long long)latestPastBucketNum);
+void AnomalyTracker::advanceMostRecentBucketTo(const int64_t& bucketNum) {
+    VLOG("advanceMostRecentBucketTo() called.");
+    if (bucketNum <= mMostRecentBucketNum) {
+        ALOGW("Cannot advance buckets backwards (bucketNum=%lld but mMostRecentBucketNum=%lld)",
+              (long long)bucketNum, (long long)mMostRecentBucketNum);
         return;
     }
-
-    // The past packets are ancient. Empty out old mPastBuckets[i] values and reset
-    // mSumOverPastBuckets.
-    if (latestPastBucketNum - mMostRecentBucketNum >= mNumOfPastBuckets) {
+    // If in the future (i.e. buckets are ancient), just empty out all past info.
+    if (bucketNum >= mMostRecentBucketNum + mNumOfPastBuckets) {
         resetStorage();
-    } else {
-        for (int64_t i = std::max(0LL, (long long)(mMostRecentBucketNum - mNumOfPastBuckets + 1));
-             i <= latestPastBucketNum - mNumOfPastBuckets; i++) {
-            const int idx = index(i);
-            subtractBucketFromSum(mPastBuckets[idx]);
-            mPastBuckets[idx] = nullptr;  // release (but not clear) the old bucket.
+        mMostRecentBucketNum = bucketNum;
+        return;
+    }
+
+    // Clear out space by emptying out old mPastBuckets[i] values and update mSumOverPastBuckets.
+    for (int64_t i = mMostRecentBucketNum + 1; i <= bucketNum; i++) {
+        const int idx = index(i);
+        subtractBucketFromSum(mPastBuckets[idx]);
+        mPastBuckets[idx] = nullptr;  // release (but not clear) the old bucket.
+    }
+    mMostRecentBucketNum = bucketNum;
+}
+
+void AnomalyTracker::addPastBucket(const MetricDimensionKey& key,
+                                   const int64_t& bucketValue,
+                                   const int64_t& bucketNum) {
+    VLOG("addPastBucket(bucketValue) called.");
+    if (mNumOfPastBuckets == 0 ||
+        bucketNum < 0 || bucketNum <= mMostRecentBucketNum - mNumOfPastBuckets) {
+        return;
+    }
+
+    const int bucketIndex = index(bucketNum);
+    if (bucketNum <= mMostRecentBucketNum && (mPastBuckets[bucketIndex] != nullptr)) {
+        // We need to insert into an already existing past bucket.
+        std::shared_ptr<DimToValMap>& bucket = mPastBuckets[bucketIndex];
+        auto itr = bucket->find(key);
+        if (itr != bucket->end()) {
+            // Old entry already exists; update it.
+            subtractValueFromSum(key, itr->second);
+            itr->second = bucketValue;
+        } else {
+            bucket->insert({key, bucketValue});
         }
-    }
-
-    // It is an update operation.
-    if (latestPastBucketNum <= mMostRecentBucketNum &&
-        latestPastBucketNum > mMostRecentBucketNum - mNumOfPastBuckets) {
-        subtractBucketFromSum(mPastBuckets[index(latestPastBucketNum)]);
+        mSumOverPastBuckets[key] += bucketValue;
+    } else {
+        // Bucket does not exist yet (in future or was never made), so we must make it.
+        std::shared_ptr<DimToValMap> bucket = std::make_shared<DimToValMap>();
+        bucket->insert({key, bucketValue});
+        addPastBucket(bucket, bucketNum);
     }
 }
 
-void AnomalyTracker::addPastBucket(const MetricDimensionKey& key, const int64_t& bucketValue,
+void AnomalyTracker::addPastBucket(std::shared_ptr<DimToValMap> bucket,
                                    const int64_t& bucketNum) {
-    if (mNumOfPastBuckets == 0) {
+    VLOG("addPastBucket(bucket) called.");
+    if (mNumOfPastBuckets == 0 ||
+            bucketNum < 0 || bucketNum <= mMostRecentBucketNum - mNumOfPastBuckets) {
         return;
     }
-    flushPastBuckets(bucketNum);
 
-    auto& bucket = mPastBuckets[index(bucketNum)];
-    if (bucket == nullptr) {
-        bucket = std::make_shared<DimToValMap>();
+    if (bucketNum <= mMostRecentBucketNum) {
+        // We are updating an old bucket, not adding a new one.
+        subtractBucketFromSum(mPastBuckets[index(bucketNum)]);
+    } else {
+        // Clear space for the new bucket to be at bucketNum.
+        advanceMostRecentBucketTo(bucketNum);
     }
-    bucket->insert({key, bucketValue});
+    mPastBuckets[index(bucketNum)] = bucket;
     addBucketToSum(bucket);
-    mMostRecentBucketNum = std::max(mMostRecentBucketNum, bucketNum);
-}
-
-void AnomalyTracker::addPastBucket(std::shared_ptr<DimToValMap> bucketValues,
-                                   const int64_t& bucketNum) {
-    VLOG("addPastBucket() called.");
-    if (mNumOfPastBuckets == 0) {
-        return;
-    }
-    flushPastBuckets(bucketNum);
-    // Replace the oldest bucket with the new bucket we are adding.
-    mPastBuckets[index(bucketNum)] = bucketValues;
-    addBucketToSum(bucketValues);
-    mMostRecentBucketNum = std::max(mMostRecentBucketNum, bucketNum);
 }
 
 void AnomalyTracker::subtractBucketFromSum(const shared_ptr<DimToValMap>& bucket) {
     if (bucket == nullptr) {
         return;
     }
-    // For each dimension present in the bucket, subtract its value from its corresponding sum.
     for (const auto& keyValuePair : *bucket) {
-        auto itr = mSumOverPastBuckets.find(keyValuePair.first);
-        if (itr == mSumOverPastBuckets.end()) {
-            continue;
-        }
-        itr->second -= keyValuePair.second;
-        // TODO: No need to look up the object twice like this. Use a var.
-        if (itr->second == 0) {
-            mSumOverPastBuckets.erase(itr);
-        }
+        subtractValueFromSum(keyValuePair.first, keyValuePair.second);
+    }
+}
+
+
+void AnomalyTracker::subtractValueFromSum(const MetricDimensionKey& key,
+                                          const int64_t& bucketValue) {
+    auto itr = mSumOverPastBuckets.find(key);
+    if (itr == mSumOverPastBuckets.end()) {
+        return;
+    }
+    itr->second -= bucketValue;
+    if (itr->second == 0) {
+        mSumOverPastBuckets.erase(itr);
     }
 }
 
@@ -154,7 +170,8 @@
 
 int64_t AnomalyTracker::getPastBucketValue(const MetricDimensionKey& key,
                                            const int64_t& bucketNum) const {
-    if (mNumOfPastBuckets == 0 || bucketNum < 0) {
+    if (bucketNum < 0 || bucketNum <= mMostRecentBucketNum - mNumOfPastBuckets
+            || bucketNum > mMostRecentBucketNum) {
         return 0;
     }
 
@@ -174,11 +191,13 @@
     return 0;
 }
 
-bool AnomalyTracker::detectAnomaly(const int64_t& currentBucketNum, const MetricDimensionKey& key,
+bool AnomalyTracker::detectAnomaly(const int64_t& currentBucketNum,
+                                   const MetricDimensionKey& key,
                                    const int64_t& currentBucketValue) {
+
+    // currentBucketNum should be the next bucket after pastBuckets. If not, advance so that it is.
     if (currentBucketNum > mMostRecentBucketNum + 1) {
-        // TODO: This creates a needless 0 entry in mSumOverPastBuckets. Fix this.
-        addPastBucket(key, 0, currentBucketNum - 1);
+        advanceMostRecentBucketTo(currentBucketNum - 1);
     }
     return mAlert.has_trigger_if_sum_gt() &&
            getSumOverPastBuckets(key) + currentBucketValue > mAlert.trigger_if_sum_gt();
@@ -190,19 +209,17 @@
         VLOG("Skipping anomaly declaration since within refractory period");
         return;
     }
-    mRefractoryPeriodEndsSec[key] = (timestampNs / NS_PER_SEC) + mAlert.refractory_period_secs();
-
-    // TODO: If we had access to the bucket_size_millis, consider calling resetStorage()
-    // if (mAlert.refractory_period_secs() > mNumOfPastBuckets * bucketSizeNs) { resetStorage(); }
+    if (mAlert.has_refractory_period_secs()) {
+        mRefractoryPeriodEndsSec[key] = ((timestampNs + NS_PER_SEC - 1) / NS_PER_SEC) // round up
+                                        + mAlert.refractory_period_secs();
+        // TODO: If we had access to the bucket_size_millis, consider calling resetStorage()
+        // if (mAlert.refractory_period_secs() > mNumOfPastBuckets * bucketSizeNs) {resetStorage();}
+    }
 
     if (!mSubscriptions.empty()) {
-        if (mAlert.has_id()) {
-            ALOGI("An anomaly (%lld) %s has occurred! Informing subscribers.", mAlert.id(),
-                  key.toString().c_str());
-            informSubscribers(key);
-        } else {
-            ALOGI("An anomaly (with no id) has occurred! Not informing any subscribers.");
-        }
+        ALOGI("An anomaly (%lld) %s has occurred! Informing subscribers.",
+                mAlert.id(), key.toString().c_str());
+        informSubscribers(key);
     } else {
         ALOGI("An anomaly has occurred! (But no subscriber for that alert.)");
     }
@@ -227,7 +244,7 @@
                                           const MetricDimensionKey& key) {
     const auto& it = mRefractoryPeriodEndsSec.find(key);
     if (it != mRefractoryPeriodEndsSec.end()) {
-        if ((timestampNs / NS_PER_SEC) <= it->second) {
+        if (timestampNs < it->second * NS_PER_SEC) {
             return true;
         } else {
             mRefractoryPeriodEndsSec.erase(key);
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.h b/cmds/statsd/src/anomaly/AnomalyTracker.h
index d27dee8..d3da7dc 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.h
@@ -47,20 +47,32 @@
         mSubscriptions.push_back(subscription);
     }
 
-    // Adds a bucket.
-    // Bucket index starts from 0.
-    void addPastBucket(std::shared_ptr<DimToValMap> bucketValues, const int64_t& bucketNum);
+    // Adds a bucket for the given bucketNum (index starting at 0).
+    // If a bucket for bucketNum already exists, it will be replaced.
+    // Also, advances to bucketNum (if not in the past), effectively filling any intervening
+    // buckets with 0s.
+    void addPastBucket(std::shared_ptr<DimToValMap> bucket, const int64_t& bucketNum);
+
+    // Inserts (or replaces) the bucket entry for the given bucketNum at the given key to be the
+    // given bucketValue. If the bucket does not exist, it will be created.
+    // Also, advances to bucketNum (if not in the past), effectively filling any intervening
+    // buckets with 0s.
     void addPastBucket(const MetricDimensionKey& key, const int64_t& bucketValue,
                        const int64_t& bucketNum);
 
-    // Returns true if detected anomaly for the existing buckets on one or more dimension keys.
+    // Returns true if, based on past buckets plus the new currentBucketValue (which generally
+    // represents the partially-filled current bucket), an anomaly has happened.
+    // Also advances to currBucketNum-1.
     bool detectAnomaly(const int64_t& currBucketNum, const MetricDimensionKey& key,
                        const int64_t& currentBucketValue);
 
     // Informs incidentd about the detected alert.
     void declareAnomaly(const uint64_t& timestampNs, const MetricDimensionKey& key);
 
-    // Detects the alert and informs the incidentd when applicable.
+    // Detects if, based on past buckets plus the new currentBucketValue (which generally
+    // represents the partially-filled current bucket), an anomaly has happened, and if so,
+    // declares an anomaly and informs relevant subscribers.
+    // Also advances to currBucketNum-1.
     void detectAndDeclareAnomaly(const uint64_t& timestampNs, const int64_t& currBucketNum,
                                  const MetricDimensionKey& key, const int64_t& currentBucketValue);
 
@@ -69,24 +81,26 @@
         return; // Base AnomalyTracker class has no need for the AlarmMonitor.
     }
 
-    // Helper function to return the sum value of past buckets at given dimension.
+    // Returns the sum of all past bucket values for the given dimension key.
     int64_t getSumOverPastBuckets(const MetricDimensionKey& key) const;
 
-    // Helper function to return the value for a past bucket.
+    // Returns the value for a past bucket, or 0 if that bucket doesn't exist.
     int64_t getPastBucketValue(const MetricDimensionKey& key, const int64_t& bucketNum) const;
 
-    // Returns the anomaly threshold.
+    // Returns the anomaly threshold set in the configuration.
     inline int64_t getAnomalyThreshold() const {
         return mAlert.trigger_if_sum_gt();
     }
 
-    // Returns the refractory period timestamp (in seconds) for the given key.
+    // Returns the refractory period ending timestamp (in seconds) for the given key.
+    // Before this moment, any detected anomaly will be ignored.
     // If there is no stored refractory period ending timestamp, returns 0.
     uint32_t getRefractoryPeriodEndsSec(const MetricDimensionKey& key) const {
         const auto& it = mRefractoryPeriodEndsSec.find(key);
         return it != mRefractoryPeriodEndsSec.end() ? it->second : 0;
     }
 
+    // Returns the (constant) number of past buckets this anomaly tracker can store.
     inline int getNumOfPastBuckets() const {
         return mNumOfPastBuckets;
     }
@@ -112,22 +126,27 @@
     // for the anomaly detection (since the current bucket is not in the past).
     const int mNumOfPastBuckets;
 
-    // The existing bucket list.
+    // Values for each of the past mNumOfPastBuckets buckets. Always of size mNumOfPastBuckets.
+    // mPastBuckets[i] can be null, meaning that no data is present in that bucket.
     std::vector<shared_ptr<DimToValMap>> mPastBuckets;
 
-    // Sum over all existing buckets cached in mPastBuckets.
+    // Cached sum over all existing buckets in mPastBuckets.
+    // Its buckets never contain entries of 0.
     DimToValMap mSumOverPastBuckets;
 
     // The bucket number of the last added bucket.
     int64_t mMostRecentBucketNum = -1;
 
     // Map from each dimension to the timestamp that its refractory period (if this anomaly was
-    // declared for that dimension) ends, in seconds. Only anomalies that occur after this period
-    // ends will be declared.
+    // declared for that dimension) ends, in seconds. From this moment and onwards, anomalies
+    // can be declared again.
     // Entries may be, but are not guaranteed to be, removed after the period is finished.
     unordered_map<MetricDimensionKey, uint32_t> mRefractoryPeriodEndsSec;
 
-    void flushPastBuckets(const int64_t& currBucketNum);
+    // Advances mMostRecentBucketNum to bucketNum, deleting any data that is now too old.
+    // Specifically, since it is now too old, removes the data for
+    //   [mMostRecentBucketNum - mNumOfPastBuckets + 1, bucketNum - mNumOfPastBuckets].
+    void advanceMostRecentBucketTo(const int64_t& bucketNum);
 
     // Add the information in the given bucket to mSumOverPastBuckets.
     void addBucketToSum(const shared_ptr<DimToValMap>& bucket);
@@ -136,15 +155,21 @@
     // and remove any items with value 0.
     void subtractBucketFromSum(const shared_ptr<DimToValMap>& bucket);
 
+    // From mSumOverPastBuckets[key], subtracts bucketValue, removing it if it is now 0.
+    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);
 
     // Calculates the corresponding bucket index within the circular array.
+    // Requires bucketNum >= 0.
     size_t index(int64_t bucketNum) const;
 
     // Resets all bucket data. For use when all the data gets stale.
     virtual void resetStorage();
 
-    // Informs the subscribers that an anomaly has occurred.
+    // Informs the subscribers (incidentd, perfetto, broadcasts, etc) that an anomaly has occurred.
     void informSubscribers(const MetricDimensionKey& key);
 
     FRIEND_TEST(AnomalyTrackerTest, TestConsecutiveBuckets);
diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
index 31d50be..d85157c 100644
--- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
@@ -26,30 +26,13 @@
 
 DurationAnomalyTracker::DurationAnomalyTracker(const Alert& alert, const ConfigKey& configKey,
                                                const sp<AlarmMonitor>& alarmMonitor)
-    : AnomalyTracker(alert, configKey), mAlarmMonitor(alarmMonitor) {
+        : AnomalyTracker(alert, configKey), mAlarmMonitor(alarmMonitor) {
+    VLOG("DurationAnomalyTracker() called");
 }
 
 DurationAnomalyTracker::~DurationAnomalyTracker() {
-    stopAllAlarms();
-}
-
-void DurationAnomalyTracker::resetStorage() {
-    AnomalyTracker::resetStorage();
-    if (!mAlarms.empty()) VLOG("AnomalyTracker.resetStorage() called but mAlarms is NOT empty!");
-}
-
-void DurationAnomalyTracker::declareAnomalyIfAlarmExpired(const MetricDimensionKey& dimensionKey,
-                                                          const uint64_t& timestampNs) {
-    auto itr = mAlarms.find(dimensionKey);
-    if (itr == mAlarms.end()) {
-        return;
-    }
-
-    if (itr->second != nullptr &&
-        static_cast<uint32_t>(timestampNs / NS_PER_SEC) >= itr->second->timestampSec) {
-        declareAnomaly(timestampNs, dimensionKey);
-        stopAlarm(dimensionKey);
-    }
+    VLOG("~DurationAnomalyTracker() called");
+    cancelAllAlarms();
 }
 
 void DurationAnomalyTracker::startAlarm(const MetricDimensionKey& dimensionKey,
@@ -57,34 +40,47 @@
     // 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
     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;
     }
+
+    auto itr = mAlarms.find(dimensionKey);
+    if (itr != mAlarms.end() && mAlarmMonitor != nullptr) {
+        mAlarmMonitor->remove(itr->second);
+    }
+
     sp<const InternalAlarm> alarm = new InternalAlarm{timestampSec};
-    mAlarms.insert({dimensionKey, alarm});
+    mAlarms[dimensionKey] = alarm;
     if (mAlarmMonitor != nullptr) {
         mAlarmMonitor->add(alarm);
     }
 }
 
-void DurationAnomalyTracker::stopAlarm(const MetricDimensionKey& dimensionKey) {
-    auto itr = mAlarms.find(dimensionKey);
-    if (itr != mAlarms.end()) {
-        mAlarms.erase(dimensionKey);
-        if (mAlarmMonitor != nullptr) {
-            mAlarmMonitor->remove(itr->second);
-        }
+void DurationAnomalyTracker::stopAlarm(const MetricDimensionKey& dimensionKey,
+                                       const uint64_t& timestampNs) {
+    const auto itr = mAlarms.find(dimensionKey);
+    if (itr == mAlarms.end()) {
+        return;
+    }
+
+    // If the alarm is set in the past but hasn't fired yet (due to lag), catch it now.
+    if (itr->second != nullptr && timestampNs >= NS_PER_SEC * itr->second->timestampSec) {
+        declareAnomaly(timestampNs, dimensionKey);
+    }
+    mAlarms.erase(dimensionKey);
+    if (mAlarmMonitor != nullptr) {
+        mAlarmMonitor->remove(itr->second);
     }
 }
 
-void DurationAnomalyTracker::stopAllAlarms() {
-    std::set<MetricDimensionKey> keys;
-    for (auto itr = mAlarms.begin(); itr != mAlarms.end(); ++itr) {
-        keys.insert(itr->first);
+void DurationAnomalyTracker::cancelAllAlarms() {
+    if (mAlarmMonitor != nullptr) {
+        for (const auto& itr : mAlarms) {
+            mAlarmMonitor->remove(itr.second);
+        }
     }
-    for (auto key : keys) {
-        stopAlarm(key);
-    }
+    mAlarms.clear();
 }
 
 void DurationAnomalyTracker::informAlarmsFired(const uint64_t& timestampNs,
diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.h b/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
index 51186df..92bb2bc 100644
--- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
@@ -32,21 +32,20 @@
 
     virtual ~DurationAnomalyTracker();
 
-    // Starts the alarm at the given timestamp.
+    // Sets an alarm for the given timestamp.
+    // Replaces previous alarm if one already exists.
     void startAlarm(const MetricDimensionKey& dimensionKey, const uint64_t& eventTime);
 
     // Stops the alarm.
-    void stopAlarm(const MetricDimensionKey& dimensionKey);
+    // If it should have already fired, but hasn't yet (e.g. because the AlarmManager is delayed),
+    // declare the anomaly now.
+    void stopAlarm(const MetricDimensionKey& dimensionKey, const uint64_t& timestampNs);
 
-    // Stop all the alarms owned by this tracker.
-    void stopAllAlarms();
-
-    // Declares the anomaly when the alarm expired given the current timestamp.
-    void declareAnomalyIfAlarmExpired(const MetricDimensionKey& dimensionKey,
-                                      const uint64_t& timestampNs);
+    // Stop all the alarms owned by this tracker. Does not declare any anomalies.
+    void cancelAllAlarms();
 
     // Declares an anomaly for each alarm in firedAlarms that belongs to this DurationAnomalyTracker
-    // and removes it from firedAlarms.
+    // and removes it from firedAlarms. The AlarmMonitor is not informed.
     // Note that this will generally be called from a different thread from the other functions;
     // the caller is responsible for thread safety.
     void informAlarmsFired(const uint64_t& timestampNs,
@@ -60,9 +59,6 @@
     // Anomaly alarm monitor.
     sp<AlarmMonitor> mAlarmMonitor;
 
-    // Resets all bucket data. For use when all the data gets stale.
-    void resetStorage() override;
-
     FRIEND_TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp);
     FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm);
     FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 298f494..31ca13a 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -115,7 +115,6 @@
         HardwareFailed hardware_failed = 72;
         PhysicalDropDetected physical_drop_detected = 73;
         ChargeCyclesReported charge_cycles_reported = 74;
-        // TODO: Reorder the numbering so that the most frequent occur events occur in the first 15.
     }
 
     // Pulled events will start at field 10000.
diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
index bfb1ec7..991a76a 100644
--- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
@@ -128,11 +128,11 @@
         }
     }
 
-    // Stops the anomaly alarm.
-    void stopAnomalyAlarm() {
+    // Stops the anomaly alarm. If it should have already fired, declare the anomaly now.
+    void stopAnomalyAlarm(const uint64_t timestamp) {
         for (auto& anomalyTracker : mAnomalyTrackers) {
             if (anomalyTracker != nullptr) {
-                anomalyTracker->stopAlarm(mEventKey);
+                anomalyTracker->stopAlarm(mEventKey, timestamp);
             }
         }
     }
@@ -155,14 +155,6 @@
         }
     }
 
-    void declareAnomalyIfAlarmExpired(const uint64_t& timestamp) {
-        for (auto& anomalyTracker : mAnomalyTrackers) {
-            if (anomalyTracker != nullptr) {
-                anomalyTracker->declareAnomalyIfAlarmExpired(mEventKey, timestamp);
-            }
-        }
-    }
-
     // Convenience to compute the current bucket's end time, which is always aligned with the
     // start time of the metric.
     uint64_t getCurrentBucketEndTimeNs() {
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
index 058940d..335ec4c 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
@@ -130,7 +130,7 @@
         case DurationState::kStarted: {
             duration.startCount--;
             if (forceStop || !mNested || duration.startCount <= 0) {
-                stopAnomalyAlarm();
+                stopAnomalyAlarm(eventTime);
                 duration.state = DurationState::kStopped;
                 int64_t durationTime = eventTime - duration.lastStartTime;
                 VLOG("Max, key %s, Stop %lld %lld %lld", key.toString().c_str(),
@@ -284,7 +284,7 @@
             // If condition becomes false, kStarted -> kPaused. Record the current duration and
             // stop anomaly alarm.
             if (!conditionMet) {
-                stopAnomalyAlarm();
+                stopAnomalyAlarm(timestamp);
                 it->second.state = DurationState::kPaused;
                 it->second.lastDuration += (timestamp - it->second.lastStartTime);
                 if (anyStarted()) {
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
index c8a5016..b418a85 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
@@ -92,7 +92,6 @@
 
 void OringDurationTracker::noteStop(const HashableDimensionKey& key, const uint64_t timestamp,
                                     const bool stopAll) {
-    declareAnomalyIfAlarmExpired(timestamp);
     VLOG("Oring: %s stop", key.toString().c_str());
     auto it = mStarted.find(key);
     if (it != mStarted.end()) {
@@ -118,12 +117,11 @@
         }
     }
     if (mStarted.empty()) {
-        stopAnomalyAlarm();
+        stopAnomalyAlarm(timestamp);
     }
 }
 
 void OringDurationTracker::noteStopAll(const uint64_t timestamp) {
-    declareAnomalyIfAlarmExpired(timestamp);
     if (!mStarted.empty()) {
         mDuration += (timestamp - mLastStartTime);
         VLOG("Oring Stop all: record duration %lld %lld ", (long long)timestamp - mLastStartTime,
@@ -131,7 +129,7 @@
         detectAndDeclareAnomaly(timestamp, mCurrentBucketNum, mDuration + mDurationFullBucket);
     }
 
-    stopAnomalyAlarm();
+    stopAnomalyAlarm(timestamp);
     mStarted.clear();
     mPaused.clear();
     mConditionKeyMap.clear();
@@ -213,7 +211,6 @@
 }
 
 void OringDurationTracker::onSlicedConditionMayChange(const uint64_t timestamp) {
-    declareAnomalyIfAlarmExpired(timestamp);
     vector<pair<HashableDimensionKey, int>> startedToPaused;
     vector<pair<HashableDimensionKey, int>> pausedToStarted;
     if (!mStarted.empty()) {
@@ -291,12 +288,11 @@
     mPaused.insert(startedToPaused.begin(), startedToPaused.end());
 
     if (mStarted.empty()) {
-        stopAnomalyAlarm();
+        stopAnomalyAlarm(timestamp);
     }
 }
 
 void OringDurationTracker::onConditionChanged(bool condition, const uint64_t timestamp) {
-    declareAnomalyIfAlarmExpired(timestamp);
     if (condition) {
         if (!mPaused.empty()) {
             VLOG("Condition true, all started");
@@ -319,7 +315,7 @@
         }
     }
     if (mStarted.empty()) {
-        stopAnomalyAlarm();
+        stopAnomalyAlarm(timestamp);
     }
 }
 
@@ -328,12 +324,16 @@
     // TODO: Unit-test this and see if it can be done more efficiently (e.g. use int32).
     // All variables below represent durations (not timestamps).
 
+    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);
-    // TODO: This should never be < 0. Document/guard against possible failures if it is.
-
-    const int64_t thresholdNs = anomalyTracker.getAnomalyThreshold();
+    if (currRemainingBucketSizeNs < 0) {
+        ALOGE("OringDurationTracker currRemainingBucketSizeNs < 0");
+        // This should never happen. Return the safest thing possible given that data is corrupt.
+        return eventTimestampNs + thresholdNs;
+    }
 
     // As we move into the future, old buckets get overwritten (so their old data is erased).
 
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index b5afef2..901f500 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -562,6 +562,10 @@
                   (long long)alert.metric_id());
             return false;
         }
+        if (!alert.has_trigger_if_sum_gt()) {
+            ALOGW("invalid alert: missing threshold");
+            return false;
+        }
         if (alert.trigger_if_sum_gt() < 0 || alert.num_buckets() <= 0) {
             ALOGW("invalid alert: threshold=%f num_buckets= %d",
                   alert.trigger_if_sum_gt(), alert.num_buckets());
diff --git a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
index b4a7bb7..218d52a 100644
--- a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
+++ b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
@@ -16,6 +16,7 @@
 #include "../metrics/metrics_test_helper.h"
 
 #include <gtest/gtest.h>
+#include <math.h>
 #include <stdio.h>
 #include <vector>
 
@@ -104,12 +105,12 @@
     for (const auto& kv : timestamps) {
         if (kv.second < 0) {
             // Make sure that, if there is a refractory period, it is already past.
-            EXPECT_LT(tracker.getRefractoryPeriodEndsSec(kv.first),
-                    currTimestampNs / NS_PER_SEC + 1)
+            EXPECT_LT(tracker.getRefractoryPeriodEndsSec(kv.first) * NS_PER_SEC,
+                    (uint64_t)currTimestampNs)
                     << "Failure was at currTimestampNs " << currTimestampNs;
         } else {
             EXPECT_EQ(tracker.getRefractoryPeriodEndsSec(kv.first),
-                      kv.second / NS_PER_SEC + refractoryPeriodSec)
+                      std::ceil(1.0 * kv.second / NS_PER_SEC) + refractoryPeriodSec)
                       << "Failure was at currTimestampNs " << currTimestampNs;
         }
     }
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
index a07683e..fff1155 100644
--- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -19,6 +19,7 @@
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
+#include <math.h>
 #include <stdio.h>
 #include <vector>
 
@@ -379,13 +380,13 @@
     EXPECT_EQ(3L, countProducer.mCurrentSlicedCounter->begin()->second);
     // Anomaly at event 6 is within refractory period. The alarm is at event 5 timestamp not event 6
     EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-            event5.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec);
+            std::ceil(1.0 * event5.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
 
     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event7);
     EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
     EXPECT_EQ(4L, countProducer.mCurrentSlicedCounter->begin()->second);
     EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-            event7.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec);
+            std::ceil(1.0 * event7.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index c0cc0b6..5ef84e6 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -20,6 +20,7 @@
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
+#include <math.h>
 #include <stdio.h>
 #include <vector>
 
@@ -392,7 +393,7 @@
                            .mFields->begin()
                            ->mValue.int_value);
     EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-            event2->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec);
+            std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC) + refPeriodSec);
 
     std::shared_ptr<LogEvent> event3 =
             std::make_shared<LogEvent>(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 10);
@@ -407,7 +408,7 @@
                            .mFields->begin()
                            ->mValue.int_value);
     EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-            event2->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec);
+            std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
 
     // The event4 does not have the gauge field. Thus the current bucket value is 0.
     std::shared_ptr<LogEvent> event4 =
diff --git a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
index 54abcb2..9b27f3c 100644
--- a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
@@ -19,6 +19,7 @@
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
+#include <math.h>
 #include <stdio.h>
 #include <set>
 #include <unordered_map>
@@ -416,7 +417,7 @@
     tracker.noteStop(kEventKey1, eventStartTimeNs + 2 * bucketSizeNs + 25, false);
     EXPECT_EQ(anomalyTracker->getSumOverPastBuckets(eventKey), (long long)(bucketSizeNs));
     EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey),
-              (eventStartTimeNs + 2 * bucketSizeNs + 25) / NS_PER_SEC + refPeriodSec);
+              std::ceil((eventStartTimeNs + 2 * bucketSizeNs + 25.0) / NS_PER_SEC + refPeriodSec));
 }
 
 TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm) {
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index a0addcc..a8eb2703 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -19,6 +19,7 @@
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
+#include <math.h>
 #include <stdio.h>
 #include <vector>
 
@@ -415,16 +416,16 @@
     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
     // Anomaly at event 4 since Value sum == 131 > 130!
     EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-            event4->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec);
+            std::ceil(1.0 * event4->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event5);
     // Event 5 is within 3 sec refractory period. Thus last alarm timestamp is still event4.
     EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-            event4->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec);
+            std::ceil(1.0 * event4->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
 
     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event6);
     // Anomaly at event 6 since Value sum == 160 > 130 and after refractory period.
     EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-            event6->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec);
+            std::ceil(1.0 * event6->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
 }
 
 }  // namespace statsd
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 99d871e..e2121dd 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -117,8 +117,8 @@
 Landroid/app/admin/DevicePolicyManager;->packageHasActiveAdmins(Ljava/lang/String;I)Z
 Landroid/app/admin/DevicePolicyManager;->setActiveAdmin(Landroid/content/ComponentName;ZI)V
 Landroid/app/admin/DevicePolicyManager;->setActiveAdmin(Landroid/content/ComponentName;Z)V
-Landroid/app/admin/DevicePolicyManager;->throwIfParentInstance(Ljava/lang/String;)V
 Landroid/app/admin/DevicePolicyManager;->setDefaultSmsApplication(Landroid/content/ComponentName;Ljava/lang/String;)V
+Landroid/app/admin/DevicePolicyManager;->throwIfParentInstance(Ljava/lang/String;)V
 Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_packageHasActiveAdmins:I
 Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_removeActiveAdmin:I
 Landroid/app/admin/SecurityLog$SecurityEvent;-><init>([B)V
@@ -148,6 +148,7 @@
 Landroid/app/Application;->mLoadedApk:Landroid/app/LoadedApk;
 Landroid/app/ApplicationPackageManager;->configurationChanged()V
 Landroid/app/ApplicationPackageManager;->deletePackage(Ljava/lang/String;Landroid/content/pm/IPackageDeleteObserver;I)V
+Landroid/app/ApplicationPackageManager;->getPackageCurrentVolume(Landroid/content/pm/ApplicationInfo;)Landroid/os/storage/VolumeInfo;
 Landroid/app/ApplicationPackageManager;->getPackageSizeInfoAsUser(Ljava/lang/String;ILandroid/content/pm/IPackageStatsObserver;)V
 Landroid/app/ApplicationPackageManager;-><init>(Landroid/app/ContextImpl;Landroid/content/pm/IPackageManager;)V
 Landroid/app/ApplicationPackageManager;->mPM:Landroid/content/pm/IPackageManager;
@@ -175,6 +176,7 @@
 Landroid/app/backup/BackupHelperDispatcher$Header;->keyPrefix:Ljava/lang/String;
 Landroid/app/backup/FullBackup;->backupToTar(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/app/backup/FullBackupDataOutput;)I
 Landroid/app/backup/FullBackupDataOutput;->addSize(J)V
+Landroid/app/backup/FullBackupDataOutput;-><init>(Landroid/os/ParcelFileDescriptor;)V
 Landroid/app/backup/FullBackupDataOutput;->mData:Landroid/app/backup/BackupDataOutput;
 Landroid/app/ContentProviderHolder;->info:Landroid/content/pm/ProviderInfo;
 Landroid/app/ContentProviderHolder;-><init>(Landroid/content/pm/ProviderInfo;)V
@@ -281,6 +283,7 @@
 Landroid/app/Notification;->mLargeIcon:Landroid/graphics/drawable/Icon;
 Landroid/app/Notification;->mSmallIcon:Landroid/graphics/drawable/Icon;
 Landroid/app/Notification;->setLatestEventInfo(Landroid/content/Context;Ljava/lang/CharSequence;Ljava/lang/CharSequence;Landroid/app/PendingIntent;)V
+Landroid/app/Notification;->setSmallIcon(Landroid/graphics/drawable/Icon;)V
 Landroid/app/PendingIntent;->getActivityAsUser(Landroid/content/Context;ILandroid/content/Intent;ILandroid/os/Bundle;Landroid/os/UserHandle;)Landroid/app/PendingIntent;
 Landroid/app/PendingIntent;->getIntent()Landroid/content/Intent;
 Landroid/app/PendingIntent;->isActivity()Z
@@ -327,7 +330,9 @@
 Landroid/appwidget/AppWidgetManager;->mService:Lcom/android/internal/appwidget/IAppWidgetService;
 Landroid/bluetooth/BluetoothA2dp;->connect(Landroid/bluetooth/BluetoothDevice;)Z
 Landroid/bluetooth/BluetoothAdapter;->disable(Z)Z
+Landroid/bluetooth/BluetoothAdapter;->factoryReset()Z
 Landroid/bluetooth/BluetoothAdapter;->getDiscoverableTimeout()I
+Landroid/bluetooth/BluetoothAdapter;->getLeState()I
 Landroid/bluetooth/BluetoothAdapter;->mService:Landroid/bluetooth/IBluetooth;
 Landroid/bluetooth/BluetoothAdapter;->setScanMode(II)Z
 Landroid/bluetooth/BluetoothAdapter;->setScanMode(I)Z
@@ -337,8 +342,11 @@
 Landroid/bluetooth/BluetoothGattCharacteristic;->mService:Landroid/bluetooth/BluetoothGattService;
 Landroid/bluetooth/BluetoothGattDescriptor;->mCharacteristic:Landroid/bluetooth/BluetoothGattCharacteristic;
 Landroid/bluetooth/BluetoothGattDescriptor;->mInstance:I
+Landroid/bluetooth/BluetoothGatt;->mAuthRetryState:I
 Landroid/bluetooth/BluetoothGatt;->refresh()Z
 Landroid/bluetooth/BluetoothHeadset;->close()V
+Landroid/bluetooth/BluetoothPan;->isTetheringOn()Z
+Landroid/bluetooth/BluetoothPan;->setBluetoothTethering(Z)V
 Landroid/bluetooth/BluetoothUuid;->RESERVED_UUIDS:[Landroid/os/ParcelUuid;
 Landroid/bluetooth/IBluetooth;->getAddress()Ljava/lang/String;
 Landroid/bluetooth/IBluetoothManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -610,6 +618,12 @@
 Landroid/graphics/drawable/GradientDrawable$GradientState;->mThicknessRatio:F
 Landroid/graphics/drawable/GradientDrawable$GradientState;->mWidth:I
 Landroid/graphics/drawable/GradientDrawable;->mPadding:Landroid/graphics/Rect;
+Landroid/graphics/drawable/Icon;->getBitmap()Landroid/graphics/Bitmap;
+Landroid/graphics/drawable/Icon;->getDataBytes()[B
+Landroid/graphics/drawable/Icon;->getDataLength()I
+Landroid/graphics/drawable/Icon;->getDataOffset()I
+Landroid/graphics/drawable/Icon;->getResources()Landroid/content/res/Resources;
+Landroid/graphics/drawable/Icon;->hasTint()Z
 Landroid/graphics/drawable/Icon;->mType:I
 Landroid/graphics/drawable/InsetDrawable;->mState:Landroid/graphics/drawable/InsetDrawable$InsetState;
 Landroid/graphics/drawable/NinePatchDrawable;->mNinePatchState:Landroid/graphics/drawable/NinePatchDrawable$NinePatchState;
@@ -817,6 +831,7 @@
 Landroid/media/AudioManager;->getService()Landroid/media/IAudioService;
 Landroid/media/AudioManager;->mAudioFocusIdListenerMap:Ljava/util/concurrent/ConcurrentHashMap;
 Landroid/media/AudioManager;->setMasterMute(ZI)V
+Landroid/media/AudioManager;->startBluetoothScoVirtualCall()V
 Landroid/media/AudioManager;->STREAM_BLUETOOTH_SCO:I
 Landroid/media/AudioManager;->STREAM_SYSTEM_ENFORCED:I
 Landroid/media/AudioManager;->STREAM_TTS:I
@@ -860,6 +875,7 @@
 Landroid/media/AudioSystem;->errorCallbackFromNative(I)V
 Landroid/media/AudioSystem;->getPrimaryOutputFrameCount()I
 Landroid/media/AudioSystem;->getPrimaryOutputSamplingRate()I
+Landroid/media/AudioSystem;->isStreamActive(II)Z
 Landroid/media/AudioSystem;->recordingCallbackFromNative(IIII[I)V
 Landroid/media/AudioSystem;->setDeviceConnectionState(IILjava/lang/String;Ljava/lang/String;)I
 Landroid/media/AudioSystem;->setErrorCallback(Landroid/media/AudioSystem$ErrorCallback;)V
@@ -1045,6 +1061,22 @@
 Landroid/net/wifi/ScanResult;->distanceSdCm:I
 Landroid/net/wifi/ScanResult;->flags:J
 Landroid/net/wifi/ScanResult;->hessid:J
+Landroid/net/wifi/ScanResult$InformationElement;->bytes:[B
+Landroid/net/wifi/ScanResult$InformationElement;->EID_BSS_LOAD:I
+Landroid/net/wifi/ScanResult$InformationElement;->EID_ERP:I
+Landroid/net/wifi/ScanResult$InformationElement;->EID_EXTENDED_CAPS:I
+Landroid/net/wifi/ScanResult$InformationElement;->EID_EXTENDED_SUPPORTED_RATES:I
+Landroid/net/wifi/ScanResult$InformationElement;->EID_HT_OPERATION:I
+Landroid/net/wifi/ScanResult$InformationElement;->EID_INTERWORKING:I
+Landroid/net/wifi/ScanResult$InformationElement;->EID_ROAMING_CONSORTIUM:I
+Landroid/net/wifi/ScanResult$InformationElement;->EID_RSN:I
+Landroid/net/wifi/ScanResult$InformationElement;->EID_SSID:I
+Landroid/net/wifi/ScanResult$InformationElement;->EID_SUPPORTED_RATES:I
+Landroid/net/wifi/ScanResult$InformationElement;->EID_TIM:I
+Landroid/net/wifi/ScanResult$InformationElement;->EID_VHT_OPERATION:I
+Landroid/net/wifi/ScanResult$InformationElement;->EID_VSA:I
+Landroid/net/wifi/ScanResult$InformationElement;->id:I
+Landroid/net/wifi/ScanResult;->informationElements:[Landroid/net/wifi/ScanResult$InformationElement;
 Landroid/net/wifi/ScanResult;->numUsage:I
 Landroid/net/wifi/ScanResult;->seen:J
 Landroid/net/wifi/ScanResult;->untrusted:Z
@@ -1182,6 +1214,7 @@
 Landroid/os/Parcel;->readArrayMap(Landroid/util/ArrayMap;Ljava/lang/ClassLoader;)V
 Landroid/os/Parcel$ReadWriteHelper;-><init>()V
 Landroid/os/Parcel;->writeArrayMap(Landroid/util/ArrayMap;)V
+Landroid/os/PowerManager;->getDefaultScreenBrightnessSetting()I
 Landroid/os/PowerManager;->getMaximumScreenBrightnessSetting()I
 Landroid/os/PowerManager;->getMinimumScreenBrightnessSetting()I
 Landroid/os/PowerManager;->isLightDeviceIdleMode()Z
@@ -1371,6 +1404,8 @@
 Landroid/provider/Settings$Global;->ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED:Ljava/lang/String;
 Landroid/provider/Settings$Global;->PACKAGE_VERIFIER_ENABLE:Ljava/lang/String;
 Landroid/provider/Settings$Global;->sNameValueCache:Landroid/provider/Settings$NameValueCache;
+Landroid/provider/Settings;->isCallingPackageAllowedToDrawOverlays(Landroid/content/Context;ILjava/lang/String;Z)Z
+Landroid/provider/Settings;->isCallingPackageAllowedToWriteSettings(Landroid/content/Context;ILjava/lang/String;Z)Z
 Landroid/provider/Settings$NameValueCache;->mProviderHolder:Landroid/provider/Settings$ContentProviderHolder;
 Landroid/provider/Settings$Secure;->ACCESSIBILITY_AUTOCLICK_ENABLED:Ljava/lang/String;
 Landroid/provider/Settings$Secure;->ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED:Ljava/lang/String;
@@ -1385,6 +1420,7 @@
 Landroid/provider/Settings$System;->HEARING_AID:Ljava/lang/String;
 Landroid/provider/Settings$System;->MASTER_MONO:Ljava/lang/String;
 Landroid/provider/Settings$System;->putStringForUser(Landroid/content/ContentResolver;Ljava/lang/String;Ljava/lang/String;I)Z
+Landroid/provider/Settings$System;->SCREEN_AUTO_BRIGHTNESS_ADJ:Ljava/lang/String;
 Landroid/provider/Settings$System;->sNameValueCache:Landroid/provider/Settings$NameValueCache;
 Landroid/provider/Telephony$Sms;->addMessageToUri(ILandroid/content/ContentResolver;Landroid/net/Uri;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;ZZJ)Landroid/net/Uri;
 Landroid/provider/Telephony$Sms;->addMessageToUri(ILandroid/content/ContentResolver;Landroid/net/Uri;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;ZZ)Landroid/net/Uri;
@@ -2036,6 +2072,7 @@
 Landroid/view/View;->dispatchDetachedFromWindow()V
 Landroid/view/View;->fitsSystemWindows()Z
 Landroid/view/View;->getAccessibilityDelegate()Landroid/view/View$AccessibilityDelegate;
+Landroid/view/View;->getInverseMatrix()Landroid/graphics/Matrix;
 Landroid/view/View;->getListenerInfo()Landroid/view/View$ListenerInfo;
 Landroid/view/View;->getLocationOnScreen()[I
 Landroid/view/View;->getTransitionAlpha()F
@@ -2195,6 +2232,7 @@
 Landroid/widget/ActivityChooserView;->setExpandActivityOverflowButtonDrawable(Landroid/graphics/drawable/Drawable;)V
 Landroid/widget/AdapterView;->mDataChanged:Z
 Landroid/widget/AdapterView;->mFirstPosition:I
+Landroid/widget/AdapterView;->mOldSelectedPosition:I
 Landroid/widget/AdapterView;->setNextSelectedPositionInt(I)V
 Landroid/widget/AdapterView;->setSelectedPositionInt(I)V
 Landroid/widget/AutoCompleteTextView;->doAfterTextChanged()V
@@ -2207,6 +2245,7 @@
 Landroid/widget/EdgeEffect;->mPaint:Landroid/graphics/Paint;
 Landroid/widget/Editor;->invalidateTextDisplayList()V
 Landroid/widget/Editor;->mShowCursor:J
+Landroid/widget/Editor;->mShowSoftInputOnFocus:Z
 Landroid/widget/ExpandableListView;->mChildDivider:Landroid/graphics/drawable/Drawable;
 Landroid/widget/FastScroller;->mContainerRect:Landroid/graphics/Rect;
 Landroid/widget/FastScroller;->mHeaderCount:I
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index cab6744..2752fa9 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -69,6 +69,13 @@
               AppProtoEnums.APP_TRANSITION_SNAPSHOT; // 4
 
     /**
+     * Type for {@link #notifyAppTransitionStarting}: The transition was started because it was a
+     * recents animation and we only needed to wait on the wallpaper.
+     */
+    public static final int APP_TRANSITION_RECENTS_ANIM =
+            AppProtoEnums.APP_TRANSITION_RECENTS_ANIM; // 5
+
+    /**
      * The bundle key to extract the assist data.
      */
     public static final String ASSIST_KEY_DATA = "data";
diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java
index b12e3bc..7325daa7 100644
--- a/core/java/android/app/StatsManager.java
+++ b/core/java/android/app/StatsManager.java
@@ -103,12 +103,12 @@
             try {
                 IStatsManager service = getIStatsManagerLocked();
                 if (service == null) {
-                    if (DEBUG) Slog.d(TAG, "Failed to find statsd when adding configuration");
+                    Slog.e(TAG, "Failed to find statsd when adding configuration");
                     return false;
                 }
                 return service.addConfiguration(configKey, config);
             } catch (RemoteException e) {
-                if (DEBUG) Slog.d(TAG, "Failed to connect to statsd when adding configuration");
+                Slog.e(TAG, "Failed to connect to statsd when adding configuration");
                 return false;
             }
         }
@@ -126,12 +126,12 @@
             try {
                 IStatsManager service = getIStatsManagerLocked();
                 if (service == null) {
-                    if (DEBUG) Slog.d(TAG, "Failed to find statsd when removing configuration");
+                    Slog.e(TAG, "Failed to find statsd when removing configuration");
                     return false;
                 }
                 return service.removeConfiguration(configKey);
             } catch (RemoteException e) {
-                if (DEBUG) Slog.d(TAG, "Failed to connect to statsd when removing configuration");
+                Slog.e(TAG, "Failed to connect to statsd when removing configuration");
                 return false;
             }
         }
@@ -173,7 +173,7 @@
             try {
                 IStatsManager service = getIStatsManagerLocked();
                 if (service == null) {
-                    Slog.w(TAG, "Failed to find statsd when adding broadcast subscriber");
+                    Slog.e(TAG, "Failed to find statsd when adding broadcast subscriber");
                     return false;
                 }
                 if (pendingIntent != null) {
@@ -184,7 +184,7 @@
                     return service.unsetBroadcastSubscriber(configKey, subscriberId);
                 }
             } catch (RemoteException e) {
-                Slog.w(TAG, "Failed to connect to statsd when adding broadcast subscriber", e);
+                Slog.e(TAG, "Failed to connect to statsd when adding broadcast subscriber", e);
                 return false;
             }
         }
@@ -210,7 +210,7 @@
             try {
                 IStatsManager service = getIStatsManagerLocked();
                 if (service == null) {
-                    Slog.d(TAG, "Failed to find statsd when registering data listener.");
+                    Slog.e(TAG, "Failed to find statsd when registering data listener.");
                     return false;
                 }
                 if (pendingIntent == null) {
@@ -222,7 +222,7 @@
                 }
 
             } catch (RemoteException e) {
-                Slog.d(TAG, "Failed to connect to statsd when registering data listener.");
+                Slog.e(TAG, "Failed to connect to statsd when registering data listener.");
                 return false;
             }
         }
@@ -241,12 +241,12 @@
             try {
                 IStatsManager service = getIStatsManagerLocked();
                 if (service == null) {
-                    if (DEBUG) Slog.d(TAG, "Failed to find statsd when getting data");
+                    Slog.e(TAG, "Failed to find statsd when getting data");
                     return null;
                 }
                 return service.getData(configKey);
             } catch (RemoteException e) {
-                if (DEBUG) Slog.d(TAG, "Failed to connecto statsd when getting data");
+                Slog.e(TAG, "Failed to connect to statsd when getting data");
                 return null;
             }
         }
@@ -265,12 +265,12 @@
             try {
                 IStatsManager service = getIStatsManagerLocked();
                 if (service == null) {
-                    if (DEBUG) Slog.d(TAG, "Failed to find statsd when getting metadata");
+                    Slog.e(TAG, "Failed to find statsd when getting metadata");
                     return null;
                 }
                 return service.getMetadata();
             } catch (RemoteException e) {
-                if (DEBUG) Slog.d(TAG, "Failed to connecto statsd when getting metadata");
+                Slog.e(TAG, "Failed to connect to statsd when getting metadata");
                 return null;
             }
         }
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 85a9be3..b83b44d 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -74,11 +74,12 @@
     public static final int DISABLE2_SYSTEM_ICONS = 1 << 1;
     public static final int DISABLE2_NOTIFICATION_SHADE = 1 << 2;
     public static final int DISABLE2_GLOBAL_ACTIONS = 1 << 3;
+    public static final int DISABLE2_ROTATE_SUGGESTIONS = 1 << 4;
 
     public static final int DISABLE2_NONE = 0x00000000;
 
     public static final int DISABLE2_MASK = DISABLE2_QUICK_SETTINGS | DISABLE2_SYSTEM_ICONS
-            | DISABLE2_NOTIFICATION_SHADE | DISABLE2_GLOBAL_ACTIONS;
+            | DISABLE2_NOTIFICATION_SHADE | DISABLE2_GLOBAL_ACTIONS | DISABLE2_ROTATE_SUGGESTIONS;
 
     @IntDef(flag = true, prefix = { "DISABLE2_" }, value = {
             DISABLE2_NONE,
@@ -86,7 +87,8 @@
             DISABLE2_QUICK_SETTINGS,
             DISABLE2_SYSTEM_ICONS,
             DISABLE2_NOTIFICATION_SHADE,
-            DISABLE2_GLOBAL_ACTIONS
+            DISABLE2_GLOBAL_ACTIONS,
+            DISABLE2_ROTATE_SUGGESTIONS
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Disable2Flags {}
diff --git a/core/java/android/content/SyncResult.java b/core/java/android/content/SyncResult.java
index 4f86af9..f67d7f5 100644
--- a/core/java/android/content/SyncResult.java
+++ b/core/java/android/content/SyncResult.java
@@ -79,7 +79,17 @@
 
     /**
      * Used to indicate to the SyncManager that future sync requests that match the request's
-     * Account and authority should be delayed at least this many seconds.
+     * Account and authority should be delayed until a time in seconds since Java epoch.
+     *
+     * <p>For example, if you want to delay the next sync for at least 5 minutes, then:
+     * <pre>
+     * result.delayUntil = (System.currentTimeMillis() / 1000) + 5 * 60;
+     * </pre>
+     *
+     * <p>By default, when a sync fails, the system retries later with an exponential back-off
+     * with the system default initial delay time, which always wins over {@link #delayUntil} --
+     * i.e. if the system back-off time is larger than {@link #delayUntil}, {@link #delayUntil}
+     * will essentially be ignored.
      */
     public long delayUntil;
 
diff --git a/core/java/android/security/ConfirmationDialog.java b/core/java/android/security/ConfirmationDialog.java
index f6127e1..1697106 100644
--- a/core/java/android/security/ConfirmationDialog.java
+++ b/core/java/android/security/ConfirmationDialog.java
@@ -227,12 +227,32 @@
         return uiOptionsAsFlags;
     }
 
+    private boolean isAccessibilityServiceRunning() {
+        boolean serviceRunning = false;
+        try {
+            ContentResolver contentResolver = mContext.getContentResolver();
+            int a11yEnabled = Settings.Secure.getInt(contentResolver,
+                    Settings.Secure.ACCESSIBILITY_ENABLED);
+            if (a11yEnabled == 1) {
+                serviceRunning = true;
+            }
+        } catch (SettingNotFoundException e) {
+            Log.w(TAG, "Unexpected SettingNotFoundException");
+            e.printStackTrace();
+        }
+        return serviceRunning;
+    }
+
     /**
      * Requests a confirmation prompt to be presented to the user.
      *
      * When the prompt is no longer being presented, one of the methods in
      * {@link ConfirmationCallback} is called on the supplied callback object.
      *
+     * Confirmation dialogs may not be available when accessibility services are running so this
+     * may fail with a {@link ConfirmationNotAvailableException} exception even if
+     * {@link #isSupported} returns {@code true}.
+     *
      * @param executor the executor identifying the thread that will receive the callback.
      * @param callback the callback to use when the dialog is done showing.
      * @throws IllegalArgumentException if the prompt text is too long or malfomed.
@@ -245,6 +265,9 @@
         if (mCallback != null) {
             throw new ConfirmationAlreadyPresentingException();
         }
+        if (isAccessibilityServiceRunning()) {
+            throw new ConfirmationNotAvailableException();
+        }
         mCallback = callback;
         mExecutor = executor;
 
diff --git a/core/proto/android/app/enums.proto b/core/proto/android/app/enums.proto
index 5eb05be..1754e42 100644
--- a/core/proto/android/app/enums.proto
+++ b/core/proto/android/app/enums.proto
@@ -32,6 +32,9 @@
     APP_TRANSITION_TIMEOUT = 3;
     // The transition was started because of a we drew a task snapshot.
     APP_TRANSITION_SNAPSHOT = 4;
+    // The transition was started because it was a recents animation and we only needed to wait on
+    // the wallpaper.
+    APP_TRANSITION_RECENTS_ANIM = 5;
 }
 
 // ActivityManager.java PROCESS_STATEs
diff --git a/media/java/android/media/MediaPlayerBase.java b/media/java/android/media/MediaPlayerBase.java
index f18e347..48b7a51 100644
--- a/media/java/android/media/MediaPlayerBase.java
+++ b/media/java/android/media/MediaPlayerBase.java
@@ -129,6 +129,33 @@
      */
     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;
 
     /**
diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java
index 60714df..6647831 100644
--- a/media/java/android/media/MediaSession2.java
+++ b/media/java/android/media/MediaSession2.java
@@ -1418,14 +1418,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();
diff --git a/media/java/android/media/update/ApiLoader.java b/media/java/android/media/update/ApiLoader.java
index 0d190a7..cf18bdd 100644
--- a/media/java/android/media/update/ApiLoader.java
+++ b/media/java/android/media/update/ApiLoader.java
@@ -16,49 +16,73 @@
 
 package android.media.update;
 
-import android.annotation.NonNull;
-import android.content.res.Resources;
+import android.app.ActivityManager;
+import android.app.AppGlobals;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Build;
+import android.os.RemoteException;
+import android.os.UserHandle;
+
+import com.android.internal.annotations.GuardedBy;
+
+import dalvik.system.PathClassLoader;
+
+import java.io.File;
 
 /**
  * @hide
  */
 public final class ApiLoader {
-    private static Object sMediaLibrary;
+    @GuardedBy("this")
+    private static StaticProvider sMediaUpdatable;
 
     private static final String UPDATE_PACKAGE = "com.android.media.update";
     private static final String UPDATE_CLASS = "com.android.media.update.ApiFactory";
     private static final String UPDATE_METHOD = "initialize";
+    private static final boolean REGISTER_UPDATE_DEPENDENCY = true;
 
     private ApiLoader() { }
 
-    public static StaticProvider getProvider(@NonNull Context context) {
-        if (context == null) {
-            throw new IllegalArgumentException("context shouldn't be null");
-        }
+    @Deprecated
+    public static StaticProvider getProvider(Context context) {
+        return getProvider();
+    }
+
+    public static StaticProvider getProvider() {
+        if (sMediaUpdatable != null) return sMediaUpdatable;
+
         try {
-            return (StaticProvider) getMediaLibraryImpl(context);
-        } catch (PackageManager.NameNotFoundException | ReflectiveOperationException e) {
+            return getMediaUpdatable();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (NameNotFoundException | ReflectiveOperationException e) {
             throw new RuntimeException(e);
         }
     }
 
     // TODO This method may do I/O; Ensure it does not violate (emit warnings in) strict mode.
-    private static synchronized Object getMediaLibraryImpl(Context context)
-            throws PackageManager.NameNotFoundException, ReflectiveOperationException {
-        if (sMediaLibrary != null) return sMediaLibrary;
+    private static synchronized StaticProvider getMediaUpdatable()
+            throws NameNotFoundException, ReflectiveOperationException, RemoteException {
+        if (sMediaUpdatable != null) return sMediaUpdatable;
 
         // TODO Figure out when to use which package (query media update service)
         int flags = Build.IS_DEBUGGABLE ? 0 : PackageManager.MATCH_FACTORY_ONLY;
-        Context libContext = context.createApplicationContext(
-                context.getPackageManager().getPackageInfo(UPDATE_PACKAGE, flags).applicationInfo,
-                Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
-        sMediaLibrary = libContext.getClassLoader()
-                .loadClass(UPDATE_CLASS)
-                .getMethod(UPDATE_METHOD, Resources.class, Resources.Theme.class)
-                .invoke(null, libContext.getResources(), libContext.getTheme());
-        return sMediaLibrary;
+        flags |= PackageManager.GET_SHARED_LIBRARY_FILES;
+        ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
+                UPDATE_PACKAGE, flags, UserHandle.myUserId());
+
+        if (REGISTER_UPDATE_DEPENDENCY) {
+            // Register a dependency to the updatable in order to be killed during updates
+            ActivityManager.getService().addPackageDependency(ai.packageName);
+        }
+
+        PathClassLoader classLoader = new PathClassLoader(ai.sourceDir,
+                ai.nativeLibraryDir + File.pathSeparator + System.getProperty("java.library.path"),
+                ClassLoader.getSystemClassLoader().getParent());
+        return sMediaUpdatable = (StaticProvider) classLoader.loadClass(UPDATE_CLASS)
+                .getMethod(UPDATE_METHOD, ApplicationInfo.class).invoke(null, ai);
     }
 }
diff --git a/packages/CaptivePortalLogin/AndroidManifest.xml b/packages/CaptivePortalLogin/AndroidManifest.xml
index f21fd88..69fbb99 100644
--- a/packages/CaptivePortalLogin/AndroidManifest.xml
+++ b/packages/CaptivePortalLogin/AndroidManifest.xml
@@ -23,7 +23,8 @@
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
 
-    <application android:label="@string/app_name" >
+    <application android:label="@string/app_name"
+                 android:usesCleartextTraffic="true">
         <activity
             android:name="com.android.captiveportallogin.CaptivePortalLoginActivity"
             android:label="@string/action_bar_label"
diff --git a/packages/CarrierDefaultApp/AndroidManifest.xml b/packages/CarrierDefaultApp/AndroidManifest.xml
index 1cd7b61..824d9f4 100644
--- a/packages/CarrierDefaultApp/AndroidManifest.xml
+++ b/packages/CarrierDefaultApp/AndroidManifest.xml
@@ -29,7 +29,8 @@
 
     <application
         android:label="@string/app_name"
-        android:directBootAware="true">
+        android:directBootAware="true"
+        android:usesCleartextTraffic="true">
         <receiver android:name="com.android.carrierdefaultapp.CarrierDefaultBroadcastReceiver">
             <intent-filter>
                 <action android:name="com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED" />
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index e77db82..fe785c2 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -887,13 +887,13 @@
     <string name="power_remaining_duration_only_short"><xliff:g id="time">%1$s</xliff:g> left</string>
 
     <!-- [CHAR_LIMIT=100] Label for enhanced estimated time that phone will run out of battery -->
-    <string name="power_discharge_by_enhanced">Will last until about <xliff:g id="time">%1$s</xliff:g> based on your usage (<xliff:g id="level">%2$s</xliff:g>)</string>
+    <string name="power_discharge_by_enhanced">Should last until about <xliff:g id="time">%1$s</xliff:g> based on your usage (<xliff:g id="level">%2$s</xliff:g>)</string>
     <!-- [CHAR_LIMIT=100] Label for enhanced estimated time that phone will run out of battery with no percentage -->
-    <string name="power_discharge_by_only_enhanced">Will last until about <xliff:g id="time">%1$s</xliff:g> based on your usage</string>
+    <string name="power_discharge_by_only_enhanced">Should last until about <xliff:g id="time">%1$s</xliff:g> based on your usage</string>
     <!-- [CHAR_LIMIT=100] Label for estimated time that phone will run out of battery -->
-    <string name="power_discharge_by">Will last until about <xliff:g id="time">%1$s</xliff:g> (<xliff:g id="level">%2$s</xliff:g>)</string>
+    <string name="power_discharge_by">Should last until about <xliff:g id="time">%1$s</xliff:g> (<xliff:g id="level">%2$s</xliff:g>)</string>
     <!-- [CHAR_LIMIT=100] Label for estimated time that phone will run out of battery -->
-    <string name="power_discharge_by_only">Will last until about <xliff:g id="time">%1$s</xliff:g></string>
+    <string name="power_discharge_by_only">Should last until about <xliff:g id="time">%1$s</xliff:g></string>
 
     <!-- [CHAR_LIMIT=60] label for estimated remaining duration of battery when under a certain amount -->
     <string name="power_remaining_less_than_duration_only">Less than <xliff:g id="threshold">%1$s</xliff:g> remaining</string>
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java
index 5758467..c11687b 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java
@@ -40,7 +40,7 @@
     public static final long TEN_MINUTES_MILLIS = Duration.ofMinutes(10).toMillis();
     public static final long THREE_DAYS_MILLIS = Duration.ofDays(3).toMillis();
     public static final long THIRTY_HOURS_MILLIS = Duration.ofHours(30).toMillis();
-    public static final String NORMAL_CASE_EXPECTED_PREFIX = "Will last until about";
+    public static final String NORMAL_CASE_EXPECTED_PREFIX = "Should last until about";
     public static final String ENHANCED_SUFFIX = " based on your usage";
     // matches a time (ex: '1:15 PM', '2 AM')
     public static final String TIME_OF_DAY_REGEX = " (\\d)+:?(\\d)* (AM)|(PM)";
diff --git a/packages/SettingsProvider/res/values-as/defaults.xml b/packages/SettingsProvider/res/values-as/defaults.xml
index ea05c92..1434b59 100644
--- a/packages/SettingsProvider/res/values-as/defaults.xml
+++ b/packages/SettingsProvider/res/values-as/defaults.xml
@@ -24,4 +24,5 @@
     <string name="def_nfc_payment_component" msgid="5861297439873026958"></string>
     <string name="def_backup_manager_constants" msgid="75273734665044867"></string>
     <string name="def_backup_local_transport_parameters" msgid="303005414813191641"></string>
+    <string name="def_backup_agent_timeout_parameters" msgid="8293164064853654150"></string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-or/defaults.xml b/packages/SettingsProvider/res/values-or/defaults.xml
index ea05c92..1434b59 100644
--- a/packages/SettingsProvider/res/values-or/defaults.xml
+++ b/packages/SettingsProvider/res/values-or/defaults.xml
@@ -24,4 +24,5 @@
     <string name="def_nfc_payment_component" msgid="5861297439873026958"></string>
     <string name="def_backup_manager_constants" msgid="75273734665044867"></string>
     <string name="def_backup_local_transport_parameters" msgid="303005414813191641"></string>
+    <string name="def_backup_agent_timeout_parameters" msgid="8293164064853654150"></string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-te/defaults.xml b/packages/SettingsProvider/res/values-te/defaults.xml
index ea05c92..1434b59 100644
--- a/packages/SettingsProvider/res/values-te/defaults.xml
+++ b/packages/SettingsProvider/res/values-te/defaults.xml
@@ -24,4 +24,5 @@
     <string name="def_nfc_payment_component" msgid="5861297439873026958"></string>
     <string name="def_backup_manager_constants" msgid="75273734665044867"></string>
     <string name="def_backup_local_transport_parameters" msgid="303005414813191641"></string>
+    <string name="def_backup_agent_timeout_parameters" msgid="8293164064853654150"></string>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 1db9050..bf3fa29 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2152,8 +2152,14 @@
         been identified for them as running). [CHAR LIMIT=NONE] -->
     <string name="running_foreground_services_msg">Tap for details on battery and data usage</string>
 
-    <!-- Prompt to turn off data usage [CHAR LIMIT=NONE] -->
-    <string name="data_usage_disable_mobile" msgid="8656552431969276305">Turn off mobile data?</string>
+    <!-- Title of the dialog to turn off data usage [CHAR LIMIT=NONE] -->
+    <string name="mobile_data_disable_title">Turn off mobile data?</string>
+
+    <!-- Message body of the dialog to turn off data usage [CHAR LIMIT=NONE] -->
+    <string name="mobile_data_disable_message">You won\’t have access to data or the internet through <xliff:g id="carrier" example="T-Mobile">%s</xliff:g>. Internet will only be available via Wi-Fi.</string>
+
+    <!-- Text used to refer to the user's current carrier in mobile_data_disable_message if the users's mobile network carrier name is not available [CHAR LIMIT=NONE] -->
+    <string name="mobile_data_disable_message_default_carrier">your carrier</string>
 
     <!-- Warning shown when user input has been blocked due to another app overlaying screen
      content. Since we don't know what the app is showing on top of the input target, we
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 396d317..1a9655e 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -52,7 +52,8 @@
             Key.SEEN_MULTI_USER,
             Key.NUM_APPS_LAUNCHED,
             Key.HAS_SEEN_RECENTS_ONBOARDING,
-            Key.SEEN_RINGER_GUIDANCE_COUNT
+            Key.SEEN_RINGER_GUIDANCE_COUNT,
+            Key.QS_HAS_TURNED_OFF_MOBILE_DATA
     })
     public @interface Key {
         @Deprecated
@@ -89,6 +90,7 @@
         String HAS_SEEN_RECENTS_ONBOARDING = "HasSeenRecentsOnboarding";
         String SEEN_RINGER_GUIDANCE_COUNT = "RingerGuidanceCount";
         String QS_TILE_SPECS_REVEALED = "QsTileSpecsRevealed";
+        String QS_HAS_TURNED_OFF_MOBILE_DATA = "QsHasTurnedOffMobileData";
     }
 
     public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index b7a64e1..2abe9d9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.qs.tiles;
 
+import static com.android.systemui.Prefs.Key.QS_HAS_TURNED_OFF_MOBILE_DATA;
+
 import android.app.AlertDialog;
 import android.app.AlertDialog.Builder;
 import android.content.Context;
@@ -34,8 +36,8 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.net.DataUsageController;
 import com.android.systemui.Dependency;
+import com.android.systemui.Prefs;
 import com.android.systemui.R;
-import com.android.systemui.R.string;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.plugins.qs.QSIconView;
@@ -108,7 +110,11 @@
             if (mKeyguardMonitor.isSecure() && !mKeyguardMonitor.canSkipBouncer()) {
                 mActivityStarter.postQSRunnableDismissingKeyguard(this::showDisableDialog);
             } else {
-                mUiHandler.post(this::showDisableDialog);
+                if (Prefs.getBoolean(mContext, QS_HAS_TURNED_OFF_MOBILE_DATA, false)) {
+                    mDataController.setMobileDataEnabled(false);
+                } else {
+                    mUiHandler.post(this::showDisableDialog);
+                }
             }
         } else {
             mDataController.setMobileDataEnabled(true);
@@ -117,12 +123,20 @@
 
     private void showDisableDialog() {
         mHost.collapsePanels();
+        String carrierName = mController.getMobileDataNetworkName();
+        if (TextUtils.isEmpty(carrierName)) {
+            carrierName = mContext.getString(R.string.mobile_data_disable_message_default_carrier);
+        }
         AlertDialog dialog = new Builder(mContext)
-                .setMessage(string.data_usage_disable_mobile)
+                .setTitle(R.string.mobile_data_disable_title)
+                .setMessage(mContext.getString(R.string.mobile_data_disable_message, carrierName))
                 .setNegativeButton(android.R.string.cancel, null)
                 .setPositiveButton(
                         com.android.internal.R.string.alert_windows_notification_turn_off_action,
-                        (d, w) -> mDataController.setMobileDataEnabled(false))
+                        (d, w) -> {
+                            mDataController.setMobileDataEnabled(false);
+                            Prefs.putBoolean(mContext, QS_HAS_TURNED_OFF_MOBILE_DATA, true);
+                        })
                 .create();
         dialog.getWindow().setType(LayoutParams.TYPE_KEYGUARD_DIALOG);
         SystemUIDialog.setShowForAllUsers(dialog, true);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
index 475a609..1807465 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
@@ -107,11 +107,6 @@
     }
 
     @Override
-    public void setBackground(Drawable background) {
-        Log.wtfStack(TAG, "ScrimView should never have a background.");
-    }
-
-    @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
         int densityDpi = newConfig.densityDpi;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
index 1d9cdf7..3bbfe3c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
@@ -77,6 +77,9 @@
 
     public RemoteAnimationAdapter getLaunchAnimation(
             ExpandableNotificationRow sourceNotification) {
+        if (mStatusBar.getBarState() != StatusBarState.SHADE) {
+            return null;
+        }
         AnimationRunner animationRunner = new AnimationRunner(sourceNotification);
         return new RemoteAnimationAdapter(animationRunner, ANIMATION_DURATION,
                 0 /* statusBarTransitionDelay */);
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 91483bc..b493d7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -114,6 +114,7 @@
     private static final boolean DEBUG = false;
     private static final boolean DEBUG_ROTATION = true;
     private static final String EXTRA_DISABLE_STATE = "disabled_state";
+    private static final String EXTRA_DISABLE2_STATE = "disabled2_state";
 
     private final static int BUTTON_FADE_IN_OUT_DURATION_MS = 100;
     private final static int NAVBAR_HIDDEN_PENDING_ICON_TIMEOUT_MS = 20000;
@@ -137,6 +138,7 @@
     private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
 
     private int mDisabledFlags1;
+    private int mDisabledFlags2;
     private StatusBar mStatusBar;
     private Recents mRecents;
     private Divider mDivider;
@@ -212,6 +214,7 @@
 
         if (savedInstanceState != null) {
             mDisabledFlags1 = savedInstanceState.getInt(EXTRA_DISABLE_STATE, 0);
+            mDisabledFlags2 = savedInstanceState.getInt(EXTRA_DISABLE2_STATE, 0);
         }
         mAssistManager = Dependency.get(AssistManager.class);
         mOverviewProxyService = Dependency.get(OverviewProxyService.class);
@@ -277,6 +280,8 @@
         prepareNavigationBarView();
         checkNavBarModes();
 
+        setDisabled2Flags(mDisabledFlags2);
+
         IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
         filter.addAction(Intent.ACTION_SCREEN_ON);
         getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
@@ -296,6 +301,7 @@
     public void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
         outState.putInt(EXTRA_DISABLE_STATE, mDisabledFlags1);
+        outState.putInt(EXTRA_DISABLE2_STATE, mDisabledFlags2);
         if (mNavigationBarView != null) {
             mNavigationBarView.getLightTransitionsController().saveState(outState);
         }
@@ -398,15 +404,20 @@
     @Override
     public void onRotationProposal(final int rotation, boolean isValid) {
         final int winRotation = mWindowManager.getDefaultDisplay().getRotation();
+        final boolean rotateSuggestionsDisabled = hasDisable2RotateSuggestionFlag(mDisabledFlags2);
         if (DEBUG_ROTATION) {
             Log.v(TAG, "onRotationProposal proposedRotation=" + Surface.rotationToString(rotation)
                     + ", winRotation=" + Surface.rotationToString(winRotation)
                     + ", isValid=" + isValid + ", mNavBarWindowState="
                     + StatusBarManager.windowStateToString(mNavigationBarWindowState)
+                    + ", rotateSuggestionsDisabled=" + rotateSuggestionsDisabled
                     + ", isRotateButtonVisible=" + (mNavigationBarView == null ? "null" :
                         mNavigationBarView.isRotateButtonVisible()));
         }
 
+        // Respect the disabled flag, no need for action as flag change callback will handle hiding
+        if (rotateSuggestionsDisabled) return;
+
         // This method will be called on rotation suggestion changes even if the proposed rotation
         // is not valid for the top app. Use invalid rotation choices as a signal to remove the
         // rotate button if shown.
@@ -450,6 +461,12 @@
         }
     }
 
+    private void onRotationSuggestionsDisabled() {
+        // Immediately hide the rotate button and clear any planned removal
+        setRotateSuggestionButtonState(false, true);
+        getView().removeCallbacks(mRemoveRotationProposal);
+    }
+
     private void showAndLogRotationSuggestion() {
         setRotateSuggestionButtonState(true);
         rescheduleRotationTimeout(false);
@@ -643,8 +660,8 @@
 
     @Override
     public void disable(int state1, int state2, boolean animate) {
-        // All navigation bar flags are in state1.
-        int masked = state1 & (StatusBarManager.DISABLE_HOME
+        // Navigation bar flags are in both state1 and state2.
+        final int masked = state1 & (StatusBarManager.DISABLE_HOME
                 | StatusBarManager.DISABLE_RECENT
                 | StatusBarManager.DISABLE_BACK
                 | StatusBarManager.DISABLE_SEARCH);
@@ -653,6 +670,22 @@
             if (mNavigationBarView != null) mNavigationBarView.setDisabledFlags(state1);
             updateScreenPinningGestures();
         }
+
+        final int masked2 = state2 & (StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS);
+        if (masked2 != mDisabledFlags2) {
+            mDisabledFlags2 = masked2;
+            setDisabled2Flags(masked2);
+        }
+    }
+
+    private void setDisabled2Flags(int state2) {
+        // Method only called on change of disable2 flags
+        final boolean rotateSuggestionsDisabled = hasDisable2RotateSuggestionFlag(state2);
+        if (rotateSuggestionsDisabled) onRotationSuggestionsDisabled();
+    }
+
+    private boolean hasDisable2RotateSuggestionFlag(int disable2Flags) {
+        return (disable2Flags & StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS) != 0;
     }
 
     // ----- Internal stuffz -----
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 a09b84f..ae55ae8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -239,6 +239,11 @@
         mCurrentBehindAlpha = state.getBehindAlpha(mNotificationDensity);
         applyExpansionToAlpha();
 
+        // Scrim might acquire focus when user is navigating with a D-pad or a keyboard.
+        // We need to disable focus otherwise AOD would end up with a gray overlay.
+        mScrimInFront.setFocusable(!state.isLowPowerState());
+        mScrimBehind.setFocusable(!state.isLowPowerState());
+
         // Cancel blanking transitions that were pending before we requested a new state
         if (mPendingFrameCallback != null) {
             Choreographer.getInstance().removeFrameCallback(mPendingFrameCallback);
@@ -257,7 +262,7 @@
         // the animation plays properly until the last frame.
         // It's important to avoid holding the wakelock unless necessary because
         // WakeLock#aqcuire will trigger an IPC and will cause jank.
-        if (mState == ScrimState.AOD) {
+        if (mState.isLowPowerState()) {
             holdWakeLock();
         }
 
@@ -528,7 +533,7 @@
             scrim.setClickable(false);
         } else {
             // Eat touch events (unless dozing).
-            scrim.setClickable(!(mState == ScrimState.AOD));
+            scrim.setClickable(!mState.isLowPowerState());
         }
         updateScrim(scrim, alpha);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index a14d056..55e8714 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -116,6 +116,11 @@
             // to set our state.
             mAnimateChange = mCanControlScreenOff;
         }
+
+        @Override
+        public boolean isLowPowerState() {
+            return true;
+        }
     },
 
     /**
@@ -250,4 +255,8 @@
     public void setWallpaperSupportsAmbientMode(boolean wallpaperSupportsAmbientMode) {
         mWallpaperSupportsAmbientMode = wallpaperSupportsAmbientMode;
     }
+
+    public boolean isLowPowerState() {
+        return false;
+    }
 }
\ No newline at end of file
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 120122f..5bc45cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -5044,8 +5044,11 @@
                     RemoteAnimationAdapter adapter = mActivityLaunchAnimator.getLaunchAnimation(
                             row);
                     try {
-                        ActivityManager.getService().registerRemoteAnimationForNextActivityStart(
-                                intent.getCreatorPackage(), adapter);
+                        if (adapter != null) {
+                            ActivityManager.getService()
+                                    .registerRemoteAnimationForNextActivityStart(
+                                            intent.getCreatorPackage(), adapter);
+                        }
                         launchResult = intent.sendAndReturnResult(mContext, 0, fillInIntent, null,
                                 null, null, getActivityOptions(adapter));
                         mActivityLaunchAnimator.setLaunchResult(launchResult);
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 9eee906..76e3ad7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -36,6 +36,7 @@
     AccessPointController getAccessPointController();
     DataUsageController getMobileDataController();
     DataSaverController getDataSaverController();
+    String getMobileDataNetworkName();
 
     boolean hasVoiceCallingFeature();
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 2258fa2..779b0fb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -308,6 +308,7 @@
         return mDefaultSignalController;
     }
 
+    @Override
     public String getMobileDataNetworkName() {
         MobileSignalController controller = getDataController();
         return controller != null ? controller.getState().networkNameData : "";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TintedKeyButtonDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TintedKeyButtonDrawable.java
index 56f6726..0616ffc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TintedKeyButtonDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TintedKeyButtonDrawable.java
@@ -63,7 +63,7 @@
     }
 
     public boolean isDarkIntensitySet() {
-        return mDarkIntensity == DARK_INTENSITY_NOT_SET;
+        return mDarkIntensity != DARK_INTENSITY_NOT_SET;
     }
 
     public float getDarkIntensity() {
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 df29e1f..f088c0b 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
@@ -42,6 +42,7 @@
 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;
@@ -463,6 +464,17 @@
                 mHeadsUpScrim.getAlpha(), 0.01f);
     }
 
+    @Test
+    public void testScrimFocus() {
+        mScrimController.transitionTo(ScrimState.AOD);
+        Assert.assertFalse("Should not be focusable on AOD", mScrimBehind.isFocusable());
+        Assert.assertFalse("Should not be focusable on AOD", mScrimInFront.isFocusable());
+
+        mScrimController.transitionTo(ScrimState.KEYGUARD);
+        Assert.assertTrue("Should be focusable on keyguard", mScrimBehind.isFocusable());
+        Assert.assertTrue("Should be focusable on keyguard", mScrimInFront.isFocusable());
+    }
+
     /**
      * Conserves old notification density after leaving state and coming back.
      *
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java
index 64fe8dd..5385f6d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java
@@ -88,4 +88,9 @@
     public void dispatchDemoCommand(String command, Bundle args) {
 
     }
+
+    @Override
+    public String getMobileDataNetworkName() {
+        return "";
+    }
 }
diff --git a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-en-rAU/strings.xml b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..1058832
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-en-rAU/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="4967302169856689448">"Corner display cut out"</string>
+</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-en-rCA/strings.xml b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..1058832
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-en-rCA/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="4967302169856689448">"Corner display cut out"</string>
+</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-en-rGB/strings.xml b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..1058832
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-en-rGB/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="4967302169856689448">"Corner display cut out"</string>
+</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-en-rIN/strings.xml b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..1058832
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-en-rIN/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="4967302169856689448">"Corner display cut out"</string>
+</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-en-rXC/strings.xml b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..bdd497a
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-en-rXC/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="4967302169856689448">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‏‎‏‏‏‏‎‏‏‎‎‏‏‏‎‎‎‎‎‎‎‏‎‏‏‎‏‏‏‎‎‏‎‏‎‏‎‏‏‏‎‎‎‏‎‏‎‎‏‎‏‎‎‎‎Corner display cutout‎‏‎‎‏‎"</string>
+</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-my/strings.xml b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-my/strings.xml
new file mode 100644
index 0000000..c56ea8b
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-my/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="4967302169856689448">"မျက်နှာပြင်ထောင့် ဖြတ်ညှပ်ပြသမှု"</string>
+</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-iw/strings.xml b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-iw/strings.xml
new file mode 100644
index 0000000..eff8a8d
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-iw/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="5659433562878674546">"חיתוך תצוגה כפול"</string>
+</resources>
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 04d46aa..063c1f1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -110,6 +110,7 @@
 import static android.os.Process.setThreadScheduler;
 import static android.os.Process.startWebView;
 import static android.os.Process.zygoteProcess;
+import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
 import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
 import static android.provider.Settings.Global.DEBUG_APP;
 import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
@@ -737,6 +738,13 @@
     private ActivityRecord mLastResumedActivity;
 
     /**
+     * The activity that is currently being traced as the active resumed activity.
+     *
+     * @see #updateResumedAppTrace
+     */
+    private @Nullable ActivityRecord mTracedResumedActivity;
+
+    /**
      * If non-null, we are tracking the time the user spends in the currently focused app.
      */
     private AppTimeTracker mCurAppTimeTracker;
@@ -3423,6 +3431,7 @@
         if (mLastResumedActivity != null && r.userId != mLastResumedActivity.userId) {
             mUserController.sendForegroundProfileChanged(r.userId);
         }
+        updateResumedAppTrace(r);
         mLastResumedActivity = r;
 
         mWindowManager.setFocusedApp(r.appToken, true);
@@ -3436,6 +3445,22 @@
                 reason);
     }
 
+    private void updateResumedAppTrace(@Nullable ActivityRecord resumed) {
+        if (mTracedResumedActivity != null) {
+            Trace.asyncTraceEnd(TRACE_TAG_ACTIVITY_MANAGER,
+                    constructResumedTraceName(mTracedResumedActivity.packageName), 0);
+        }
+        if (resumed != null) {
+            Trace.asyncTraceBegin(TRACE_TAG_ACTIVITY_MANAGER,
+                    constructResumedTraceName(resumed.packageName), 0);
+        }
+        mTracedResumedActivity = resumed;
+    }
+
+    private String constructResumedTraceName(String packageName) {
+        return "focused app: " + packageName;
+    }
+
     @Override
     public void setFocusedStack(int stackId) {
         enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "setFocusedStack()");
@@ -7575,6 +7600,9 @@
 
             if (profilerInfo != null && profilerInfo.profileFd != null) {
                 profilerInfo.profileFd = profilerInfo.profileFd.dup();
+                if (TextUtils.equals(mProfileApp, processName) && mProfilerInfo != null) {
+                    clearProfilerLocked();
+                }
             }
 
             // We deprecated Build.SERIAL and it is not accessible to
@@ -7659,7 +7687,10 @@
                         mCoreSettingsObserver.getCoreSettingsLocked(),
                         buildSerial, isAutofillCompatEnabled);
             }
-
+            if (profilerInfo != null) {
+                profilerInfo.closeFd();
+                profilerInfo = null;
+            }
             checkTime(startTime, "attachApplicationLocked: immediately after bindApplication");
             updateLruProcessLocked(app, false, null);
             checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked");
@@ -13073,6 +13104,7 @@
             }
             mTopProcessState = ActivityManager.PROCESS_STATE_TOP_SLEEPING;
             mStackSupervisor.goingToSleepLocked();
+            updateResumedAppTrace(null /* resumed */);
             updateOomAdjLocked();
         }
     }
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 352b7570..724dd3f 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -299,7 +299,7 @@
 
         final boolean otherWindowModesLaunching =
                 mWindowingModeTransitionInfo.size() > 0 && info == null;
-        if ((resultCode < 0 || launchedActivity == null || !processSwitch
+        if ((!isLoggableResultCode(resultCode) || launchedActivity == null || !processSwitch
                 || windowingMode == WINDOWING_MODE_UNDEFINED) && !otherWindowModesLaunching) {
 
             // Failed to launch or it was not a process switch, so we don't care about the timing.
@@ -322,6 +322,14 @@
     }
 
     /**
+     * @return True if we should start logging an event for an activity start that returned
+     *         {@code resultCode} and that we'll indeed get a windows drawn event.
+     */
+    private boolean isLoggableResultCode(int resultCode) {
+        return resultCode == START_SUCCESS || resultCode == START_TASK_TO_FRONT;
+    }
+
+    /**
      * Notifies the tracker that all windows of the app have been drawn.
      */
     void notifyWindowsDrawn(int windowingMode, long timestamp) {
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 8c49472..68c47d5 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -1193,6 +1193,9 @@
     }
 
     boolean isFocusable() {
+        if (inSplitScreenPrimaryWindowingMode() && mStackSupervisor.mIsDockMinimized) {
+            return false;
+        }
         return getWindowConfiguration().canReceiveKeys() || isAlwaysFocusable();
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 8f987be..6101420 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -3420,7 +3420,7 @@
     }
 
     /** Find next proper focusable stack and make it focused. */
-    private boolean adjustFocusToNextFocusableStack(String reason) {
+    boolean adjustFocusToNextFocusableStack(String reason) {
         return adjustFocusToNextFocusableStack(reason, false /* allowFocusSelf */);
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index efc0d7d..be826f7 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2455,19 +2455,20 @@
 
                 if (currentWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
                         && candidate == null && stack.inSplitScreenPrimaryWindowingMode()) {
-                    // If the currently focused stack is in split-screen secondary we would prefer
-                    // the focus to move to another split-screen secondary stack or fullscreen stack
-                    // over the primary split screen stack to avoid:
-                    // - Moving the focus to the primary split-screen stack when it can't be focused
-                    //   because it will be minimized, but AM doesn't know that yet
-                    // - primary split-screen stack overlapping with a fullscreen stack when a
-                    //   fullscreen stack is higher in z than the next split-screen stack. Assistant
-                    //   stack, I am looking at you...
+                    // If the currently focused stack is in split-screen secondary we save off the
+                    // top primary split-screen stack as a candidate for focus because we might
+                    // prefer focus to move to an other stack to avoid primary split-screen stack
+                    // overlapping with a fullscreen stack when a fullscreen stack is higher in z
+                    // than the next split-screen stack. Assistant stack, I am looking at you...
                     // We only move the focus to the primary-split screen stack if there isn't a
                     // better alternative.
                     candidate = stack;
                     continue;
                 }
+                if (candidate != null && stack.inSplitScreenSecondaryWindowingMode()) {
+                    // Use the candidate stack since we are now at the secondary split-screen.
+                    return candidate;
+                }
                 return stack;
             }
         }
@@ -4413,6 +4414,14 @@
 
     void setDockedStackMinimized(boolean minimized) {
         mIsDockMinimized = minimized;
+        if (mIsDockMinimized) {
+            final ActivityStack current = getFocusedStack();
+            if (current.inSplitScreenPrimaryWindowingMode()) {
+                // The primary split-screen stack can't be focused while it is minimize, so move
+                // focus to something else.
+                current.adjustFocusToNextFocusableStack("setDockedStackMinimized");
+            }
+        }
     }
 
     void wakeUp(String reason) {
diff --git a/services/core/java/com/android/server/am/RecentsAnimation.java b/services/core/java/com/android/server/am/RecentsAnimation.java
index 9121568..da56ffd 100644
--- a/services/core/java/com/android/server/am/RecentsAnimation.java
+++ b/services/core/java/com/android/server/am/RecentsAnimation.java
@@ -16,6 +16,7 @@
 
 package com.android.server.am;
 
+import static android.app.ActivityManager.START_TASK_TO_FRONT;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
@@ -95,6 +96,8 @@
             }
         }
 
+        mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching();
+
         mService.setRunningRemoteAnimation(mCallingPid, true);
 
         mWindowManager.deferSurfaceLayout();
@@ -143,6 +146,9 @@
             // If we updated the launch-behind state, update the visibility of the activities after
             // we fetch the visible tasks to be controlled by the animation
             mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS);
+
+            mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunched(START_TASK_TO_FRONT,
+                    homeActivity);
         } finally {
             mWindowManager.continueSurfaceLayout();
             Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 59fce64..0678d08 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -629,7 +629,7 @@
      */
     @Override
     public void disable2ForUser(int what, IBinder token, String pkg, int userId) {
-        enforceStatusBarService();
+        enforceStatusBar();
 
         synchronized (mLock) {
             disableLocked(userId, what, token, pkg, 2);
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index 1170148..1575694 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -617,7 +617,8 @@
 
             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Schedule remove starting " + mContainer
                     + " startingWindow=" + mContainer.startingWindow
-                    + " startingView=" + mContainer.startingSurface);
+                    + " startingView=" + mContainer.startingSurface
+                    + " Callers=" + Debug.getCallers(5));
 
             // Use the same thread to remove the window as we used to add it, as otherwise we end up
             // with things in the view hierarchy being called from different threads.
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 1f71b8f..88cb54d 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -2079,6 +2079,13 @@
         super.prepareSurfaces();
     }
 
+    /**
+     * @return Whether our {@link #getSurfaceControl} is currently showing.
+     */
+    boolean isSurfaceShowing() {
+        return mLastSurfaceShowing;
+    }
+
     boolean isFreezingScreen() {
         return mFreezingScreen;
     }
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 0b0df6f..3e72a71 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -16,13 +16,16 @@
 
 package com.android.server.wm;
 
+import static android.app.ActivityManagerInternal.APP_TRANSITION_RECENTS_ANIM;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.view.RemoteAnimationTarget.MODE_CLOSING;
 import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.H.NOTIFY_APP_TRANSITION_STARTING;
 import static com.android.server.wm.proto.RemoteAnimationAdapterWrapperProto.TARGET;
 import static com.android.server.wm.proto.AnimationAdapterProto.REMOTE;
 
@@ -37,6 +40,7 @@
 import android.util.Log;
 import android.util.Slog;import android.util.proto.ProtoOutputStream;
 import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
 import android.util.proto.ProtoOutputStream;
 import android.view.IRecentsAnimationController;
 import android.view.IRecentsAnimationRunner;
@@ -279,6 +283,10 @@
         } catch (RemoteException e) {
             Slog.e(TAG, "Failed to start recents animation", e);
         }
+        final SparseIntArray reasons = new SparseIntArray();
+        reasons.put(WINDOWING_MODE_FULLSCREEN, APP_TRANSITION_RECENTS_ANIM);
+        mService.mH.obtainMessage(NOTIFY_APP_TRANSITION_STARTING,
+                reasons).sendToTarget();
     }
 
     void cancelAnimation() {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 9310dc4..970a8d7 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -247,7 +247,8 @@
                 // Ensure at least one window for the top app is visible before attempting to take
                 // a screenshot. Visible here means that the WSA surface is shown and has an alpha
                 // greater than 0.
-                ws -> ws.mWinAnimator != null && ws.mWinAnimator.getShown()
+                ws -> (ws.mAppToken == null || ws.mAppToken.isSurfaceShowing())
+                        && ws.mWinAnimator != null && ws.mWinAnimator.getShown()
                         && ws.mWinAnimator.mLastAlpha > 0f, true);
 
         if (!hasVisibleChild) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index c7ae570..5a3b268 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -566,7 +566,7 @@
         @NonNull PasswordMetrics mActivePasswordMetrics = new PasswordMetrics();
         int mFailedPasswordAttempts = 0;
         boolean mPasswordStateHasBeenSetSinceBoot = false;
-        boolean mPasswordValidAtLastCheckpoint = false;
+        boolean mPasswordValidAtLastCheckpoint = true;
 
         int mUserHandle;
         int mPasswordOwner = -1;
@@ -3887,23 +3887,28 @@
             final PasswordMetrics metrics = ap.minimumPasswordMetrics;
             if (metrics.quality != quality) {
                 metrics.quality = quality;
-                updatePasswordValidityCheckpointLocked(userId);
-                saveSettingsLocked(userId);
+                updatePasswordValidityCheckpointLocked(userId, parent);
             }
             maybeLogPasswordComplexitySet(who, userId, parent, metrics);
         }
     }
 
     /**
-     * Updates flag in memory that tells us whether the user's password currently satisfies the
-     * requirements set by all of the user's active admins.  This should be called before
-     * {@link #saveSettingsLocked} whenever the password or the admin policies have changed.
+     * Updates a flag that tells us whether the user's password currently satisfies the
+     * requirements set by all of the user's active admins. The flag is updated both in memory
+     * and persisted to disk by calling {@link #saveSettingsLocked}, for the value of the flag
+     * be the correct one upon boot.
+     * This should be called whenever the password or the admin policies have changed.
      */
     @GuardedBy("DevicePolicyManagerService.this")
-    private void updatePasswordValidityCheckpointLocked(int userHandle) {
-        DevicePolicyData policy = getUserData(userHandle);
-        policy.mPasswordValidAtLastCheckpoint = isActivePasswordSufficientForUserLocked(
-                policy, policy.mUserHandle, false);
+    private void updatePasswordValidityCheckpointLocked(int userHandle, boolean parent) {
+        final int credentialOwner = getCredentialOwner(userHandle, parent);
+        DevicePolicyData policy = getUserData(credentialOwner);
+        policy.mPasswordValidAtLastCheckpoint =
+                isPasswordSufficientForUserWithoutCheckpointLocked(
+                        policy.mActivePasswordMetrics, userHandle, parent);
+
+        saveSettingsLocked(credentialOwner);
     }
 
     @Override
@@ -3990,8 +3995,7 @@
             final PasswordMetrics metrics = ap.minimumPasswordMetrics;
             if (metrics.length != length) {
                 metrics.length = length;
-                updatePasswordValidityCheckpointLocked(userId);
-                saveSettingsLocked(userId);
+                updatePasswordValidityCheckpointLocked(userId, parent);
             }
             maybeLogPasswordComplexitySet(who, userId, parent, metrics);
         }
@@ -4015,8 +4019,7 @@
                     who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
             if (ap.passwordHistoryLength != length) {
                 ap.passwordHistoryLength = length;
-                updatePasswordValidityCheckpointLocked(userId);
-                saveSettingsLocked(userId);
+                updatePasswordValidityCheckpointLocked(userId, parent);
             }
         }
         if (SecurityLog.isLoggingEnabled()) {
@@ -4217,8 +4220,7 @@
             final PasswordMetrics metrics = ap.minimumPasswordMetrics;
             if (metrics.upperCase != length) {
                 metrics.upperCase = length;
-                updatePasswordValidityCheckpointLocked(userId);
-                saveSettingsLocked(userId);
+                updatePasswordValidityCheckpointLocked(userId, parent);
             }
             maybeLogPasswordComplexitySet(who, userId, parent, metrics);
         }
@@ -4240,8 +4242,7 @@
             final PasswordMetrics metrics = ap.minimumPasswordMetrics;
             if (metrics.lowerCase != length) {
                 metrics.lowerCase = length;
-                updatePasswordValidityCheckpointLocked(userId);
-                saveSettingsLocked(userId);
+                updatePasswordValidityCheckpointLocked(userId, parent);
             }
             maybeLogPasswordComplexitySet(who, userId, parent, metrics);
         }
@@ -4266,8 +4267,7 @@
             final PasswordMetrics metrics = ap.minimumPasswordMetrics;
             if (metrics.letters != length) {
                 metrics.letters = length;
-                updatePasswordValidityCheckpointLocked(userId);
-                saveSettingsLocked(userId);
+                updatePasswordValidityCheckpointLocked(userId, parent);
             }
             maybeLogPasswordComplexitySet(who, userId, parent, metrics);
         }
@@ -4292,8 +4292,7 @@
             final PasswordMetrics metrics = ap.minimumPasswordMetrics;
             if (metrics.numeric != length) {
                 metrics.numeric = length;
-                updatePasswordValidityCheckpointLocked(userId);
-                saveSettingsLocked(userId);
+                updatePasswordValidityCheckpointLocked(userId, parent);
             }
             maybeLogPasswordComplexitySet(who, userId, parent, metrics);
         }
@@ -4318,8 +4317,7 @@
             final PasswordMetrics metrics = ap.minimumPasswordMetrics;
             if (metrics.symbols != length) {
                 ap.minimumPasswordMetrics.symbols = length;
-                updatePasswordValidityCheckpointLocked(userId);
-                saveSettingsLocked(userId);
+                updatePasswordValidityCheckpointLocked(userId, parent);
             }
             maybeLogPasswordComplexitySet(who, userId, parent, metrics);
         }
@@ -4344,8 +4342,7 @@
             final PasswordMetrics metrics = ap.minimumPasswordMetrics;
             if (metrics.nonLetter != length) {
                 ap.minimumPasswordMetrics.nonLetter = length;
-                updatePasswordValidityCheckpointLocked(userId);
-                saveSettingsLocked(userId);
+                updatePasswordValidityCheckpointLocked(userId, parent);
             }
             maybeLogPasswordComplexitySet(who, userId, parent, metrics);
         }
@@ -4566,16 +4563,6 @@
 
     private boolean isActivePasswordSufficientForUserLocked(
             DevicePolicyData policy, int userHandle, boolean parent) {
-        final int requiredPasswordQuality = getPasswordQuality(null, userHandle, parent);
-        if (requiredPasswordQuality == PASSWORD_QUALITY_UNSPECIFIED) {
-            // A special case is when there is no required password quality, then we just return
-            // true since any password would be sufficient. This is for the scenario when a work
-            // profile is first created so there is no information about the current password but
-            // it should be considered sufficient as there is no password requirement either.
-            // This is useful since it short-circuits the password checkpoint for FDE device below.
-            return true;
-        }
-
         if (!mInjector.storageManagerIsFileBasedEncryptionEnabled()
                 && !policy.mPasswordStateHasBeenSetSinceBoot) {
             // Before user enters their password for the first time after a reboot, return the
@@ -4586,28 +4573,41 @@
             return policy.mPasswordValidAtLastCheckpoint;
         }
 
-        if (policy.mActivePasswordMetrics.quality < requiredPasswordQuality) {
+        return isPasswordSufficientForUserWithoutCheckpointLocked(
+                policy.mActivePasswordMetrics, userHandle, parent);
+    }
+
+    /**
+     * Returns {@code true} if the password represented by the {@code passwordMetrics} argument
+     * sufficiently fulfills the password requirements for the user corresponding to
+     * {@code userHandle} (or its parent, if {@code parent} is set to {@code true}).
+     */
+    private boolean isPasswordSufficientForUserWithoutCheckpointLocked(
+            PasswordMetrics passwordMetrics, int userHandle, boolean parent) {
+        final int requiredPasswordQuality = getPasswordQuality(null, userHandle, parent);
+
+        if (passwordMetrics.quality < requiredPasswordQuality) {
             return false;
         }
         if (requiredPasswordQuality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
-                && policy.mActivePasswordMetrics.length < getPasswordMinimumLength(
+                && passwordMetrics.length < getPasswordMinimumLength(
                         null, userHandle, parent)) {
             return false;
         }
         if (requiredPasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
             return true;
         }
-        return policy.mActivePasswordMetrics.upperCase >= getPasswordMinimumUpperCase(
+        return passwordMetrics.upperCase >= getPasswordMinimumUpperCase(
                     null, userHandle, parent)
-                && policy.mActivePasswordMetrics.lowerCase >= getPasswordMinimumLowerCase(
+                && passwordMetrics.lowerCase >= getPasswordMinimumLowerCase(
                         null, userHandle, parent)
-                && policy.mActivePasswordMetrics.letters >= getPasswordMinimumLetters(
+                && passwordMetrics.letters >= getPasswordMinimumLetters(
                         null, userHandle, parent)
-                && policy.mActivePasswordMetrics.numeric >= getPasswordMinimumNumeric(
+                && passwordMetrics.numeric >= getPasswordMinimumNumeric(
                         null, userHandle, parent)
-                && policy.mActivePasswordMetrics.symbols >= getPasswordMinimumSymbols(
+                && passwordMetrics.symbols >= getPasswordMinimumSymbols(
                         null, userHandle, parent)
-                && policy.mActivePasswordMetrics.nonLetter >= getPasswordMinimumNonLetter(
+                && passwordMetrics.nonLetter >= getPasswordMinimumNonLetter(
                         null, userHandle, parent);
     }
 
@@ -6148,8 +6148,7 @@
         try {
             synchronized (this) {
                 policy.mFailedPasswordAttempts = 0;
-                updatePasswordValidityCheckpointLocked(userId);
-                saveSettingsLocked(userId);
+                updatePasswordValidityCheckpointLocked(userId, /* parent */ false);
                 updatePasswordExpirationsLocked(userId);
                 setExpirationAlarmCheckLocked(mContext, userId, /* parent */ false);
 
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
index 92ea766..17e5832 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
@@ -22,6 +22,7 @@
 
 import android.content.ComponentName;
 import android.content.Intent;
+import android.os.BaseBundle;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.util.ArraySet;
@@ -92,7 +93,10 @@
             public boolean matches(Object item) {
                 if (item == null) return false;
                 if (!intent.filterEquals((Intent) item)) return false;
-                return intent.getExtras().kindofEquals(((Intent) item).getExtras());
+                BaseBundle extras = intent.getExtras();
+                BaseBundle itemExtras = ((Intent) item).getExtras();
+                return (extras == itemExtras) || (extras != null &&
+                        extras.kindofEquals(itemExtras));
             }
             @Override
             public void describeTo(Description description) {
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 ccde049..4f49a4a 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -33,7 +33,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import android.support.test.filters.FlakyTest;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -302,7 +301,6 @@
     }
 
     @Test
-    @FlakyTest(bugId = 37908381)
     public void testFocusedWindowMultipleDisplays() throws Exception {
         // Create a focusable window and check that focus is calculated correctly
         final WindowState window1 =
diff --git a/services/tests/uiservicestests/AndroidManifest.xml b/services/tests/uiservicestests/AndroidManifest.xml
index fc459a0..4c70466 100644
--- a/services/tests/uiservicestests/AndroidManifest.xml
+++ b/services/tests/uiservicestests/AndroidManifest.xml
@@ -27,6 +27,7 @@
     <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
     <uses-permission android:name="android.permission.ACCESS_VOICE_INTERACTION_SERVICE" />
     <uses-permission android:name="android.permission.DEVICE_POWER" />
+    <uses-permission android:name="android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY" />
 
     <application android:debuggable="true">
         <uses-library android:name="android.test.runner" />