Merge "KeyChain: Provide public & private keys"
diff --git a/Android.mk b/Android.mk
index f4a9ff9..7a3c46d 100644
--- a/Android.mk
+++ b/Android.mk
@@ -559,6 +559,7 @@
 	wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \
 	wifi/java/android/net/wifi/rtt/IRttCallback.aidl \
 	wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl \
+	wifi/java/android/net/wifi/hotspot2/IProvisioningCallback.aidl \
 	wifi/java/android/net/wifi/IWifiScanner.aidl \
 	wifi/java/android/net/wifi/IRttManager.aidl \
 	packages/services/PacProcessor/com/android/net/IProxyService.aidl \
@@ -694,6 +695,7 @@
 	frameworks/base/telephony/java/android/telephony/NeighboringCellInfo.aidl \
 	frameworks/base/telephony/java/android/telephony/ModemActivityInfo.aidl \
 	frameworks/base/telephony/java/android/telephony/UiccAccessRule.aidl \
+	frameworks/base/telephony/java/android/telephony/data/DataProfile.aidl \
 	frameworks/base/telephony/java/android/telephony/euicc/DownloadableSubscription.aidl \
 	frameworks/base/telephony/java/android/telephony/euicc/EuiccInfo.aidl \
 	frameworks/base/location/java/android/location/Location.aidl \
@@ -913,7 +915,7 @@
 # Search through the base framework dirs for these packages.
 # The result will be relative to frameworks/base.
 fwbase_dirs_to_document := \
-	legacy-test/src \
+	test-base/src \
 	$(patsubst $(LOCAL_PATH)/%,%, \
 	  $(wildcard \
 	    $(foreach dir, $(FRAMEWORKS_BASE_JAVA_SRC_DIRS), \
@@ -1027,7 +1029,9 @@
     -knowntags ./frameworks/base/docs/knowntags.txt \
     -knowntags ./libcore/known_oj_tags.txt \
     -manifest ./frameworks/base/core/res/AndroidManifest.xml \
+    -hidePackage com.android.okhttp \
     -hidePackage com.android.org.conscrypt \
+    -hidePackage com.android.server \
     -since $(SRC_API_DIR)/1.xml 1 \
     -since $(SRC_API_DIR)/2.xml 2 \
     -since $(SRC_API_DIR)/3.xml 3 \
@@ -1055,7 +1059,7 @@
     -since $(SRC_API_DIR)/25.txt 25 \
     -since $(SRC_API_DIR)/26.txt 26 \
     -since $(SRC_API_DIR)/27.txt 27 \
-    -werror -lerror -hide 111 -hide 113 -hide 121 -hide 125 -hide 126 -hide 127 -hide 128 \
+    -werror -lerror -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 \
     -overview $(LOCAL_PATH)/core/java/overview.html \
 
 framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR:= \
@@ -1561,7 +1565,8 @@
     tools/streaming_proto/stream.proto \
     cmds/am/proto/instrumentation_data.proto \
     $(call all-proto-files-under, core/proto) \
-    $(call all-proto-files-under, libs/incident/proto)
+    $(call all-proto-files-under, libs/incident/proto) \
+    $(call all-proto-files-under, cmds/statsd/src)
 include $(BUILD_HOST_JAVA_LIBRARY)
 
 # ====  java proto device library (for test only)  ==============================
diff --git a/api/current.txt b/api/current.txt
index f6b5cd5..f6f74af 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1119,6 +1119,7 @@
     field public static final int scheme = 16842791; // 0x1010027
     field public static final int screenDensity = 16843467; // 0x10102cb
     field public static final int screenOrientation = 16842782; // 0x101001e
+    field public static final int screenReaderFocusable = 16844148; // 0x1010574
     field public static final int screenSize = 16843466; // 0x10102ca
     field public static final int scrollHorizontally = 16843099; // 0x101015b
     field public static final int scrollIndicators = 16844006; // 0x10104e6
@@ -6588,6 +6589,7 @@
 
   public abstract class NetworkEvent implements android.os.Parcelable {
     method public int describeContents();
+    method public long getId();
     method public java.lang.String getPackageName();
     method public long getTimestamp();
     field public static final android.os.Parcelable.Creator<android.app.admin.NetworkEvent> CREATOR;
@@ -37499,6 +37501,7 @@
   public final class SaveCallback {
     method public void onFailure(java.lang.CharSequence);
     method public void onSuccess();
+    method public void onSuccess(android.content.IntentSender);
   }
 
   public final class SaveInfo implements android.os.Parcelable {
@@ -37555,6 +37558,7 @@
 
   public final class Validators {
     method public static android.service.autofill.Validator and(android.service.autofill.Validator...);
+    method public static android.service.autofill.Validator not(android.service.autofill.Validator);
     method public static android.service.autofill.Validator or(android.service.autofill.Validator...);
   }
 
@@ -41768,8 +41772,6 @@
   public deprecated class TestSuiteBuilder {
     ctor public TestSuiteBuilder(java.lang.Class);
     ctor public TestSuiteBuilder(java.lang.String, java.lang.ClassLoader);
-    method public android.test.suitebuilder.TestSuiteBuilder addRequirements(java.util.List<com.android.internal.util.Predicate<android.test.suitebuilder.TestMethod>>);
-    method public final android.test.suitebuilder.TestSuiteBuilder addRequirements(com.android.internal.util.Predicate<android.test.suitebuilder.TestMethod>...);
     method public final junit.framework.TestSuite build();
     method public android.test.suitebuilder.TestSuiteBuilder excludePackages(java.lang.String...);
     method protected java.lang.String getSuiteName();
@@ -46330,6 +46332,7 @@
     method public boolean isPressed();
     method public boolean isSaveEnabled();
     method public boolean isSaveFromParentEnabled();
+    method public boolean isScreenReaderFocusable();
     method public boolean isScrollContainer();
     method public boolean isScrollbarFadingEnabled();
     method public boolean isSelected();
@@ -46549,6 +46552,7 @@
     method public void setSaveFromParentEnabled(boolean);
     method public void setScaleX(float);
     method public void setScaleY(float);
+    method public void setScreenReaderFocusable(boolean);
     method public void setScrollBarDefaultDelayBeforeFade(int);
     method public void setScrollBarFadeDuration(int);
     method public void setScrollBarSize(int);
@@ -47967,6 +47971,7 @@
     method public boolean isLongClickable();
     method public boolean isMultiLine();
     method public boolean isPassword();
+    method public boolean isScreenReaderFocusable();
     method public boolean isScrollable();
     method public boolean isSelected();
     method public boolean isShowingHintText();
@@ -48022,6 +48027,7 @@
     method public void setParent(android.view.View, int);
     method public void setPassword(boolean);
     method public void setRangeInfo(android.view.accessibility.AccessibilityNodeInfo.RangeInfo);
+    method public void setScreenReaderFocusable(boolean);
     method public void setScrollable(boolean);
     method public void setSelected(boolean);
     method public void setShowingHintText(boolean);
@@ -51219,6 +51225,12 @@
     field public android.view.View view;
   }
 
+  public final class Magnifier {
+    ctor public Magnifier(android.view.View);
+    method public void dismiss();
+    method public void show(float, float);
+  }
+
   public class MediaController extends android.widget.FrameLayout {
     ctor public MediaController(android.content.Context, android.util.AttributeSet);
     ctor public MediaController(android.content.Context, boolean);
diff --git a/api/removed.txt b/api/removed.txt
index 2934846..be4d5be 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -210,10 +210,6 @@
 
 package android.media.tv {
 
-  public final class TvInputManager {
-    method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputManager.HardwareCallback, android.media.tv.TvInputInfo);
-  }
-
   public class TvView extends android.view.ViewGroup {
     method public void requestUnblockContent(android.media.tv.TvContentRating);
   }
diff --git a/api/system-current.txt b/api/system-current.txt
index 9dca6f7..95f28e4 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -751,6 +751,20 @@
     field public java.lang.String credentialProtectedDataDir;
   }
 
+  public final class InstantAppInfo implements android.os.Parcelable {
+    ctor public InstantAppInfo(android.content.pm.ApplicationInfo, java.lang.String[], java.lang.String[]);
+    ctor public InstantAppInfo(java.lang.String, java.lang.CharSequence, java.lang.String[], java.lang.String[]);
+    method public int describeContents();
+    method public android.content.pm.ApplicationInfo getApplicationInfo();
+    method public java.lang.String[] getGrantedPermissions();
+    method public java.lang.String getPackageName();
+    method public java.lang.String[] getRequestedPermissions();
+    method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
+    method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.content.pm.InstantAppInfo> CREATOR;
+  }
+
   public final class InstantAppIntentFilter implements android.os.Parcelable {
     ctor public InstantAppIntentFilter(java.lang.String, java.util.List<android.content.IntentFilter>);
     method public int describeContents();
@@ -4131,6 +4145,39 @@
 
 }
 
+package android.telephony.data {
+
+  public final class DataProfile implements android.os.Parcelable {
+    ctor public DataProfile(int, java.lang.String, java.lang.String, int, java.lang.String, java.lang.String, int, int, int, int, boolean, int, java.lang.String, int, int, java.lang.String, java.lang.String, boolean);
+    ctor public DataProfile(android.os.Parcel);
+    method public int describeContents();
+    method public java.lang.String getApn();
+    method public int getAuthType();
+    method public int getBearerBitmap();
+    method public int getMaxConns();
+    method public int getMaxConnsTime();
+    method public int getMtu();
+    method public java.lang.String getMvnoMatchData();
+    method public java.lang.String getMvnoType();
+    method public java.lang.String getPassword();
+    method public int getProfileId();
+    method public java.lang.String getProtocol();
+    method public java.lang.String getRoamingProtocol();
+    method public int getSupportedApnTypesBitmap();
+    method public int getType();
+    method public java.lang.String getUserName();
+    method public int getWaitTime();
+    method public boolean isEnabled();
+    method public boolean isModemCognitive();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telephony.data.DataProfile> CREATOR;
+    field public static final int TYPE_3GPP = 1; // 0x1
+    field public static final int TYPE_3GPP2 = 2; // 0x2
+    field public static final int TYPE_COMMON = 0; // 0x0
+  }
+
+}
+
 package android.telephony.ims {
 
   public class ImsService extends android.app.Service {
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 396bcd6..f98d011 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -103,6 +103,10 @@
 
 package android.media.tv {
 
+  public final class TvInputManager {
+    method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputManager.HardwareCallback, android.media.tv.TvInputInfo);
+  }
+
   public static final class TvInputManager.Hardware {
     method public boolean dispatchKeyEventToHdmi(android.view.KeyEvent);
   }
@@ -111,6 +115,13 @@
 
 package android.net.wifi {
 
+  public deprecated class BatchedScanResult implements android.os.Parcelable {
+    ctor public BatchedScanResult();
+    ctor public BatchedScanResult(android.net.wifi.BatchedScanResult);
+    field public final java.util.List<android.net.wifi.ScanResult> scanResults;
+    field public boolean truncated;
+  }
+
   public class ScanResult implements android.os.Parcelable {
     field public boolean untrusted;
   }
diff --git a/api/test-current.txt b/api/test-current.txt
index 2e6c40a..8647ed3 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -75,9 +75,11 @@
     method public int describeContents();
     method public int getActivityType();
     method public android.graphics.Rect getAppBounds();
+    method public android.graphics.Rect getBounds();
     method public int getWindowingMode();
     method public void setActivityType(int);
     method public void setAppBounds(android.graphics.Rect);
+    method public void setBounds(android.graphics.Rect);
     method public void setTo(android.app.WindowConfiguration);
     method public void setWindowingMode(int);
     method public void writeToParcel(android.os.Parcel, int);
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 4d975fc..1f15c5e 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -57,7 +57,8 @@
     src/StatsLogProcessor.cpp \
     src/StatsService.cpp \
     src/stats_util.cpp \
-    src/guardrail/MemoryLeakTrackUtil.cpp
+    src/guardrail/MemoryLeakTrackUtil.cpp \
+    src/guardrail/StatsdStats.cpp
 
 statsd_common_c_includes := \
     $(LOCAL_PATH)/src \
@@ -167,7 +168,8 @@
     tests/metrics/MaxDurationTracker_test.cpp \
     tests/metrics/CountMetricProducer_test.cpp \
     tests/metrics/EventMetricProducer_test.cpp \
-    tests/metrics/ValueMetricProducer_test.cpp
+    tests/metrics/ValueMetricProducer_test.cpp \
+    tests/guardrail/StatsdStats_test.cpp
 
 LOCAL_STATIC_LIBRARIES := \
     libgmock
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index b5cb20c..57b4fc1 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#define DEBUG true  // STOPSHIP if true
 #include "Log.h"
 #include "statslog.h"
 
@@ -21,6 +22,7 @@
 #include <dirent.h>
 #include "StatsLogProcessor.h"
 #include "android-base/stringprintf.h"
+#include "guardrail/StatsdStats.h"
 #include "metrics/CountMetricProducer.h"
 #include "stats_util.h"
 #include "storage/StorageManager.h"
@@ -73,15 +75,14 @@
 void StatsLogProcessor::onAnomalyAlarmFired(
         const uint64_t timestampNs,
         unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> anomalySet) {
-    for (const auto& anomaly : anomalySet) {
-        for (const auto& itr : mMetricsManagers) {
-            itr.second->onAnomalyAlarmFired(timestampNs, anomaly);
-        }
+    for (const auto& itr : mMetricsManagers) {
+        itr.second->onAnomalyAlarmFired(timestampNs, anomalySet);
     }
 }
 
 // TODO: what if statsd service restarts? How do we know what logs are already processed before?
 void StatsLogProcessor::OnLogEvent(const LogEvent& msg) {
+    StatsdStats::getInstance().noteAtomLogged(msg.GetTagId(), msg.GetTimestampNs() / NS_PER_SEC);
     // pass the event to metrics managers.
     for (auto& pair : mMetricsManagers) {
         pair.second->onLogEvent(msg);
@@ -106,23 +107,26 @@
 }
 
 void StatsLogProcessor::OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config) {
+    ALOGD("Updated configuration for key %s", key.ToString().c_str());
+    unique_ptr<MetricsManager> newMetricsManager = std::make_unique<MetricsManager>(key, config);
+
     auto it = mMetricsManagers.find(key);
     if (it != mMetricsManagers.end()) {
         it->second->finish();
+    } else if (mMetricsManagers.size() > StatsdStats::kMaxConfigCount) {
+        ALOGE("Can't accept more configs!");
+        return;
     }
 
-    ALOGD("Updated configuration for key %s", key.ToString().c_str());
-
-    unique_ptr<MetricsManager> newMetricsManager = std::make_unique<MetricsManager>(config);
     if (newMetricsManager->isConfigValid()) {
         mUidMap->OnConfigUpdated(key);
         newMetricsManager->setAnomalyMonitor(mAnomalyMonitor);
         mMetricsManagers[key] = std::move(newMetricsManager);
         // Why doesn't this work? mMetricsManagers.insert({key, std::move(newMetricsManager)});
-        ALOGD("StatsdConfig valid");
+        VLOG("StatsdConfig valid");
     } else {
         // If there is any error in the config, don't use it.
-        ALOGD("StatsdConfig NOT valid");
+        ALOGE("StatsdConfig NOT valid");
     }
 }
 
@@ -195,6 +199,7 @@
             iter.rp()->move(toRead);
         }
     }
+    StatsdStats::getInstance().noteMetricsReportSent(key);
 }
 
 void StatsLogProcessor::OnConfigRemoved(const ConfigKey& key) {
@@ -204,6 +209,7 @@
         mMetricsManagers.erase(it);
         mUidMap->OnConfigRemoved(key);
     }
+    StatsdStats::getInstance().noteConfigRemoved(key);
 
     std::lock_guard<std::mutex> lock(mBroadcastTimesMutex);
     mLastBroadcastTimes.erase(key);
@@ -223,12 +229,14 @@
             }
         }
         mLastBroadcastTimes[key] = timestampNs;
-        ALOGD("StatsD requesting broadcast for %s", key.ToString().c_str());
+        VLOG("StatsD requesting broadcast for %s", key.ToString().c_str());
         mSendBroadcast(key);
+        StatsdStats::getInstance().noteBroadcastSent(key);
     } else if (totalBytes > kMaxSerializedBytes) { // Too late. We need to start clearing data.
         // We ignore the return value so we force each metric producer to clear its contents.
         metricsManager->onDumpReport();
-        ALOGD("StatsD had to toss out metrics for %s", key.ToString().c_str());
+        StatsdStats::getInstance().noteDataDropped(key);
+        VLOG("StatsD had to toss out metrics for %s", key.ToString().c_str());
     }
 }
 
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 57928d0..27e3854 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -44,6 +44,8 @@
     size_t GetMetricsSize(const ConfigKey& key) const;
 
     void onDumpReport(const ConfigKey& key, vector<uint8_t>* outData);
+
+    /* Tells MetricsManager that the alarms in anomalySet have fired. Modifies anomalySet. */
     void onAnomalyAlarmFired(
             const uint64_t timestampNs,
             unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> anomalySet);
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index ec2650e..618e03d 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -22,6 +22,7 @@
 #include "config/ConfigKey.h"
 #include "config/ConfigManager.h"
 #include "guardrail/MemoryLeakTrackUtil.h"
+#include "guardrail/StatsdStats.h"
 #include "storage/DropboxReader.h"
 #include "storage/StorageManager.h"
 
@@ -222,7 +223,7 @@
         }
 
         if (!args[0].compare(String8("print-stats"))) {
-            return cmd_print_stats(out);
+            return cmd_print_stats(out, args);
         }
 
         if (!args[0].compare(String8("clear-config"))) {
@@ -305,8 +306,9 @@
     fprintf(out, "  NAME          The name of the configuration\n");
     fprintf(out, "\n");
     fprintf(out, "\n");
-    fprintf(out, "usage: adb shell cmd stats print-stats\n");
+    fprintf(out, "usage: adb shell cmd stats print-stats [reset]\n");
     fprintf(out, "  Prints some basic stats.\n");
+    fprintf(out, "  reset: 1 to reset the statsd stats. default=0.\n");
 }
 
 status_t StatsService::cmd_trigger_broadcast(FILE* out, Vector<String8>& args) {
@@ -474,12 +476,20 @@
     }
 }
 
-status_t StatsService::cmd_print_stats(FILE* out) {
+status_t StatsService::cmd_print_stats(FILE* out, const Vector<String8>& args) {
     vector<ConfigKey> configs = mConfigManager->GetAllConfigKeys();
     for (const ConfigKey& key : configs) {
         fprintf(out, "Config %s uses %zu bytes\n", key.ToString().c_str(),
                 mProcessor->GetMetricsSize(key));
     }
+    fprintf(out, "Detailed statsd stats in logcat...");
+    StatsdStats& statsdStats = StatsdStats::getInstance();
+    bool reset = false;
+    if (args.size() > 1) {
+        reset = strtol(args[1].string(), NULL, 10);
+    }
+    vector<uint8_t> output;
+    statsdStats.dumpStats(&output, reset);
     return NO_ERROR;
 }
 
@@ -575,11 +585,10 @@
     }
 
     if (DEBUG) ALOGD("StatsService::informAnomalyAlarmFired succeeded");
-    // TODO: check through all counters/timers and see if an anomaly has indeed occurred.
-    uint64_t currentTimeNs = time(nullptr) * NS_PER_SEC;
+    uint64_t currentTimeSec = time(nullptr);
     std::unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> anomalySet =
-            mAnomalyMonitor->onAlarmFired(currentTimeNs);
-    mProcessor->onAnomalyAlarmFired(currentTimeNs, anomalySet);
+            mAnomalyMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
+    mProcessor->onAnomalyAlarmFired(currentTimeSec * NS_PER_SEC, anomalySet);
     return Status::ok();
 }
 
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 6b5c156..a32595a 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -134,7 +134,7 @@
     /**
      * Prints some basic stats to std out.
      */
-    status_t cmd_print_stats(FILE* out);
+    status_t cmd_print_stats(FILE* out, const Vector<String8>& args);
 
     /**
      * Print the event log.
diff --git a/cmds/statsd/src/anomaly/AnomalyMonitor.cpp b/cmds/statsd/src/anomaly/AnomalyMonitor.cpp
index da52a9d..2b2bcfc 100644
--- a/cmds/statsd/src/anomaly/AnomalyMonitor.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyMonitor.cpp
@@ -72,7 +72,8 @@
         return;
     }
     if (DEBUG) ALOGD("Removing alarm with time %u", alarm->timestampSec);
-    mPq.remove(alarm);
+    bool wasPresent = mPq.remove(alarm);
+    if (!wasPresent) return;
     if (mPq.empty()) {
         if (DEBUG) ALOGD("Queue is empty. Cancel any alarm.");
         mRegisteredAlarmTimeSec = 0;
@@ -129,11 +130,6 @@
     return ((int64_t)timeSec) * 1000;
 }
 
-unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> AnomalyMonitor::onAlarmFired(
-        uint64_t timestampNs) {
-    return popSoonerThan(static_cast<uint32_t>(timestampNs));
-}
-
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/anomaly/AnomalyMonitor.h b/cmds/statsd/src/anomaly/AnomalyMonitor.h
index 0bd5055..e19c469 100644
--- a/cmds/statsd/src/anomaly/AnomalyMonitor.h
+++ b/cmds/statsd/src/anomaly/AnomalyMonitor.h
@@ -23,7 +23,6 @@
 
 #include <queue>
 #include <set>
-#include <unordered_map>
 #include <unordered_set>
 #include <vector>
 
@@ -97,15 +96,6 @@
     unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> popSoonerThan(
             uint32_t timestampSec);
 
-    // TODO: Function that uses popSoonerThan to get all alarms that have fired, and then
-    // iterates over all DurationAnomalyTracker, looking for those alarms. When they're found,
-    // have them declareAnomaly on those alarms. This means that DurationAnomalyTracker
-    // must be thread-safe (since this is being called on a different thread). There is no
-    // worry about missing the alarms (due to them being cancelled after this function being called)
-    // because DurationAnomalyTracker guarantees that it checks for anaomlies when it cancels
-    // alarms anyway.
-    // void declareAnomalies(uint32_t timestampSec);
-
     /**
      * Returns the projected alarm timestamp that is registered with
      * StatsCompanionService. This may not be equal to the soonest alarm,
@@ -115,8 +105,6 @@
         return mRegisteredAlarmTimeSec;
     }
 
-    unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> onAlarmFired(uint64_t timestampNs);
-
 private:
     std::mutex mLock;
 
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index 0904a04..7bacb44 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -19,32 +19,32 @@
 
 #include "AnomalyTracker.h"
 
+#include <android/os/IIncidentManager.h>
+#include <android/os/IncidentReportArgs.h>
+#include <binder/IServiceManager.h>
 #include <time.h>
 
 namespace android {
 namespace os {
 namespace statsd {
 
-AnomalyTracker::AnomalyTracker(const Alert& alert, const int64_t& bucketSizeNs)
+// TODO: Separate DurationAnomalyTracker as a separate subclass and let each MetricProducer
+//       decide and let which one it wants.
+// TODO: Get rid of bucketNumbers, and return to the original circular array method.
+AnomalyTracker::AnomalyTracker(const Alert& alert)
     : mAlert(alert),
-      mBucketSizeNs(bucketSizeNs),
-      mNumOfPastPackets(mAlert.number_of_buckets() - 1) {
+      mNumOfPastBuckets(mAlert.number_of_buckets() - 1) {
     VLOG("AnomalyTracker() called");
     if (mAlert.number_of_buckets() <= 0) {
-        ALOGE("Cannot create DiscreteAnomalyTracker with %lld buckets",
+        ALOGE("Cannot create AnomalyTracker with %lld buckets",
               (long long)mAlert.number_of_buckets());
         return;
     }
-    if (mBucketSizeNs <= 0) {
-        ALOGE("Cannot create DiscreteAnomalyTracker with bucket size %lld ",
-              (long long)mBucketSizeNs);
-        return;
-    }
     if (!mAlert.has_trigger_if_sum_gt()) {
-        ALOGE("Cannot create DiscreteAnomalyTracker without threshold");
+        ALOGE("Cannot create AnomalyTracker without threshold");
         return;
     }
-    reset(); // initialization
+    resetStorage(); // initialization
 }
 
 AnomalyTracker::~AnomalyTracker() {
@@ -52,37 +52,36 @@
     stopAllAlarms();
 }
 
-void AnomalyTracker::reset() {
-    VLOG("reset() called.");
-    stopAllAlarms();
+void AnomalyTracker::resetStorage() {
+    VLOG("resetStorage() called.");
     mPastBuckets.clear();
     // Excludes the current bucket.
-    mPastBuckets.resize(mNumOfPastPackets);
+    mPastBuckets.resize(mNumOfPastBuckets);
     mSumOverPastBuckets.clear();
-    mMostRecentBucketNum = -1;
-    mLastAlarmTimestampNs = -1;
+
+    if (!mAlarms.empty()) VLOG("AnomalyTracker.resetStorage() called but mAlarms is NOT empty!");
 }
 
 size_t AnomalyTracker::index(int64_t bucketNum) const {
-    return bucketNum % mNumOfPastPackets;
+    return bucketNum % mNumOfPastBuckets;
 }
 
 void AnomalyTracker::flushPastBuckets(const int64_t& latestPastBucketNum) {
     VLOG("addPastBucket() called.");
-    if (latestPastBucketNum <= mMostRecentBucketNum - mNumOfPastPackets) {
+    if (latestPastBucketNum <= mMostRecentBucketNum - mNumOfPastBuckets) {
         ALOGE("Cannot add a past bucket %lld units in past", (long long)latestPastBucketNum);
         return;
     }
 
     // The past packets are ancient. Empty out old mPastBuckets[i] values and reset
     // mSumOverPastBuckets.
-    if (latestPastBucketNum - mMostRecentBucketNum >= mNumOfPastPackets) {
+    if (latestPastBucketNum - mMostRecentBucketNum >= mNumOfPastBuckets) {
         mPastBuckets.clear();
-        mPastBuckets.resize(mNumOfPastPackets);
+        mPastBuckets.resize(mNumOfPastBuckets);
         mSumOverPastBuckets.clear();
     } else {
-        for (int64_t i = std::max(0LL, (long long)(mMostRecentBucketNum - mNumOfPastPackets + 1));
-             i <= latestPastBucketNum - mNumOfPastPackets; i++) {
+        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.
@@ -91,7 +90,7 @@
 
     // It is an update operation.
     if (latestPastBucketNum <= mMostRecentBucketNum &&
-        latestPastBucketNum > mMostRecentBucketNum - mNumOfPastPackets) {
+        latestPastBucketNum > mMostRecentBucketNum - mNumOfPastBuckets) {
         subtractBucketFromSum(mPastBuckets[index(latestPastBucketNum)]);
     }
 }
@@ -190,61 +189,79 @@
     if (currentBucketNum > mMostRecentBucketNum + 1) {
         addPastBucket(key, 0, currentBucketNum - 1);
     }
-    return getSumOverPastBuckets(key) + currentBucketValue > mAlert.trigger_if_sum_gt();
+    return mAlert.has_trigger_if_sum_gt()
+            && getSumOverPastBuckets(key) + currentBucketValue > mAlert.trigger_if_sum_gt();
 }
 
-void AnomalyTracker::declareAnomaly(const uint64_t& timestamp) {
-    if (mLastAlarmTimestampNs >= 0 &&
-        timestamp - mLastAlarmTimestampNs <= mAlert.refractory_period_secs() * NS_PER_SEC) {
-        VLOG("Skipping anomaly check since within refractory period");
+void AnomalyTracker::declareAnomaly(const uint64_t& timestampNs) {
+    // TODO: This should also take in the const HashableDimensionKey& key, to pass
+    //       more details to incidentd and to make mRefractoryPeriodEndsSec key-specific.
+    // TODO: Why receive timestamp? RefractoryPeriod should always be based on real time right now.
+    if (isInRefractoryPeriod(timestampNs)) {
+        VLOG("Skipping anomaly declaration since within refractory period");
         return;
     }
     // TODO(guardrail): Consider guarding against too short refractory periods.
-    mLastAlarmTimestampNs = timestamp;
+    mLastAlarmTimestampNs = timestampNs;
+
+
+    // TODO: If we had access to the bucket_size_millis, consider calling resetStorage()
+    // if (mAlert.refractory_period_secs() > mNumOfPastBuckets * bucketSizeNs) { resetStorage(); }
 
     if (mAlert.has_incidentd_details()) {
-        // TODO: Can construct a name based on the criteria (and/or relay the criteria).
-        ALOGW("An anomaly (nameless) has occurred! Informing incidentd.");
-        // TODO: Send incidentd_details.name and incidentd_details.incidentd_sections to incidentd
+        if (mAlert.has_name()) {
+            ALOGW("An anomaly (%s) has occurred! Informing incidentd.",
+                  mAlert.name().c_str());
+        } else {
+            // TODO: Can construct a name based on the criteria (and/or relay the criteria).
+            ALOGW("An anomaly (nameless) has occurred! Informing incidentd.");
+        }
+        informIncidentd();
     } else {
         ALOGW("An anomaly has occurred! (But informing incidentd not requested.)");
     }
 }
 
 void AnomalyTracker::declareAnomalyIfAlarmExpired(const HashableDimensionKey& dimensionKey,
-                                                  const uint64_t& timestamp) {
+                                                  const uint64_t& timestampNs) {
     auto itr = mAlarms.find(dimensionKey);
     if (itr == mAlarms.end()) {
         return;
     }
 
     if (itr->second != nullptr &&
-        static_cast<uint32_t>(timestamp / NS_PER_SEC) >= itr->second->timestampSec) {
-        declareAnomaly(timestamp);
+        static_cast<uint32_t>(timestampNs / NS_PER_SEC) >= itr->second->timestampSec) {
+        declareAnomaly(timestampNs);
         stopAlarm(dimensionKey);
     }
 }
 
-void AnomalyTracker::detectAndDeclareAnomaly(const uint64_t& timestamp,
+void AnomalyTracker::detectAndDeclareAnomaly(const uint64_t& timestampNs,
                                              const int64_t& currBucketNum,
                                              const HashableDimensionKey& key,
                                              const int64_t& currentBucketValue) {
     if (detectAnomaly(currBucketNum, key, currentBucketValue)) {
-        declareAnomaly(timestamp);
+        declareAnomaly(timestampNs);
     }
 }
 
-void AnomalyTracker::detectAndDeclareAnomaly(const uint64_t& timestamp,
+void AnomalyTracker::detectAndDeclareAnomaly(const uint64_t& timestampNs,
                                              const int64_t& currBucketNum,
                                              const DimToValMap& currentBucket) {
     if (detectAnomaly(currBucketNum, currentBucket)) {
-        declareAnomaly(timestamp);
+        declareAnomaly(timestampNs);
     }
 }
 
 void AnomalyTracker::startAlarm(const HashableDimensionKey& dimensionKey,
-                                const uint64_t& timestamp) {
-    sp<const AnomalyAlarm> alarm = new AnomalyAlarm{static_cast<uint32_t>(timestamp / NS_PER_SEC)};
+                                const uint64_t& timestampNs) {
+    uint32_t timestampSec = static_cast<uint32_t>(timestampNs / NS_PER_SEC);
+    if (isInRefractoryPeriod(timestampNs)) {
+        VLOG("Skipping setting anomaly alarm since it'd fall in the refractory period");
+        return;
+    }
+
+    sp<const AnomalyAlarm> alarm = new AnomalyAlarm{timestampSec};
     mAlarms.insert({dimensionKey, alarm});
     if (mAnomalyMonitor != nullptr) {
         mAnomalyMonitor->add(alarm);
@@ -255,9 +272,9 @@
     auto itr = mAlarms.find(dimensionKey);
     if (itr != mAlarms.end()) {
         mAlarms.erase(dimensionKey);
-    }
-    if (mAnomalyMonitor != nullptr) {
-        mAnomalyMonitor->remove(itr->second);
+        if (mAnomalyMonitor != nullptr) {
+            mAnomalyMonitor->remove(itr->second);
+        }
     }
 }
 
@@ -271,6 +288,58 @@
     }
 }
 
+bool AnomalyTracker::isInRefractoryPeriod(const uint64_t& timestampNs) {
+    return mLastAlarmTimestampNs >= 0 &&
+            timestampNs - mLastAlarmTimestampNs <= mAlert.refractory_period_secs() * NS_PER_SEC;
+}
+
+void AnomalyTracker::informAlarmsFired(const uint64_t& timestampNs,
+        unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& firedAlarms) {
+
+    if (firedAlarms.empty() || mAlarms.empty()) return;
+    // Find the intersection of firedAlarms and mAlarms.
+    // The for loop is inefficient, since it loops over all keys, but that's okay since it is very
+    // seldomly called. The alternative would be having AnomalyAlarms store information about the
+    // AnomalyTracker and key, but that's a lot of data overhead to speed up something that is
+    // rarely ever called.
+    unordered_map<HashableDimensionKey, sp<const AnomalyAlarm>> matchedAlarms;
+    for (const auto& kv : mAlarms) {
+        if (firedAlarms.count(kv.second) > 0) {
+            matchedAlarms.insert({kv.first, kv.second});
+        }
+    }
+
+    // Now declare each of these alarms to have fired.
+    for (const auto& kv : matchedAlarms) {
+        declareAnomaly(timestampNs /* TODO: , kv.first */);
+        mAlarms.erase(kv.first);
+        firedAlarms.erase(kv.second); // No one else can also own it, so we're done with it.
+    }
+}
+
+void AnomalyTracker::informIncidentd() {
+    VLOG("informIncidentd called.");
+    if (!mAlert.has_incidentd_details()) {
+        ALOGE("Attempted to call incidentd without any incidentd_details.");
+        return;
+    }
+    sp<IIncidentManager> service = interface_cast<IIncidentManager>(
+            defaultServiceManager()->getService(android::String16("incident")));
+    if (service == NULL) {
+        ALOGW("Couldn't get the incident service.");
+        return;
+    }
+
+    IncidentReportArgs incidentReport;
+    const Alert::IncidentdDetails& details = mAlert.incidentd_details();
+    for (int i = 0; i < details.section_size(); i++) {
+        incidentReport.addSection(details.section(i));
+    }
+    // TODO: Pass in mAlert.name() into the addHeader?
+
+    service->reportIncident(incidentReport);
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.h b/cmds/statsd/src/anomaly/AnomalyTracker.h
index ce6c995..49e8323 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.h
@@ -32,10 +32,10 @@
 using std::unordered_map;
 using std::shared_ptr;
 
-// This anomaly track assmues that all values are non-negative.
+// Does NOT allow negative values.
 class AnomalyTracker : public virtual RefBase {
 public:
-    AnomalyTracker(const Alert& alert, const int64_t& bucketSizeNs);
+    AnomalyTracker(const Alert& alert);
 
     virtual ~AnomalyTracker();
 
@@ -51,12 +51,12 @@
                        const int64_t& currentBucketValue);
 
     // Informs incidentd about the detected alert.
-    void declareAnomaly(const uint64_t& timestamp);
+    void declareAnomaly(const uint64_t& timestampNs);
 
     // Detects the alert and informs the incidentd when applicable.
-    void detectAndDeclareAnomaly(const uint64_t& timestamp, const int64_t& currBucketNum,
+    void detectAndDeclareAnomaly(const uint64_t& timestampNs, const int64_t& currBucketNum,
                                  const DimToValMap& currentBucket);
-    void detectAndDeclareAnomaly(const uint64_t& timestamp, const int64_t& currBucketNum,
+    void detectAndDeclareAnomaly(const uint64_t& timestampNs, const int64_t& currBucketNum,
                                  const HashableDimensionKey& key,
                                  const int64_t& currentBucketValue);
 
@@ -75,7 +75,7 @@
 
     // Declares the anomaly when the alarm expired given the current timestamp.
     void declareAnomalyIfAlarmExpired(const HashableDimensionKey& dimensionKey,
-                                      const uint64_t& timestamp);
+                                      const uint64_t& timestampNs);
 
     // Helper function to return the sum value of past buckets at given dimension.
     int64_t getSumOverPastBuckets(const HashableDimensionKey& key) const;
@@ -93,20 +93,26 @@
         return mLastAlarmTimestampNs;
     }
 
-    inline int getNumOfPastPackets() const {
-        return mNumOfPastPackets;
+    inline int getNumOfPastBuckets() const {
+        return mNumOfPastBuckets;
     }
 
+    // Declares an anomaly for each alarm in firedAlarms that belongs to this AnomalyTracker,
+    // and removes it from firedAlarms. Does NOT remove the alarm from the AnomalyMonitor.
+    // TODO: This will actually be called from a different thread, so make it thread-safe!
+    // TODO: Consider having AnomalyMonitor have a reference to each relevant MetricProducer
+    //       instead of calling it from a chain starting at StatsLogProcessor.
+    void informAlarmsFired(const uint64_t& timestampNs,
+            unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& firedAlarms);
+
 protected:
     void flushPastBuckets(const int64_t& currBucketNum);
     // statsd_config.proto Alert message that defines this tracker.
     const Alert mAlert;
 
-    // Bucket duration in ns.
-    int64_t mBucketSizeNs = 0;
-
-    // The number of past packets to track in the anomaly detection.
-    int mNumOfPastPackets = 0;
+    // Number of past buckets. One less than the total number of buckets needed
+    // for the anomaly detection (since the current bucket is not in the past).
+    int mNumOfPastBuckets;
 
     // The alarms owned by this tracker. The alarm monitor also shares the alarm pointers when they
     // are still active.
@@ -134,11 +140,16 @@
     // and remove any items with value 0.
     void subtractBucketFromSum(const shared_ptr<DimToValMap>& bucket);
 
+    bool isInRefractoryPeriod(const uint64_t& timestampNs);
+
     // Calculates the corresponding bucket index within the circular array.
     size_t index(int64_t bucketNum) const;
 
-    // Resets all data. For use when all the data gets stale.
-    void reset();
+    // Resets all bucket data. For use when all the data gets stale.
+    void resetStorage();
+
+    // Informs the incident service that an anomaly has occurred.
+    void informIncidentd();
 
     FRIEND_TEST(AnomalyTrackerTest, TestConsecutiveBuckets);
     FRIEND_TEST(AnomalyTrackerTest, TestSparseBuckets);
diff --git a/cmds/statsd/src/anomaly/indexed_priority_queue.h b/cmds/statsd/src/anomaly/indexed_priority_queue.h
index 4982d4b..99882d0 100644
--- a/cmds/statsd/src/anomaly/indexed_priority_queue.h
+++ b/cmds/statsd/src/anomaly/indexed_priority_queue.h
@@ -37,7 +37,7 @@
 /**
  * Min priority queue for generic type AA.
  * Unlike a regular priority queue, this class is also capable of removing interior elements.
- * @tparam Comparator must implement [bool operator()(sp< AA> a, sp< AA> b)], returning
+ * @tparam Comparator must implement [bool operator()(sp<const AA> a, sp<const AA> b)], returning
  *    whether a should be closer to the top of the queue than b.
  */
 template <class AA, class Comparator>
@@ -46,8 +46,11 @@
     indexed_priority_queue();
     /** Adds a into the priority queue. If already present or a==nullptr, does nothing. */
     void push(sp<const AA> a);
-    /** Removes a from the priority queue. If not present or a==nullptr, does nothing. */
-    void remove(sp<const AA> a);
+    /*
+     * Removes a from the priority queue. If not present or a==nullptr, does nothing.
+     * Returns true if a had been present (and is now removed), else false.
+     */
+    bool remove(sp<const AA> a);
     /** Removes the top element, if there is one. */
     void pop();
     /** Removes all elements. */
@@ -97,17 +100,17 @@
 }
 
 template <class AA, class Comparator>
-void indexed_priority_queue<AA, Comparator>::remove(sp<const AA> a) {
-    if (a == nullptr) return;
-    if (!contains(a)) return;
+bool indexed_priority_queue<AA, Comparator>::remove(sp<const AA> a) {
+    if (a == nullptr) return false;
+    if (!contains(a)) return false;
     size_t idx = indices[a];
     if (idx >= pq.size()) {
-        return;
+        return false;
     }
     if (idx == size()) {  // if a is the last element, i.e. at index idx == size() == (pq.size()-1)
         pq.pop_back();
         indices.erase(a);
-        return;
+        return true;
     }
     // move last element (guaranteed not to be at idx) to idx, then delete a
     sp<const AA> last_a = pq.back();
@@ -119,6 +122,8 @@
     // get the heap back in order (since the element at idx is not in order)
     sift_up(idx);
     sift_down(idx);
+
+    return true;
 }
 
 // The same as, but slightly more efficient than, remove(top()).
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
index d8099b3..50cd130 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
@@ -18,6 +18,7 @@
 #include "Log.h"
 
 #include "SimpleConditionTracker.h"
+#include "guardrail/StatsdStats.h"
 
 #include <log/logprint.h>
 
@@ -32,9 +33,10 @@
 using std::vector;
 
 SimpleConditionTracker::SimpleConditionTracker(
-        const string& name, const int index, const SimpleCondition& simpleCondition,
+        const ConfigKey& key, const string& name, const int index,
+        const SimpleCondition& simpleCondition,
         const unordered_map<string, int>& trackerNameIndexMap)
-    : ConditionTracker(name, index) {
+    : ConditionTracker(name, index), mConfigKey(key) {
     VLOG("creating SimpleConditionTracker %s", mName.c_str());
     mCountNesting = simpleCondition.count_nesting();
 
@@ -126,6 +128,24 @@
     conditionCache[mIndex] = ConditionState::kFalse;
 }
 
+bool SimpleConditionTracker::hitGuardRail(const HashableDimensionKey& newKey) {
+    if (!mSliced || mSlicedConditionState.find(newKey) != mSlicedConditionState.end()) {
+        // if the condition is not sliced or the key is not new, we are good!
+        return false;
+    }
+    // 1. Report the tuple count if the tuple count > soft limit
+    if (mSlicedConditionState.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
+        size_t newTupleCount = mSlicedConditionState.size() + 1;
+        StatsdStats::getInstance().noteConditionDimensionSize(mConfigKey, mName, newTupleCount);
+        // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
+        if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
+            ALOGE("Condition %s dropping data for dimension key %s", mName.c_str(), newKey.c_str());
+            return true;
+        }
+    }
+    return false;
+}
+
 void SimpleConditionTracker::handleConditionEvent(const HashableDimensionKey& outputKey,
                                                   bool matchStart,
                                                   std::vector<ConditionState>& conditionCache,
@@ -133,6 +153,12 @@
     bool changed = false;
     auto outputIt = mSlicedConditionState.find(outputKey);
     ConditionState newCondition;
+    if (hitGuardRail(outputKey)) {
+        conditionChangedCache[mIndex] = false;
+        // Tells the caller it's evaluated.
+        conditionCache[mIndex] = ConditionState::kUnknown;
+        return;
+    }
     if (outputIt == mSlicedConditionState.end()) {
         // We get a new output key.
         newCondition = matchStart ? ConditionState::kTrue : ConditionState::kFalse;
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.h b/cmds/statsd/src/condition/SimpleConditionTracker.h
index c287d8f..d21afd1 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.h
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.h
@@ -19,6 +19,7 @@
 
 #include <gtest/gtest_prod.h>
 #include "ConditionTracker.h"
+#include "config/ConfigKey.h"
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 #include "stats_util.h"
 
@@ -28,7 +29,7 @@
 
 class SimpleConditionTracker : public virtual ConditionTracker {
 public:
-    SimpleConditionTracker(const std::string& name, const int index,
+    SimpleConditionTracker(const ConfigKey& key, const std::string& name, const int index,
                            const SimpleCondition& simpleCondition,
                            const std::unordered_map<std::string, int>& trackerNameIndexMap);
 
@@ -50,6 +51,7 @@
                         std::vector<ConditionState>& conditionCache) const override;
 
 private:
+    const ConfigKey mConfigKey;
     // The index of the LogEventMatcher which defines the start.
     int mStartLogMatcherIndex;
 
@@ -75,6 +77,8 @@
                               std::vector<ConditionState>& conditionCache,
                               std::vector<bool>& changedCache);
 
+    bool hitGuardRail(const HashableDimensionKey& newKey);
+
     FRIEND_TEST(SimpleConditionTrackerTest, TestSlicedCondition);
     FRIEND_TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim);
     FRIEND_TEST(SimpleConditionTrackerTest, TestStopAll);
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index ac2192c..445ee59 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -210,6 +210,9 @@
     alert->set_number_of_buckets(6);
     alert->set_trigger_if_sum_gt(10);
     alert->set_refractory_period_secs(30);
+    Alert::IncidentdDetails* details = alert->mutable_incidentd_details();
+    details->add_section(12);
+    details->add_section(13);
 
     // Count process state changes, slice by uid.
     metric = config.add_count_metric();
@@ -226,6 +229,9 @@
     alert->set_number_of_buckets(4);
     alert->set_trigger_if_sum_gt(30);
     alert->set_refractory_period_secs(20);
+    details = alert->mutable_incidentd_details();
+    details->add_section(14);
+    details->add_section(15);
 
     // Count process state changes, slice by uid, while SCREEN_IS_OFF
     metric = config.add_count_metric();
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
new file mode 100644
index 0000000..2ab1146
--- /dev/null
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -0,0 +1,358 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define DEBUG true  // STOPSHIP if true
+#include "Log.h"
+
+#include "StatsdStats.h"
+
+#include <android/util/ProtoOutputStream.h>
+#include "statslog.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using android::util::FIELD_COUNT_REPEATED;
+using android::util::FIELD_TYPE_BOOL;
+using android::util::FIELD_TYPE_FLOAT;
+using android::util::FIELD_TYPE_INT32;
+using android::util::FIELD_TYPE_INT64;
+using android::util::FIELD_TYPE_MESSAGE;
+using android::util::FIELD_TYPE_STRING;
+using android::util::ProtoOutputStream;
+using std::lock_guard;
+using std::map;
+using std::string;
+using std::vector;
+
+const int FIELD_ID_BEGIN_TIME = 1;
+const int FIELD_ID_END_TIME = 2;
+const int FIELD_ID_CONFIG_STATS = 3;
+const int FIELD_ID_MATCHER_STATS = 4;
+const int FIELD_ID_CONDITION_STATS = 5;
+const int FIELD_ID_METRIC_STATS = 6;
+const int FIELD_ID_ATOM_STATS = 7;
+
+const int FIELD_ID_MATCHER_STATS_NAME = 1;
+const int FIELD_ID_MATCHER_STATS_COUNT = 2;
+
+const int FIELD_ID_CONDITION_STATS_NAME = 1;
+const int FIELD_ID_CONDITION_STATS_COUNT = 2;
+
+const int FIELD_ID_METRIC_STATS_NAME = 1;
+const int FIELD_ID_METRIC_STATS_COUNT = 2;
+
+const int FIELD_ID_ATOM_STATS_TAG = 1;
+const int FIELD_ID_ATOM_STATS_COUNT = 2;
+
+// TODO: add stats for pulled atoms.
+StatsdStats::StatsdStats() {
+    mPushedAtomStats.resize(android::util::kMaxPushedAtomId + 1);
+    mStartTimeSec = time(nullptr);
+}
+
+StatsdStats& StatsdStats::getInstance() {
+    static StatsdStats statsInstance;
+    return statsInstance;
+}
+
+void StatsdStats::noteConfigReceived(const ConfigKey& key, int metricsCount, int conditionsCount,
+                                     int matchersCount, int alertsCount, bool isValid) {
+    lock_guard<std::mutex> lock(mLock);
+    int32_t nowTimeSec = time(nullptr);
+
+    // If there is an existing config for the same key, icebox the old config.
+    noteConfigRemovedInternalLocked(key);
+
+    StatsdStatsReport_ConfigStats configStats;
+    configStats.set_uid(key.GetUid());
+    configStats.set_name(key.GetName());
+    configStats.set_creation_time_sec(nowTimeSec);
+    configStats.set_metric_count(metricsCount);
+    configStats.set_condition_count(conditionsCount);
+    configStats.set_matcher_count(matchersCount);
+    configStats.set_alert_count(alertsCount);
+    configStats.set_is_valid(isValid);
+
+    if (isValid) {
+        mConfigStats[key] = configStats;
+    } else {
+        configStats.set_deletion_time_sec(nowTimeSec);
+        mIceBox.push_back(configStats);
+    }
+}
+
+void StatsdStats::noteConfigRemovedInternalLocked(const ConfigKey& key) {
+    auto it = mConfigStats.find(key);
+    if (it != mConfigStats.end()) {
+        int32_t nowTimeSec = time(nullptr);
+        it->second.set_deletion_time_sec(nowTimeSec);
+        // Add condition stats, metrics stats, matcher stats
+        addSubStatsToConfig(key, it->second);
+        // Remove them after they are added to the config stats.
+        mMatcherStats.erase(key);
+        mMetricsStats.erase(key);
+        mConditionStats.erase(key);
+        mIceBox.push_back(it->second);
+        mConfigStats.erase(it);
+    }
+}
+
+void StatsdStats::noteConfigRemoved(const ConfigKey& key) {
+    lock_guard<std::mutex> lock(mLock);
+    noteConfigRemovedInternalLocked(key);
+}
+
+void StatsdStats::noteBroadcastSent(const ConfigKey& key) {
+    lock_guard<std::mutex> lock(mLock);
+    auto it = mConfigStats.find(key);
+    if (it == mConfigStats.end()) {
+        ALOGE("Config key %s not found!", key.ToString().c_str());
+        return;
+    }
+
+    it->second.add_broadcast_sent_time_sec(time(nullptr));
+}
+
+void StatsdStats::noteDataDropped(const ConfigKey& key) {
+    lock_guard<std::mutex> lock(mLock);
+    auto it = mConfigStats.find(key);
+    if (it == mConfigStats.end()) {
+        ALOGE("Config key %s not found!", key.ToString().c_str());
+        return;
+    }
+
+    it->second.add_data_drop_time_sec(time(nullptr));
+}
+
+void StatsdStats::noteMetricsReportSent(const ConfigKey& key) {
+    lock_guard<std::mutex> lock(mLock);
+    auto it = mConfigStats.find(key);
+    if (it == mConfigStats.end()) {
+        ALOGE("Config key %s not found!", key.ToString().c_str());
+        return;
+    }
+
+    it->second.add_dump_report_time_sec(time(nullptr));
+}
+
+void StatsdStats::noteConditionDimensionSize(const ConfigKey& key, const string& name, int size) {
+    lock_guard<std::mutex> lock(mLock);
+    // if name doesn't exist before, it will create the key with count 0.
+    auto& conditionSizeMap = mConditionStats[key];
+    if (size > conditionSizeMap[name]) {
+        conditionSizeMap[name] = size;
+    }
+}
+
+void StatsdStats::noteMetricDimensionSize(const ConfigKey& key, const string& name, int size) {
+    lock_guard<std::mutex> lock(mLock);
+    // if name doesn't exist before, it will create the key with count 0.
+    auto& metricsDimensionMap = mMetricsStats[key];
+    if (size > metricsDimensionMap[name]) {
+        metricsDimensionMap[name] = size;
+    }
+}
+
+void StatsdStats::noteMatcherMatched(const ConfigKey& key, const string& name) {
+    lock_guard<std::mutex> lock(mLock);
+    auto& matcherStats = mMatcherStats[key];
+    matcherStats[name]++;
+}
+
+void StatsdStats::noteAtomLogged(int atomId, int32_t timeSec) {
+    lock_guard<std::mutex> lock(mLock);
+
+    if (timeSec < mStartTimeSec) {
+        return;
+    }
+
+    if (atomId > android::util::kMaxPushedAtomId) {
+        ALOGW("not interested in atom %d", atomId);
+        return;
+    }
+
+    mPushedAtomStats[atomId]++;
+}
+
+void StatsdStats::reset() {
+    lock_guard<std::mutex> lock(mLock);
+    resetInternalLocked();
+}
+
+void StatsdStats::resetInternalLocked() {
+    // Reset the historical data, but keep the active ConfigStats
+    mStartTimeSec = time(nullptr);
+    mIceBox.clear();
+    mConditionStats.clear();
+    mMetricsStats.clear();
+    std::fill(mPushedAtomStats.begin(), mPushedAtomStats.end(), 0);
+    mMatcherStats.clear();
+}
+
+void StatsdStats::addSubStatsToConfig(const ConfigKey& key,
+                                      StatsdStatsReport_ConfigStats& configStats) {
+    // Add matcher stats
+    if (mMatcherStats.find(key) != mMatcherStats.end()) {
+        const auto& matcherStats = mMatcherStats[key];
+        for (const auto& stats : matcherStats) {
+            auto output = configStats.add_matcher_stats();
+            output->set_name(stats.first);
+            output->set_matched_times(stats.second);
+            VLOG("matcher %s matched %d times", stats.first.c_str(), stats.second);
+        }
+    }
+    // Add condition stats
+    if (mConditionStats.find(key) != mConditionStats.end()) {
+        const auto& conditionStats = mConditionStats[key];
+        for (const auto& stats : conditionStats) {
+            auto output = configStats.add_condition_stats();
+            output->set_name(stats.first);
+            output->set_max_tuple_counts(stats.second);
+            VLOG("condition %s max output tuple size %d", stats.first.c_str(), stats.second);
+        }
+    }
+    // Add metrics stats
+    if (mMetricsStats.find(key) != mMetricsStats.end()) {
+        const auto& conditionStats = mMetricsStats[key];
+        for (const auto& stats : conditionStats) {
+            auto output = configStats.add_metric_stats();
+            output->set_name(stats.first);
+            output->set_max_tuple_counts(stats.second);
+            VLOG("metrics %s max output tuple size %d", stats.first.c_str(), stats.second);
+        }
+    }
+}
+
+void StatsdStats::dumpStats(std::vector<uint8_t>* output, bool reset) {
+    lock_guard<std::mutex> lock(mLock);
+
+    if (DEBUG) {
+        time_t t = mStartTimeSec;
+        struct tm* tm = localtime(&t);
+        char timeBuffer[80];
+        strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%d %I:%M%p", tm);
+        VLOG("=================StatsdStats dump begins====================");
+        VLOG("Stats collection start second: %s", timeBuffer);
+    }
+    ProtoOutputStream proto;
+    proto.write(FIELD_TYPE_INT32 | FIELD_ID_BEGIN_TIME, mStartTimeSec);
+    proto.write(FIELD_TYPE_INT32 | FIELD_ID_END_TIME, (int32_t)time(nullptr));
+
+    VLOG("%lu Config in icebox: ", (unsigned long)mIceBox.size());
+    for (const auto& configStats : mIceBox) {
+        const int numBytes = configStats.ByteSize();
+        vector<char> buffer(numBytes);
+        configStats.SerializeToArray(&buffer[0], numBytes);
+        proto.write(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_CONFIG_STATS, &buffer[0],
+                    buffer.size());
+
+        // surround the whole block with DEBUG, so that compiler can strip out the code
+        // in production.
+        if (DEBUG) {
+            VLOG("*****ICEBOX*****");
+            VLOG("Config {%d-%s}: creation=%d, deletion=%d, #metric=%d, #condition=%d, "
+                 "#matcher=%d, #alert=%d,  #valid=%d",
+                 configStats.uid(), configStats.name().c_str(), configStats.creation_time_sec(),
+                 configStats.deletion_time_sec(), configStats.metric_count(),
+                 configStats.condition_count(), configStats.matcher_count(),
+                 configStats.alert_count(), configStats.is_valid());
+
+            for (const auto& broadcastTime : configStats.broadcast_sent_time_sec()) {
+                VLOG("\tbroadcast time: %d", broadcastTime);
+            }
+
+            for (const auto& dataDropTime : configStats.data_drop_time_sec()) {
+                VLOG("\tdata drop time: %d", dataDropTime);
+            }
+        }
+    }
+
+    for (auto& pair : mConfigStats) {
+        auto& configStats = pair.second;
+        if (DEBUG) {
+            VLOG("********Active Configs***********");
+            VLOG("Config {%d-%s}: creation=%d, deletion=%d, #metric=%d, #condition=%d, "
+                 "#matcher=%d, #alert=%d,  #valid=%d",
+                 configStats.uid(), configStats.name().c_str(), configStats.creation_time_sec(),
+                 configStats.deletion_time_sec(), configStats.metric_count(),
+                 configStats.condition_count(), configStats.matcher_count(),
+                 configStats.alert_count(), configStats.is_valid());
+            for (const auto& broadcastTime : configStats.broadcast_sent_time_sec()) {
+                VLOG("\tbroadcast time: %d", broadcastTime);
+            }
+
+            for (const auto& dataDropTime : configStats.data_drop_time_sec()) {
+                VLOG("\tdata drop time: %d", dataDropTime);
+            }
+
+            for (const auto& dumpTime : configStats.dump_report_time_sec()) {
+                VLOG("\tdump report time: %d", dumpTime);
+            }
+        }
+
+        addSubStatsToConfig(pair.first, configStats);
+
+        const int numBytes = configStats.ByteSize();
+        vector<char> buffer(numBytes);
+        configStats.SerializeToArray(&buffer[0], numBytes);
+        proto.write(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_CONFIG_STATS, &buffer[0],
+                    buffer.size());
+        // reset the sub stats, the source of truth is in the individual map
+        // they will be repopulated when dumpStats() is called again.
+        configStats.clear_matcher_stats();
+        configStats.clear_condition_stats();
+        configStats.clear_metric_stats();
+    }
+
+    VLOG("********Atom stats***********");
+    const size_t atomCounts = mPushedAtomStats.size();
+    for (size_t i = 2; i < atomCounts; i++) {
+        if (mPushedAtomStats[i] > 0) {
+            long long token =
+                    proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_ATOM_STATS | FIELD_COUNT_REPEATED);
+            proto.write(FIELD_TYPE_INT32 | FIELD_ID_ATOM_STATS_TAG, (int32_t)i);
+            proto.write(FIELD_TYPE_INT32 | FIELD_ID_ATOM_STATS_COUNT, mPushedAtomStats[i]);
+            proto.end(token);
+
+            VLOG("Atom %lu->%d\n", (unsigned long)i, mPushedAtomStats[i]);
+        }
+    }
+
+    output->clear();
+    size_t bufferSize = proto.size();
+    output->resize(bufferSize);
+
+    size_t pos = 0;
+    auto it = proto.data();
+    while (it.readBuffer() != NULL) {
+        size_t toRead = it.currentToRead();
+        std::memcpy(&((*output)[pos]), it.readBuffer(), toRead);
+        pos += toRead;
+        it.rp()->move(toRead);
+    }
+
+    if (reset) {
+        resetInternalLocked();
+    }
+
+    VLOG("reset=%d, returned proto size %lu", reset, (unsigned long)bufferSize);
+    VLOG("=================StatsdStats dump ends====================");
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
new file mode 100644
index 0000000..6fd9e4b
--- /dev/null
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "config/ConfigKey.h"
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+
+#include <gtest/gtest_prod.h>
+#include <mutex>
+#include <string>
+#include <vector>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+// Keeps track of stats of statsd.
+// Single instance shared across the process. All methods are thread safe.
+class StatsdStats {
+public:
+    static StatsdStats& getInstance();
+    ~StatsdStats(){};
+
+    // TODO: set different limit if the device is low ram.
+    const static int kDimensionKeySizeSoftLimit = 300;
+    const static int kDimensionKeySizeHardLimit = 500;
+
+    const static int kMaxConfigCount = 10;
+    const static int kMaxConditionCountPerConfig = 200;
+    const static int kMaxMetricCountPerConfig = 300;
+    const static int kMaxMatcherCountPerConfig = 500;
+
+    /**
+     * Report a new config has been received and report the static stats about the config.
+     *
+     * The static stats include: the count of metrics, conditions, matchers, and alerts.
+     * If the config is not valid, this config stats will be put into icebox immediately.
+     */
+    void noteConfigReceived(const ConfigKey& key, int metricsCount, int conditionsCount,
+                            int matchersCount, int alertCount, bool isValid);
+    /**
+     * Report a config has been removed.
+     */
+    void noteConfigRemoved(const ConfigKey& key);
+
+    /**
+     * Report a broadcast has been sent to a config owner to collect the data.
+     */
+    void noteBroadcastSent(const ConfigKey& key);
+
+    /**
+     * Report a config's metrics data has been dropped.
+     */
+    void noteDataDropped(const ConfigKey& key);
+
+    /**
+     * Report metrics data report has been sent.
+     *
+     * The report may be requested via StatsManager API, or through adb cmd.
+     */
+    void noteMetricsReportSent(const ConfigKey& key);
+
+    /**
+     * Report the size of output tuple of a condition.
+     *
+     * Note: only report when the condition has an output dimension, and the tuple
+     * count > kDimensionKeySizeSoftLimit.
+     *
+     * [key]: The config key that this condition belongs to.
+     * [name]: The name of the condition.
+     * [size]: The output tuple size.
+     */
+    void noteConditionDimensionSize(const ConfigKey& key, const std::string& name, int size);
+
+    /**
+     * Report the size of output tuple of a metric.
+     *
+     * Note: only report when the metric has an output dimension, and the tuple
+     * count > kDimensionKeySizeSoftLimit.
+     *
+     * [key]: The config key that this metric belongs to.
+     * [name]: The name of the metric.
+     * [size]: The output tuple size.
+     */
+    void noteMetricDimensionSize(const ConfigKey& key, const std::string& name, int size);
+
+    /**
+     * Report a matcher has been matched.
+     *
+     * [key]: The config key that this matcher belongs to.
+     * [name]: The name of the matcher.
+     */
+    void noteMatcherMatched(const ConfigKey& key, const std::string& name);
+
+    /**
+     * Report an atom event has been logged.
+     */
+    void noteAtomLogged(int atomId, int32_t timeSec);
+
+    /**
+     * Reset the historical stats. Including all stats in icebox, and the tracked stats about
+     * metrics, matchers, and atoms. The active configs will be kept and StatsdStats will continue
+     * to collect stats after reset() has been called.
+     */
+    void reset();
+
+    /**
+     * Output the stats in protobuf binary format to [buffer].
+     *
+     * [reset]: whether to clear the historical stats after the call.
+     */
+    void dumpStats(std::vector<uint8_t>* buffer, bool reset);
+
+private:
+    StatsdStats();
+
+    mutable std::mutex mLock;
+
+    int32_t mStartTimeSec;
+
+    // The stats about the configs that are still in use.
+    std::map<const ConfigKey, StatsdStatsReport_ConfigStats> mConfigStats;
+
+    // Stores the stats for the configs that are no longer in use.
+    std::vector<const StatsdStatsReport_ConfigStats> mIceBox;
+
+    // Stores the number of output tuple of condition trackers when it's bigger than
+    // kDimensionKeySizeSoftLimit. When you see the number is kDimensionKeySizeHardLimit +1,
+    // it means some data has been dropped.
+    std::map<const ConfigKey, std::map<const std::string, int>> mConditionStats;
+
+    // Stores the number of output tuple of metric producers when it's bigger than
+    // kDimensionKeySizeSoftLimit. When you see the number is kDimensionKeySizeHardLimit +1,
+    // it means some data has been dropped.
+    std::map<const ConfigKey, std::map<const std::string, int>> mMetricsStats;
+
+    // Stores the number of times a pushed atom is logged.
+    // The size of the vector is the largest pushed atom id in atoms.proto + 1. Atoms
+    // out of that range will be dropped (it's either pulled atoms or test atoms).
+    // This is a vector, not a map because it will be accessed A LOT -- for each stats log.
+    std::vector<int> mPushedAtomStats;
+
+    // Stores how many times a matcher have been matched.
+    std::map<const ConfigKey, std::map<const std::string, int>> mMatcherStats;
+
+    void noteConfigRemovedInternalLocked(const ConfigKey& key);
+
+    void resetInternalLocked();
+
+    void addSubStatsToConfig(const ConfigKey& key, StatsdStatsReport_ConfigStats& configStats);
+
+    FRIEND_TEST(StatsdStatsTest, TestValidConfigAdd);
+    FRIEND_TEST(StatsdStatsTest, TestInvalidConfigAdd);
+    FRIEND_TEST(StatsdStatsTest, TestConfigRemove);
+    FRIEND_TEST(StatsdStatsTest, TestSubStats);
+    FRIEND_TEST(StatsdStatsTest, TestAtomLog);
+};
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/matchers/LogMatchingTracker.h b/cmds/statsd/src/matchers/LogMatchingTracker.h
index ffbf248..fea3e9b 100644
--- a/cmds/statsd/src/matchers/LogMatchingTracker.h
+++ b/cmds/statsd/src/matchers/LogMatchingTracker.h
@@ -69,6 +69,10 @@
         return mTagIds;
     }
 
+    const std::string& getName() const {
+        return mName;
+    }
+
 protected:
     // Name of this matching. We don't really need the name, but it makes log message easy to debug.
     const std::string mName;
diff --git a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
index b2c88a0..ad37b01 100644
--- a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
+++ b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
@@ -19,8 +19,6 @@
 
 #include "SimpleLogMatchingTracker.h"
 
-#include <log/logprint.h>
-
 namespace android {
 namespace os {
 namespace statsd {
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 149b9c1..4338399 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -18,6 +18,7 @@
 #include "Log.h"
 
 #include "CountMetricProducer.h"
+#include "guardrail/StatsdStats.h"
 #include "stats_util.h"
 
 #include <limits.h>
@@ -61,12 +62,11 @@
 const int FIELD_ID_END_BUCKET_NANOS = 2;
 const int FIELD_ID_COUNT = 3;
 
-// TODO: add back AnomalyTracker.
-
-CountMetricProducer::CountMetricProducer(const CountMetric& metric, const int conditionIndex,
+CountMetricProducer::CountMetricProducer(const ConfigKey& key, const CountMetric& metric,
+                                         const int conditionIndex,
                                          const sp<ConditionWizard>& wizard,
                                          const uint64_t startTimeNs)
-    : MetricProducer(startTimeNs, conditionIndex, wizard), mMetric(metric) {
+    : MetricProducer(key, startTimeNs, conditionIndex, wizard), mMetric(metric) {
     // TODO: evaluate initial conditions. and set mConditionMet.
     if (metric.has_bucket() && metric.bucket().has_bucket_size_millis()) {
         mBucketSizeNs = metric.bucket().bucket_size_millis() * 1000 * 1000;
@@ -94,6 +94,8 @@
 }
 
 void CountMetricProducer::startNewProtoOutputStream(long long startTime) {
+    std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
+
     mProto = std::make_unique<ProtoOutputStream>();
     mProto->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mMetric.name());
     mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, startTime);
@@ -107,13 +109,8 @@
     VLOG("Metric %s onSlicedConditionMayChange", mMetric.name().c_str());
 }
 
-std::unique_ptr<std::vector<uint8_t>> CountMetricProducer::onDumpReport() {
-    long long endTime = time(nullptr) * NS_PER_SEC;
-
-    // Dump current bucket if it's stale.
-    // If current bucket is still on-going, don't force dump current bucket.
-    // In finish(), We can force dump current bucket.
-    flushIfNeeded(endTime);
+void CountMetricProducer::serializeBuckets() {
+    std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
     VLOG("metric %s dump report now...", mMetric.name().c_str());
 
     for (const auto& counter : mPastBuckets) {
@@ -159,27 +156,59 @@
         }
         mProto->end(wrapperToken);
     }
-
     mProto->end(mProtoToken);
     mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS,
                   (long long)mCurrentBucketStartTimeNs);
 
+    mPastBuckets.clear();
+    // TODO: Clear mDimensionKeyMap once the report is dumped.
+}
+
+std::unique_ptr<std::vector<uint8_t>> CountMetricProducer::onDumpReport() {
+    long long endTime = time(nullptr) * NS_PER_SEC;
     VLOG("metric %s dump report now...", mMetric.name().c_str());
+    // Dump current bucket if it's stale.
+    // If current bucket is still on-going, don't force dump current bucket.
+    // In finish(), We can force dump current bucket.
+    flushIfNeeded(endTime);
+
+    // TODO(yanglu): merge these three functions to one to avoid three locks.
+    serializeBuckets();
+
     std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
 
     startNewProtoOutputStream(endTime);
-    mPastBuckets.clear();
 
     return buffer;
-
-    // TODO: Clear mDimensionKeyMap once the report is dumped.
 }
 
 void CountMetricProducer::onConditionChanged(const bool conditionMet, const uint64_t eventTime) {
     VLOG("Metric %s onConditionChanged", mMetric.name().c_str());
+    std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
     mCondition = conditionMet;
 }
 
+bool CountMetricProducer::hitGuardRail(const HashableDimensionKey& newKey) {
+    std::shared_lock<std::shared_timed_mutex> readLock(mRWMutex);
+    if (mCurrentSlicedCounter->find(newKey) != mCurrentSlicedCounter->end()) {
+        return false;
+    }
+    // ===========GuardRail==============
+    // 1. Report the tuple count if the tuple count > soft limit
+    if (mCurrentSlicedCounter->size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
+        size_t newTupleCount = mCurrentSlicedCounter->size() + 1;
+        StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetric.name(),
+                                                           newTupleCount);
+        // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
+        if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
+            ALOGE("CountMetric %s dropping data for dimension key %s", mMetric.name().c_str(),
+                  newKey.c_str());
+            return true;
+        }
+    }
+
+    return false;
+}
 void CountMetricProducer::onMatchedLogEventInternal(
         const size_t matcherIndex, const HashableDimensionKey& eventKey,
         const map<string, HashableDimensionKey>& conditionKey, bool condition,
@@ -188,33 +217,40 @@
 
     flushIfNeeded(eventTimeNs);
 
-    if (condition == false) {
+    // ===========GuardRail==============
+    if (hitGuardRail(eventKey)) {
         return;
     }
 
-    auto it = mCurrentSlicedCounter->find(eventKey);
+    // TODO(yanglu): move the following logic to a seperate function to make it lockable.
+    {
+        std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
+        if (condition == false) {
+            return;
+        }
 
-    if (it == mCurrentSlicedCounter->end()) {
-        // create a counter for the new key
-        (*mCurrentSlicedCounter)[eventKey] = 1;
-    } else {
-        // increment the existing value
-        auto& count = it->second;
-        count++;
+        auto it = mCurrentSlicedCounter->find(eventKey);
+        if (it == mCurrentSlicedCounter->end()) {
+            // create a counter for the new key
+            mCurrentSlicedCounter->insert({eventKey, 1});
+        } else {
+            // increment the existing value
+            auto& count = it->second;
+            count++;
+        }
+        const int64_t& count = mCurrentSlicedCounter->find(eventKey)->second;
+        for (auto& tracker : mAnomalyTrackers) {
+            tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, eventKey, count);
+        }
+        VLOG("metric %s %s->%lld", mMetric.name().c_str(), eventKey.c_str(), (long long)(count));
     }
-
-    for (auto& tracker : mAnomalyTrackers) {
-        tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, eventKey,
-                                         mCurrentSlicedCounter->find(eventKey)->second);
-    }
-
-    VLOG("metric %s %s->%lld", mMetric.name().c_str(), eventKey.c_str(),
-         (long long)(*mCurrentSlicedCounter)[eventKey]);
 }
 
 // When a new matched event comes in, we check if event falls into the current
 // bucket. If not, flush the old counter to past buckets and initialize the new bucket.
 void CountMetricProducer::flushIfNeeded(const uint64_t eventTimeNs) {
+    std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
+
     if (eventTimeNs < mCurrentBucketStartTimeNs + mBucketSizeNs) {
         return;
     }
@@ -248,6 +284,7 @@
 // greater than actual data size as it contains each dimension of
 // CountMetricData is  duplicated.
 size_t CountMetricProducer::byteSize() const {
+    std::shared_lock<std::shared_timed_mutex> readLock(mRWMutex);
     size_t totalSize = 0;
     for (const auto& pair : mPastBuckets) {
         totalSize += pair.second.size() * kBucketSize;
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index 293e5b9..164dfb2 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -42,8 +42,9 @@
 class CountMetricProducer : public MetricProducer {
 public:
     // TODO: Pass in the start time from MetricsManager, it should be consistent for all metrics.
-    CountMetricProducer(const CountMetric& countMetric, const int conditionIndex,
-                        const sp<ConditionWizard>& wizard, const uint64_t startTimeNs);
+    CountMetricProducer(const ConfigKey& key, const CountMetric& countMetric,
+                        const int conditionIndex, const sp<ConditionWizard>& wizard,
+                        const uint64_t startTimeNs);
 
     virtual ~CountMetricProducer();
 
@@ -74,6 +75,8 @@
     void startNewProtoOutputStream(long long timestamp) override;
 
 private:
+    void serializeBuckets();
+
     const CountMetric mMetric;
 
     // TODO: Add a lock to mPastBuckets.
@@ -84,6 +87,8 @@
 
     static const size_t kBucketSize = sizeof(CountBucket{});
 
+    bool hitGuardRail(const HashableDimensionKey& newKey);
+
     FRIEND_TEST(CountMetricProducerTest, TestNonDimensionalEvents);
     FRIEND_TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition);
     FRIEND_TEST(CountMetricProducerTest, TestEventsWithSlicedCondition);
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 0ee7dcd..3b49b9a 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -18,6 +18,7 @@
 
 #include "Log.h"
 #include "DurationMetricProducer.h"
+#include "guardrail/StatsdStats.h"
 #include "stats_util.h"
 
 #include <limits.h>
@@ -60,14 +61,14 @@
 const int FIELD_ID_END_BUCKET_NANOS = 2;
 const int FIELD_ID_DURATION = 3;
 
-DurationMetricProducer::DurationMetricProducer(const DurationMetric& metric,
+DurationMetricProducer::DurationMetricProducer(const ConfigKey& key, const DurationMetric& metric,
                                                const int conditionIndex, const size_t startIndex,
                                                const size_t stopIndex, const size_t stopAllIndex,
                                                const bool nesting,
                                                const sp<ConditionWizard>& wizard,
                                                const vector<KeyMatcher>& internalDimension,
                                                const uint64_t startTimeNs)
-    : MetricProducer(startTimeNs, conditionIndex, wizard),
+    : MetricProducer(key, startTimeNs, conditionIndex, wizard),
       mMetric(metric),
       mStartIndex(startIndex),
       mStopIndex(stopIndex),
@@ -103,6 +104,7 @@
 }
 
 void DurationMetricProducer::startNewProtoOutputStream(long long startTime) {
+    std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
     mProto = std::make_unique<ProtoOutputStream>();
     mProto->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mMetric.name());
     mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, startTime);
@@ -110,16 +112,16 @@
 }
 
 unique_ptr<DurationTracker> DurationMetricProducer::createDurationTracker(
-        const HashableDimensionKey& eventKey, vector<DurationBucket>& bucket) {
+        const HashableDimensionKey& eventKey, vector<DurationBucket>& bucket) const {
     switch (mMetric.aggregation_type()) {
         case DurationMetric_AggregationType_SUM:
-            return make_unique<OringDurationTracker>(eventKey, mWizard, mConditionTrackerIndex,
-                                                     mNested, mCurrentBucketStartTimeNs,
-                                                     mBucketSizeNs, mAnomalyTrackers, bucket);
+            return make_unique<OringDurationTracker>(
+                    mConfigKey, mMetric.name(), eventKey, mWizard, mConditionTrackerIndex, mNested,
+                    mCurrentBucketStartTimeNs, mBucketSizeNs, mAnomalyTrackers, bucket);
         case DurationMetric_AggregationType_MAX_SPARSE:
-            return make_unique<MaxDurationTracker>(eventKey, mWizard, mConditionTrackerIndex,
-                                                   mNested, mCurrentBucketStartTimeNs,
-                                                   mBucketSizeNs, mAnomalyTrackers, bucket);
+            return make_unique<MaxDurationTracker>(
+                    mConfigKey, mMetric.name(), eventKey, mWizard, mConditionTrackerIndex, mNested,
+                    mCurrentBucketStartTimeNs, mBucketSizeNs, mAnomalyTrackers, bucket);
     }
 }
 
@@ -129,7 +131,9 @@
 }
 
 void DurationMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
+    std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
     VLOG("Metric %s onSlicedConditionMayChange", mMetric.name().c_str());
+    flushIfNeeded(eventTime);
     // Now for each of the on-going event, check if the condition has changed for them.
     for (auto& pair : mCurrentSlicedDuration) {
         pair.second->onSlicedConditionMayChange(eventTime);
@@ -137,8 +141,10 @@
 }
 
 void DurationMetricProducer::onConditionChanged(const bool conditionMet, const uint64_t eventTime) {
+    std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
     VLOG("Metric %s onConditionChanged", mMetric.name().c_str());
     mCondition = conditionMet;
+    flushIfNeeded(eventTime);
     // TODO: need to populate the condition change time from the event which triggers the condition
     // change, instead of using current time.
     for (auto& pair : mCurrentSlicedDuration) {
@@ -146,15 +152,8 @@
     }
 }
 
-std::unique_ptr<std::vector<uint8_t>> DurationMetricProducer::onDumpReport() {
-    long long endTime = time(nullptr) * NS_PER_SEC;
-
-    // Dump current bucket if it's stale.
-    // If current bucket is still on-going, don't force dump current bucket.
-    // In finish(), We can force dump current bucket.
-    flushIfNeeded(endTime);
-    VLOG("metric %s dump report now...", mMetric.name().c_str());
-
+void DurationMetricProducer::SerializeBuckets() {
+    std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
     for (const auto& pair : mPastBuckets) {
         const HashableDimensionKey& hashableKey = pair.first;
         VLOG("  dimension key %s", hashableKey.c_str());
@@ -211,13 +210,29 @@
     mProto->end(mProtoToken);
     mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS,
                   (long long)mCurrentBucketStartTimeNs);
+}
+
+std::unique_ptr<std::vector<uint8_t>> DurationMetricProducer::onDumpReport() {
+    VLOG("metric %s dump report now...", mMetric.name().c_str());
+
+    long long endTime = time(nullptr) * NS_PER_SEC;
+
+    // Dump current bucket if it's stale.
+    // If current bucket is still on-going, don't force dump current bucket.
+    // In finish(), We can force dump current bucket.
+    flushIfNeeded(endTime);
+
+    SerializeBuckets();
+
     std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
+
     startNewProtoOutputStream(endTime);
     // TODO: Properly clear the old buckets.
     return buffer;
 }
 
 void DurationMetricProducer::flushIfNeeded(uint64_t eventTime) {
+    std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
     if (mCurrentBucketStartTimeNs + mBucketSizeNs > eventTime) {
         return;
     }
@@ -236,35 +251,64 @@
     mCurrentBucketNum += numBucketsForward;
 }
 
+bool DurationMetricProducer::hitGuardRail(const HashableDimensionKey& newKey) {
+    std::shared_lock<std::shared_timed_mutex> readLock(mRWMutex);
+    // the key is not new, we are good.
+    if (mCurrentSlicedDuration.find(newKey) != mCurrentSlicedDuration.end()) {
+        return false;
+    }
+    // 1. Report the tuple count if the tuple count > soft limit
+    if (mCurrentSlicedDuration.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
+        size_t newTupleCount = mCurrentSlicedDuration.size() + 1;
+        StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetric.name(),
+                                                           newTupleCount);
+        // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
+        if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
+            ALOGE("DurationMetric %s dropping data for dimension key %s", mMetric.name().c_str(),
+                  newKey.c_str());
+            return true;
+        }
+    }
+    return false;
+}
+
 void DurationMetricProducer::onMatchedLogEventInternal(
         const size_t matcherIndex, const HashableDimensionKey& eventKey,
         const map<string, HashableDimensionKey>& conditionKeys, bool condition,
         const LogEvent& event, bool scheduledPull) {
     flushIfNeeded(event.GetTimestampNs());
 
-    if (matcherIndex == mStopAllIndex) {
-        for (auto& pair : mCurrentSlicedDuration) {
-            pair.second->noteStopAll(event.GetTimestampNs());
+    // TODO(yanglu): move the following logic to a seperate function to make it lockable.
+    {
+        std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
+        if (matcherIndex == mStopAllIndex) {
+            for (auto& pair : mCurrentSlicedDuration) {
+                pair.second->noteStopAll(event.GetTimestampNs());
+            }
+            return;
         }
-        return;
-    }
 
-    HashableDimensionKey atomKey = getHashableKey(getDimensionKey(event, mInternalDimension));
+        HashableDimensionKey atomKey = getHashableKey(getDimensionKey(event, mInternalDimension));
 
-    if (mCurrentSlicedDuration.find(eventKey) == mCurrentSlicedDuration.end()) {
-        mCurrentSlicedDuration[eventKey] = createDurationTracker(eventKey, mPastBuckets[eventKey]);
-    }
+        if (mCurrentSlicedDuration.find(eventKey) == mCurrentSlicedDuration.end()) {
+            if (hitGuardRail(eventKey)) {
+                return;
+            }
+            mCurrentSlicedDuration[eventKey] =
+                    createDurationTracker(eventKey, mPastBuckets[eventKey]);
+        }
+        auto it = mCurrentSlicedDuration.find(eventKey);
 
-    auto it = mCurrentSlicedDuration.find(eventKey);
-
-    if (matcherIndex == mStartIndex) {
-        it->second->noteStart(atomKey, condition, event.GetTimestampNs(), conditionKeys);
-    } else if (matcherIndex == mStopIndex) {
-        it->second->noteStop(atomKey, event.GetTimestampNs(), false);
+        if (matcherIndex == mStartIndex) {
+            it->second->noteStart(atomKey, condition, event.GetTimestampNs(), conditionKeys);
+        } else if (matcherIndex == mStopIndex) {
+            it->second->noteStop(atomKey, event.GetTimestampNs(), false);
+        }
     }
 }
 
 size_t DurationMetricProducer::byteSize() const {
+    std::shared_lock<std::shared_timed_mutex> readLock(mRWMutex);
     size_t totalSize = 0;
     for (const auto& pair : mPastBuckets) {
         totalSize += pair.second.size() * kBucketSize;
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index ebd5e8d..68fff48 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -37,9 +37,9 @@
 
 class DurationMetricProducer : public MetricProducer {
 public:
-    DurationMetricProducer(const DurationMetric& durationMetric, const int conditionIndex,
-                           const size_t startIndex, const size_t stopIndex,
-                           const size_t stopAllIndex, const bool nesting,
+    DurationMetricProducer(const ConfigKey& key, const DurationMetric& durationMetric,
+                           const int conditionIndex, const size_t startIndex,
+                           const size_t stopIndex, const size_t stopAllIndex, const bool nesting,
                            const sp<ConditionWizard>& wizard,
                            const vector<KeyMatcher>& internalDimension, const uint64_t startTimeNs);
 
@@ -71,6 +71,8 @@
     void startNewProtoOutputStream(long long timestamp) override;
 
 private:
+    void SerializeBuckets();
+
     const DurationMetric mMetric;
 
     // Index of the SimpleLogEntryMatcher which defines the start.
@@ -96,8 +98,9 @@
     std::unordered_map<HashableDimensionKey, std::unique_ptr<DurationTracker>>
             mCurrentSlicedDuration;
 
-    std::unique_ptr<DurationTracker> createDurationTracker(const HashableDimensionKey& eventKey,
-                                                           std::vector<DurationBucket>& bucket);
+    std::unique_ptr<DurationTracker> createDurationTracker(
+            const HashableDimensionKey& eventKey, std::vector<DurationBucket>& bucket) const;
+    bool hitGuardRail(const HashableDimensionKey& newKey);
 
     static const size_t kBucketSize = sizeof(DurationBucket{});
 };
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index 567b4c7..53f112a 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -51,10 +51,11 @@
 const int FIELD_ID_TIMESTAMP_NANOS = 1;
 const int FIELD_ID_ATOMS = 2;
 
-EventMetricProducer::EventMetricProducer(const EventMetric& metric, const int conditionIndex,
+EventMetricProducer::EventMetricProducer(const ConfigKey& key, const EventMetric& metric,
+                                         const int conditionIndex,
                                          const sp<ConditionWizard>& wizard,
                                          const uint64_t startTimeNs)
-    : MetricProducer(startTimeNs, conditionIndex, wizard), mMetric(metric) {
+    : MetricProducer(key, startTimeNs, conditionIndex, wizard), mMetric(metric) {
     if (metric.links().size() > 0) {
         mConditionLinks.insert(mConditionLinks.begin(), metric.links().begin(),
                                metric.links().end());
@@ -72,6 +73,7 @@
 }
 
 void EventMetricProducer::startNewProtoOutputStream(long long startTime) {
+    std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
     mProto = std::make_unique<ProtoOutputStream>();
     // TODO: We need to auto-generate the field IDs for StatsLogReport, EventMetricData,
     // and StatsEvent.
@@ -88,11 +90,16 @@
 
 std::unique_ptr<std::vector<uint8_t>> EventMetricProducer::onDumpReport() {
     long long endTime = time(nullptr) * NS_PER_SEC;
-    mProto->end(mProtoToken);
-    mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS, endTime);
+    // TODO(yanglu): make this section to an util function.
+    {
+        std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
+        mProto->end(mProtoToken);
+        mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS, endTime);
 
-    size_t bufferSize = mProto->size();
-    VLOG("metric %s dump report now... proto size: %zu ", mMetric.name().c_str(), bufferSize);
+        size_t bufferSize = mProto->size();
+        VLOG("metric %s dump report now... proto size: %zu ", mMetric.name().c_str(), bufferSize);
+    }
+
     std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
 
     startNewProtoOutputStream(endTime);
@@ -102,6 +109,7 @@
 
 void EventMetricProducer::onConditionChanged(const bool conditionMet, const uint64_t eventTime) {
     VLOG("Metric %s onConditionChanged", mMetric.name().c_str());
+    std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
     mCondition = conditionMet;
 }
 
@@ -109,6 +117,7 @@
         const size_t matcherIndex, const HashableDimensionKey& eventKey,
         const std::map<std::string, HashableDimensionKey>& conditionKey, bool condition,
         const LogEvent& event, bool scheduledPull) {
+    std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
     if (!condition) {
         return;
     }
@@ -123,6 +132,7 @@
 }
 
 size_t EventMetricProducer::byteSize() const {
+    std::shared_lock<std::shared_timed_mutex> readLock(mRWMutex);
     return mProto->bytesWritten();
 }
 
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index 5afcebd..33a9510 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -34,8 +34,9 @@
 class EventMetricProducer : public MetricProducer {
 public:
     // TODO: Pass in the start time from MetricsManager, it should be consistent for all metrics.
-    EventMetricProducer(const EventMetric& eventMetric, const int conditionIndex,
-                        const sp<ConditionWizard>& wizard, const uint64_t startTimeNs);
+    EventMetricProducer(const ConfigKey& key, const EventMetric& eventMetric,
+                        const int conditionIndex, const sp<ConditionWizard>& wizard,
+                        const uint64_t startTimeNs);
 
     virtual ~EventMetricProducer();
 
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index be030d8..ed4c760 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -18,6 +18,7 @@
 #include "Log.h"
 
 #include "GaugeMetricProducer.h"
+#include "guardrail/StatsdStats.h"
 #include "stats_util.h"
 
 #include <cutils/log.h>
@@ -62,10 +63,11 @@
 const int FIELD_ID_END_BUCKET_NANOS = 2;
 const int FIELD_ID_GAUGE = 3;
 
-GaugeMetricProducer::GaugeMetricProducer(const GaugeMetric& metric, const int conditionIndex,
+GaugeMetricProducer::GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& metric,
+                                         const int conditionIndex,
                                          const sp<ConditionWizard>& wizard, const int pullTagId,
                                          const int64_t startTimeNs)
-    : MetricProducer(startTimeNs, conditionIndex, wizard),
+    : MetricProducer(key, startTimeNs, conditionIndex, wizard),
       mMetric(metric),
       mPullTagId(pullTagId) {
     if (metric.has_bucket() && metric.bucket().has_bucket_size_millis()) {
@@ -100,6 +102,7 @@
 }
 
 void GaugeMetricProducer::startNewProtoOutputStream(long long startTime) {
+    std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
     mProto = std::make_unique<ProtoOutputStream>();
     mProto->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mMetric.name());
     mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, startTime);
@@ -109,14 +112,8 @@
 void GaugeMetricProducer::finish() {
 }
 
-std::unique_ptr<std::vector<uint8_t>> GaugeMetricProducer::onDumpReport() {
-    VLOG("gauge metric %s dump report now...", mMetric.name().c_str());
-
-    // Dump current bucket if it's stale.
-    // If current bucket is still on-going, don't force dump current bucket.
-    // In finish(), We can force dump current bucket.
-    flushIfNeeded(time(nullptr) * NS_PER_SEC);
-
+void GaugeMetricProducer::SerializeBuckets() {
+    std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
     for (const auto& pair : mPastBuckets) {
         const HashableDimensionKey& hashableKey = pair.first;
         auto it = mDimensionKeyMap.find(hashableKey);
@@ -164,50 +161,69 @@
     mProto->end(mProtoToken);
     mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS,
                   (long long)mCurrentBucketStartTimeNs);
+    mPastBuckets.clear();
+}
+
+std::unique_ptr<std::vector<uint8_t>> GaugeMetricProducer::onDumpReport() {
+    VLOG("gauge metric %s dump report now...", mMetric.name().c_str());
+
+    // Dump current bucket if it's stale.
+    // If current bucket is still on-going, don't force dump current bucket.
+    // In finish(), We can force dump current bucket.
+    flushIfNeeded(time(nullptr) * NS_PER_SEC);
+
+    SerializeBuckets();
 
     std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
 
     startNewProtoOutputStream(time(nullptr) * NS_PER_SEC);
-    mPastBuckets.clear();
-
     return buffer;
 
     // TODO: Clear mDimensionKeyMap once the report is dumped.
 }
 
 void GaugeMetricProducer::onConditionChanged(const bool conditionMet, const uint64_t eventTime) {
-    AutoMutex _l(mLock);
     VLOG("Metric %s onConditionChanged", mMetric.name().c_str());
-    flushIfNeeded(eventTime);
-    mCondition = conditionMet;
 
-    // Push mode. No need to proactively pull the gauge data.
-    if (mPullTagId == -1) {
-        return;
-    }
-    if (!mCondition) {
-        return;
-    }
-    // Already have gauge metric for the current bucket, do not do it again.
-    if (mCurrentSlicedBucket->size() > 0) {
-        return;
-    }
+    // flushIfNeeded holds the write lock and is thread-safe.
+    flushIfNeeded(eventTime);
+
     vector<std::shared_ptr<LogEvent>> allData;
-    if (!mStatsPullerManager.Pull(mPullTagId, &allData)) {
-        ALOGE("Stats puller failed for tag: %d", mPullTagId);
-        return;
+    // The following section is to update the condition and re-pull the gauge.
+    // TODO(yanglu): make it a seperate lockable function.
+    {
+        std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
+
+        mCondition = conditionMet;
+
+        // Push mode. No need to proactively pull the gauge data.
+        if (mPullTagId == -1) {
+            return;
+        }
+        if (!mCondition) {
+            return;
+        }
+        // Already have gauge metric for the current bucket, do not do it again.
+        if (mCurrentSlicedBucket->size() > 0) {
+            return;
+        }
+        if (!mStatsPullerManager.Pull(mPullTagId, &allData)) {
+            ALOGE("Stats puller failed for tag: %d", mPullTagId);
+            return;
+        }
     }
+
+    // onMatchedLogEventInternal holds the write lock and is thread-safe.
     for (const auto& data : allData) {
         onMatchedLogEvent(0, *data, false /*scheduledPull*/);
     }
-    flushIfNeeded(eventTime);
 }
 
 void GaugeMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
     VLOG("Metric %s onSlicedConditionMayChange", mMetric.name().c_str());
 }
 
-int64_t GaugeMetricProducer::getGauge(const LogEvent& event) {
+int64_t GaugeMetricProducer::getGauge(const LogEvent& event) const {
     status_t err = NO_ERROR;
     int64_t val = event.GetLong(mMetric.gauge_field(), &err);
     if (err == NO_ERROR) {
@@ -219,39 +235,63 @@
 }
 
 void GaugeMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData) {
-    AutoMutex mutex(mLock);
+    // onMatchedLogEventInternal holds the write lock and is thread-safe.
     for (const auto& data : allData) {
         onMatchedLogEvent(0, *data, true /*scheduledPull*/);
     }
 }
 
+bool GaugeMetricProducer::hitGuardRail(const HashableDimensionKey& newKey) {
+    std::shared_lock<std::shared_timed_mutex> readLock(mRWMutex);
+    if (mCurrentSlicedBucket->find(newKey) != mCurrentSlicedBucket->end()) {
+        return false;
+    }
+    // 1. Report the tuple count if the tuple count > soft limit
+    if (mCurrentSlicedBucket->size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
+        size_t newTupleCount = mCurrentSlicedBucket->size() + 1;
+        StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetric.name(),
+                                                           newTupleCount);
+        // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
+        if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
+            ALOGE("GaugeMetric %s dropping data for dimension key %s", mMetric.name().c_str(),
+                  newKey.c_str());
+            return true;
+        }
+    }
+
+    return false;
+}
+
 void GaugeMetricProducer::onMatchedLogEventInternal(
         const size_t matcherIndex, const HashableDimensionKey& eventKey,
         const map<string, HashableDimensionKey>& conditionKey, bool condition,
         const LogEvent& event, bool scheduledPull) {
+    uint64_t eventTimeNs = event.GetTimestampNs();
+    flushIfNeeded(eventTimeNs);
+
     if (condition == false) {
         return;
     }
-    uint64_t eventTimeNs = event.GetTimestampNs();
+    const long gauge = getGauge(event);
+    if (gauge < 0) {
+        return;
+    }
+    if (hitGuardRail(eventKey)) {
+        return;
+    }
+
+    std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
     if (eventTimeNs < mCurrentBucketStartTimeNs) {
         VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
              (long long)mCurrentBucketStartTimeNs);
         return;
     }
 
-    // When the event happens in a new bucket, flush the old buckets.
-    if (eventTimeNs >= mCurrentBucketStartTimeNs + mBucketSizeNs) {
-        flushIfNeeded(eventTimeNs);
-    }
-
-    // For gauge metric, we just simply use the first guage in the given bucket.
+    // For gauge metric, we just simply use the first gauge in the given bucket.
     if (!mCurrentSlicedBucket->empty()) {
         return;
     }
-    const long gauge = getGauge(event);
-    if (gauge >= 0) {
         (*mCurrentSlicedBucket)[eventKey] = gauge;
-    }
     for (auto& tracker : mAnomalyTrackers) {
         tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, eventKey, gauge);
     }
@@ -263,6 +303,7 @@
 // if data is pushed, onMatchedLogEvent will only be called through onConditionChanged() inside
 // the GaugeMetricProducer while holding the lock.
 void GaugeMetricProducer::flushIfNeeded(const uint64_t eventTimeNs) {
+    std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
     if (eventTimeNs < mCurrentBucketStartTimeNs + mBucketSizeNs) {
         return;
     }
@@ -296,6 +337,7 @@
 }
 
 size_t GaugeMetricProducer::byteSize() const {
+    std::shared_lock<std::shared_timed_mutex> readLock(mRWMutex);
     size_t totalSize = 0;
     for (const auto& pair : mPastBuckets) {
         totalSize += pair.second.size() * kBucketSize;
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index 4b7654b4..8df6111 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -47,9 +47,9 @@
 public:
     // TODO: Pass in the start time from MetricsManager, it should be consistent
     // for all metrics.
-    GaugeMetricProducer(const GaugeMetric& countMetric, const int conditionIndex,
-                        const sp<ConditionWizard>& wizard, const int pullTagId,
-                        const int64_t startTimeNs);
+    GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& countMetric,
+                        const int conditionIndex, const sp<ConditionWizard>& wizard,
+                        const int pullTagId, const int64_t startTimeNs);
 
     virtual ~GaugeMetricProducer();
 
@@ -81,6 +81,8 @@
     void startNewProtoOutputStream(long long timestamp) override;
 
 private:
+    void SerializeBuckets();
+
     // The default bucket size for gauge metric is 1 second.
     static const uint64_t kDefaultGaugemBucketSizeNs = 1000 * 1000 * 1000;
     const GaugeMetric mMetric;
@@ -89,8 +91,6 @@
     // tagId for pulled data. -1 if this is not pulled
     const int mPullTagId;
 
-    Mutex mLock;
-
     // Save the past buckets and we can clear when the StatsLogReport is dumped.
     // TODO: Add a lock to mPastBuckets.
     std::unordered_map<HashableDimensionKey, std::vector<GaugeBucket>> mPastBuckets;
@@ -98,7 +98,9 @@
     // The current bucket.
     std::shared_ptr<DimToValMap> mCurrentSlicedBucket = std::make_shared<DimToValMap>();
 
-    int64_t getGauge(const LogEvent& event);
+    int64_t getGauge(const LogEvent& event) const;
+
+    bool hitGuardRail(const HashableDimensionKey& newKey);
 
     static const size_t kBucketSize = sizeof(GaugeBucket{});
 
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index 62fb632..7542a94 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -23,6 +23,7 @@
 
 void MetricProducer::onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event,
                                        bool scheduledPull) {
+    std::unique_lock<std::shared_timed_mutex> writeLock(mRWMutex);
     uint64_t eventTimeNs = event.GetTimestampNs();
     // this is old event, maybe statsd restarted?
     if (eventTimeNs < mStartTimeNs) {
@@ -59,12 +60,16 @@
     } else {
         condition = mCondition;
     }
+    // Unlock as onMatchedLogEventInternal is threadsafe.
+    writeLock.unlock();
 
     onMatchedLogEventInternal(matcherIndex, eventKey, conditionKeys, condition, event,
                               scheduledPull);
 }
 
 std::unique_ptr<std::vector<uint8_t>> MetricProducer::serializeProto() {
+    std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
+
     size_t bufferSize = mProto->size();
 
     std::unique_ptr<std::vector<uint8_t>> buffer(new std::vector<uint8_t>(bufferSize));
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index ddccf9a..27343ad 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -17,8 +17,11 @@
 #ifndef METRIC_PRODUCER_H
 #define METRIC_PRODUCER_H
 
+#include <shared_mutex>
+
 #include "anomaly/AnomalyTracker.h"
 #include "condition/ConditionWizard.h"
+#include "config/ConfigKey.h"
 #include "matchers/matcher_util.h"
 #include "packages/PackageInfoListener.h"
 
@@ -35,9 +38,10 @@
 // be a no-op.
 class MetricProducer : public virtual PackageInfoListener {
 public:
-    MetricProducer(const int64_t startTimeNs, const int conditionIndex,
+    MetricProducer(const ConfigKey& key, const int64_t startTimeNs, const int conditionIndex,
                    const sp<ConditionWizard>& wizard)
-        : mStartTimeNs(startTimeNs),
+        : mConfigKey(key),
+          mStartTimeNs(startTimeNs),
           mCurrentBucketStartTimeNs(startTimeNs),
           mCurrentBucketNum(0),
           mCondition(conditionIndex >= 0 ? false : true),
@@ -83,6 +87,8 @@
     }
 
 protected:
+    const ConfigKey mConfigKey;
+
     const uint64_t mStartTimeNs;
 
     uint64_t mCurrentBucketStartTimeNs;
@@ -133,6 +139,10 @@
 
     long long mProtoToken;
 
+    // Read/Write mutex to make the producer thread-safe.
+    // TODO(yanglu): replace with std::shared_mutex when available in libc++.
+    mutable std::shared_timed_mutex mRWMutex;
+
     virtual void startNewProtoOutputStream(long long timestamp) = 0;
 
     std::unique_ptr<std::vector<uint8_t>> serializeProto();
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 5916b040..e986c1a 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -20,6 +20,7 @@
 #include "CountMetricProducer.h"
 #include "condition/CombinationConditionTracker.h"
 #include "condition/SimpleConditionTracker.h"
+#include "guardrail/StatsdStats.h"
 #include "matchers/CombinationLogMatchingTracker.h"
 #include "matchers/SimpleLogMatchingTracker.h"
 #include "metrics_manager_util.h"
@@ -36,10 +37,24 @@
 namespace os {
 namespace statsd {
 
-MetricsManager::MetricsManager(const StatsdConfig& config) {
-    mConfigValid = initStatsdConfig(config, mTagIds, mAllLogEntryMatchers, mAllConditionTrackers,
-                                    mAllMetricProducers, mAllAnomalyTrackers, mConditionToMetricMap,
-                                    mTrackerToMetricMap, mTrackerToConditionMap);
+MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config) : mConfigKey(key) {
+    mConfigValid =
+            initStatsdConfig(key, config, mTagIds, mAllLogEntryMatchers, mAllConditionTrackers,
+                             mAllMetricProducers, mAllAnomalyTrackers, mConditionToMetricMap,
+                             mTrackerToMetricMap, mTrackerToConditionMap);
+
+    // TODO: add alert size.
+    // no matter whether this config is valid, log it in the stats.
+    StatsdStats::getInstance().noteConfigReceived(key, mAllMetricProducers.size(),
+                                                  mAllConditionTrackers.size(),
+                                                  mAllLogEntryMatchers.size(), 0, mConfigValid);
+    // Guardrail. Reject the config if it's too big.
+    if (mAllMetricProducers.size() > StatsdStats::kMaxMetricCountPerConfig ||
+        mAllConditionTrackers.size() > StatsdStats::kMaxConditionCountPerConfig ||
+        mAllLogEntryMatchers.size() > StatsdStats::kMaxMatcherCountPerConfig) {
+        ALOGE("This config is too big! Reject!");
+        mConfigValid = false;
+    }
 }
 
 MetricsManager::~MetricsManager() {
@@ -137,6 +152,8 @@
     // For matched LogEntryMatchers, tell relevant metrics that a matched event has come.
     for (size_t i = 0; i < mAllLogEntryMatchers.size(); i++) {
         if (matcherCache[i] == MatchingState::kMatched) {
+            StatsdStats::getInstance().noteMatcherMatched(mConfigKey,
+                                                          mAllLogEntryMatchers[i]->getName());
             auto pair = mTrackerToMetricMap.find(i);
             if (pair != mTrackerToMetricMap.end()) {
                 auto& metricList = pair->second;
@@ -151,9 +168,9 @@
 }
 
 void MetricsManager::onAnomalyAlarmFired(const uint64_t timestampNs,
-                                         sp<const AnomalyAlarm> anomaly) {
+                         unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& anomalySet) {
     for (const auto& itr : mAllAnomalyTrackers) {
-        itr->declareAnomaly(timestampNs);
+        itr->informAlarmsFired(timestampNs, anomalySet);
     }
 }
 
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index a6054e3..62b4c87 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -19,6 +19,7 @@
 #include "anomaly/AnomalyMonitor.h"
 #include "anomaly/AnomalyTracker.h"
 #include "condition/ConditionTracker.h"
+#include "config/ConfigKey.h"
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 #include "logd/LogEvent.h"
 #include "matchers/LogMatchingTracker.h"
@@ -33,7 +34,7 @@
 // A MetricsManager is responsible for managing metrics from one single config source.
 class MetricsManager {
 public:
-    MetricsManager(const StatsdConfig& config);
+    MetricsManager(const ConfigKey& configKey, const StatsdConfig& config);
 
     ~MetricsManager();
 
@@ -45,7 +46,8 @@
     // Called when everything should wrap up. We are about to finish (e.g., new config comes).
     void finish();
 
-    void onAnomalyAlarmFired(const uint64_t timestampNs, sp<const AnomalyAlarm> anomaly);
+    void onAnomalyAlarmFired(const uint64_t timestampNs,
+                         unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& anomalySet);
 
     void setAnomalyMonitor(const sp<AnomalyMonitor>& anomalyMonitor);
 
@@ -57,6 +59,8 @@
     size_t byteSize();
 
 private:
+    const ConfigKey mConfigKey;
+
     // All event tags that are interesting to my metrics.
     std::set<int> mTagIds;
 
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index cc02c69..eed7841 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -18,6 +18,7 @@
 #include "Log.h"
 
 #include "ValueMetricProducer.h"
+#include "guardrail/StatsdStats.h"
 
 #include <cutils/log.h>
 #include <limits.h>
@@ -67,11 +68,12 @@
 static const uint64_t kDefaultBucketSizeMillis = 60 * 60 * 1000L;
 
 // ValueMetric has a minimum bucket size of 10min so that we don't pull too frequently
-ValueMetricProducer::ValueMetricProducer(const ValueMetric& metric, const int conditionIndex,
+ValueMetricProducer::ValueMetricProducer(const ConfigKey& key, const ValueMetric& metric,
+                                         const int conditionIndex,
                                          const sp<ConditionWizard>& wizard, const int pullTagId,
                                          const uint64_t startTimeNs,
                                          shared_ptr<StatsPullerManager> statsPullerManager)
-    : MetricProducer(startTimeNs, conditionIndex, wizard),
+    : MetricProducer(key, startTimeNs, conditionIndex, wizard),
       mMetric(metric),
       mStatsPullerManager(statsPullerManager),
       mPullTagId(pullTagId) {
@@ -103,10 +105,11 @@
 }
 
 // for testing
-ValueMetricProducer::ValueMetricProducer(const ValueMetric& metric, const int conditionIndex,
+ValueMetricProducer::ValueMetricProducer(const ConfigKey& key, const ValueMetric& metric,
+                                         const int conditionIndex,
                                          const sp<ConditionWizard>& wizard, const int pullTagId,
                                          const uint64_t startTimeNs)
-    : ValueMetricProducer(metric, conditionIndex, wizard, pullTagId, startTimeNs,
+    : ValueMetricProducer(key, metric, conditionIndex, wizard, pullTagId, startTimeNs,
                           make_shared<StatsPullerManager>()) {
 }
 
@@ -118,6 +121,7 @@
 }
 
 void ValueMetricProducer::startNewProtoOutputStream(long long startTime) {
+    std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
     mProto = std::make_unique<ProtoOutputStream>();
     mProto->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mMetric.name());
     mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, startTime);
@@ -133,9 +137,8 @@
     VLOG("Metric %s onSlicedConditionMayChange", mMetric.name().c_str());
 }
 
-std::unique_ptr<std::vector<uint8_t>> ValueMetricProducer::onDumpReport() {
-    VLOG("metric %s dump report now...", mMetric.name().c_str());
-
+void ValueMetricProducer::SerializeBuckets() {
+    std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
     for (const auto& pair : mPastBuckets) {
         const HashableDimensionKey& hashableKey = pair.first;
         VLOG("  dimension key %s", hashableKey.c_str());
@@ -182,47 +185,63 @@
     mProto->end(mProtoToken);
     mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS,
                   (long long)mCurrentBucketStartTimeNs);
+    mPastBuckets.clear();
+}
 
+std::unique_ptr<std::vector<uint8_t>> ValueMetricProducer::onDumpReport() {
     VLOG("metric %s dump report now...", mMetric.name().c_str());
+
+    SerializeBuckets();
     std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
 
     startNewProtoOutputStream(time(nullptr) * NS_PER_SEC);
-    mPastBuckets.clear();
 
     return buffer;
-
     // TODO: Clear mDimensionKeyMap once the report is dumped.
 }
 
 void ValueMetricProducer::onConditionChanged(const bool condition, const uint64_t eventTime) {
-    AutoMutex _l(mLock);
-    mCondition = condition;
+    vector<shared_ptr<LogEvent>> allData;
 
-    if (mPullTagId != -1) {
+    // TODO(yanglu): move the following logic to a seperate function to make it lockable.
+    {
+        std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
+        mCondition = condition;
+
+        if (mPullTagId == -1) {
+            return;
+        }
+
         if (mCondition == true) {
             mStatsPullerManager->RegisterReceiver(mPullTagId, this,
                                                   mMetric.bucket().bucket_size_millis());
         } else if (mCondition == false) {
             mStatsPullerManager->UnRegisterReceiver(mPullTagId, this);
         }
-
-        vector<shared_ptr<LogEvent>> allData;
-        if (mStatsPullerManager->Pull(mPullTagId, &allData)) {
-            if (allData.size() == 0) {
-                return;
-            }
-            for (const auto& data : allData) {
-                onMatchedLogEvent(0, *data, false);
-            }
-            flushIfNeeded(eventTime);
+        if (!mStatsPullerManager->Pull(mPullTagId, &allData)) {
+            return;
         }
+    }
+
+    if (allData.size() == 0) {
         return;
     }
+
+    // onMatchedLogEventInternal holds the write lock and is thread-safe.
+    for (const auto& data : allData) {
+        onMatchedLogEvent(0, *data, false);
+    }
+    // flushIfNeeded holds the write lock and is thread-safe.
+    flushIfNeeded(eventTime);
+}
+
+bool ValueMetricProducer::IsConditionMet() const {
+    std::shared_lock<std::shared_timed_mutex> readLock(mRWMutex);
+    return mCondition == true || !mMetric.has_condition();
 }
 
 void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData) {
-    AutoMutex _l(mLock);
-    if (mCondition == true || !mMetric.has_condition()) {
+    if (IsConditionMet()) {
         if (allData.size() == 0) {
             return;
         }
@@ -238,55 +257,97 @@
     }
 }
 
-void ValueMetricProducer::onMatchedLogEventInternal(
-        const size_t matcherIndex, const HashableDimensionKey& eventKey,
-        const map<string, HashableDimensionKey>& conditionKey, bool condition,
-        const LogEvent& event, bool scheduledPull) {
-    uint64_t eventTimeNs = event.GetTimestampNs();
+bool ValueMetricProducer::hitGuardRail(const HashableDimensionKey& newKey) {
+    std::shared_lock<std::shared_timed_mutex> readLock(mRWMutex);
+    // ===========GuardRail==============
+    // 1. Report the tuple count if the tuple count > soft limit
+    if (mCurrentSlicedBucket.find(newKey) != mCurrentSlicedBucket.end()) {
+        return false;
+    }
+    if (mCurrentSlicedBucket.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
+        size_t newTupleCount = mCurrentSlicedBucket.size() + 1;
+        StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetric.name(),
+                                                           newTupleCount);
+        // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
+        if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
+            ALOGE("ValueMetric %s dropping data for dimension key %s", mMetric.name().c_str(),
+                  newKey.c_str());
+            return true;
+        }
+    }
+
+    return false;
+}
+
+void ValueMetricProducer::onMatchedLogEventInternal_pull(const uint64_t& eventTimeNs,
+                                                         const HashableDimensionKey& eventKey,
+                                                         const long& value, bool scheduledPull) {
+    std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
+
     if (eventTimeNs < mCurrentBucketStartTimeNs) {
         VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
              (long long)mCurrentBucketStartTimeNs);
         return;
     }
-
     Interval& interval = mCurrentSlicedBucket[eventKey];
-
-    long value = get_value(event);
-
-    if (mPullTagId != -1) {
-        if (scheduledPull) {
-            // scheduled pull always sets beginning of current bucket and end
-            // of next bucket
-            if (interval.raw.size() > 0) {
-                interval.raw.back().second = value;
-            } else {
-                interval.raw.push_back(make_pair(value, value));
-            }
-            Interval& nextInterval = mNextSlicedBucket[eventKey];
-            if (nextInterval.raw.size() == 0) {
-                nextInterval.raw.push_back(make_pair(value, 0));
-            } else {
-                nextInterval.raw.front().first = value;
-            }
+    if (scheduledPull) {
+        // scheduled pull always sets beginning of current bucket and end
+        // of next bucket
+        if (interval.raw.size() > 0) {
+            interval.raw.back().second = value;
         } else {
-            if (mCondition == true) {
-                interval.raw.push_back(make_pair(value, 0));
-            } else {
-                if (interval.raw.size() != 0) {
-                    interval.raw.back().second = value;
-                } else {
-                    interval.tainted = true;
-                    VLOG("Data on condition true missing!");
-                }
-            }
+            interval.raw.push_back(make_pair(value, value));
+        }
+        Interval& nextInterval = mNextSlicedBucket[eventKey];
+        if (nextInterval.raw.size() == 0) {
+            nextInterval.raw.push_back(make_pair(value, 0));
+        } else {
+            nextInterval.raw.front().first = value;
         }
     } else {
-        flushIfNeeded(eventTimeNs);
-        interval.raw.push_back(make_pair(value, 0));
+        if (mCondition == true) {
+            interval.raw.push_back(make_pair(value, 0));
+        } else {
+            if (interval.raw.size() != 0) {
+                interval.raw.back().second = value;
+            } else {
+                interval.tainted = true;
+                VLOG("Data on condition true missing!");
+            }
+        }
     }
 }
 
-long ValueMetricProducer::get_value(const LogEvent& event) {
+void ValueMetricProducer::onMatchedLogEventInternal_push(const uint64_t& eventTimeNs,
+                                                         const HashableDimensionKey& eventKey,
+                                                         const long& value) {
+    std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
+    if (eventTimeNs < mCurrentBucketStartTimeNs) {
+        VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
+             (long long)mCurrentBucketStartTimeNs);
+        return;
+    }
+    mCurrentSlicedBucket[eventKey].raw.push_back(make_pair(value, 0));
+}
+
+void ValueMetricProducer::onMatchedLogEventInternal(
+        const size_t matcherIndex, const HashableDimensionKey& eventKey,
+        const map<string, HashableDimensionKey>& conditionKey, bool condition,
+        const LogEvent& event, bool scheduledPull) {
+    uint64_t eventTimeNs = event.GetTimestampNs();
+    long value = get_value(event);
+    if (hitGuardRail(eventKey)) {
+        return;
+    }
+    if (mPullTagId != -1) {
+        onMatchedLogEventInternal_pull(eventTimeNs, eventKey, value, scheduledPull);
+    } else {
+        flushIfNeeded(eventTimeNs);
+        onMatchedLogEventInternal_push(eventTimeNs, eventKey, value);
+    }
+}
+
+long ValueMetricProducer::get_value(const LogEvent& event) const {
     status_t err = NO_ERROR;
     long val = event.GetLong(mMetric.value_field(), &err);
     if (err == NO_ERROR) {
@@ -298,6 +359,7 @@
 }
 
 void ValueMetricProducer::flushIfNeeded(const uint64_t eventTimeNs) {
+    std::lock_guard<std::shared_timed_mutex> writeLock(mRWMutex);
     if (mCurrentBucketStartTimeNs + mBucketSizeNs > eventTimeNs) {
         VLOG("eventTime is %lld, less than next bucket start time %lld", (long long)eventTimeNs,
              (long long)(mCurrentBucketStartTimeNs + mBucketSizeNs));
@@ -346,6 +408,7 @@
 }
 
 size_t ValueMetricProducer::byteSize() const {
+    std::shared_lock<std::shared_timed_mutex> readLock(mRWMutex);
     size_t totalSize = 0;
     for (const auto& pair : mPastBuckets) {
         totalSize += pair.second.size() * kBucketSize;
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 24c76f2..e87e9da 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -38,9 +38,9 @@
 
 class ValueMetricProducer : public virtual MetricProducer, public virtual PullDataReceiver {
 public:
-    ValueMetricProducer(const ValueMetric& valueMetric, const int conditionIndex,
-                        const sp<ConditionWizard>& wizard, const int pullTagId,
-                        const uint64_t startTimeNs);
+    ValueMetricProducer(const ConfigKey& key, const ValueMetric& valueMetric,
+                        const int conditionIndex, const sp<ConditionWizard>& wizard,
+                        const int pullTagId, const uint64_t startTimeNs);
 
     virtual ~ValueMetricProducer();
 
@@ -72,18 +72,26 @@
     void startNewProtoOutputStream(long long timestamp) override;
 
 private:
+    void onMatchedLogEventInternal_pull(const uint64_t& eventTimeNs,
+                                        const HashableDimensionKey& eventKey, const long& value,
+                                        bool scheduledPull);
+    void onMatchedLogEventInternal_push(const uint64_t& eventTimeNs,
+                                        const HashableDimensionKey& eventKey, const long& value);
+
+    void SerializeBuckets();
+
+    bool IsConditionMet() const;
+
     const ValueMetric mMetric;
 
     std::shared_ptr<StatsPullerManager> mStatsPullerManager;
 
     // for testing
-    ValueMetricProducer(const ValueMetric& valueMetric, const int conditionIndex,
-                        const sp<ConditionWizard>& wizard, const int pullTagId,
-                        const uint64_t startTimeNs,
+    ValueMetricProducer(const ConfigKey& key, const ValueMetric& valueMetric,
+                        const int conditionIndex, const sp<ConditionWizard>& wizard,
+                        const int pullTagId, const uint64_t startTimeNs,
                         std::shared_ptr<StatsPullerManager> statsPullerManager);
 
-    Mutex mLock;
-
     // tagId for pulled data. -1 if this is not pulled
     const int mPullTagId;
 
@@ -102,7 +110,9 @@
     // TODO: Add a lock to mPastBuckets.
     std::unordered_map<HashableDimensionKey, std::vector<ValueBucket>> mPastBuckets;
 
-    long get_value(const LogEvent& event);
+    long get_value(const LogEvent& event) const;
+
+    bool hitGuardRail(const HashableDimensionKey& newKey);
 
     static const size_t kBucketSize = sizeof(ValueBucket{});
 
diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
index 7ce7f02..834f7f5 100644
--- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
@@ -19,6 +19,7 @@
 
 #include "anomaly/AnomalyTracker.h"
 #include "condition/ConditionWizard.h"
+#include "config/ConfigKey.h"
 #include "stats_util.h"
 
 namespace android {
@@ -59,11 +60,14 @@
 
 class DurationTracker {
 public:
-    DurationTracker(const HashableDimensionKey& eventKey, sp<ConditionWizard> wizard,
-                    int conditionIndex, bool nesting, uint64_t currentBucketStartNs,
-                    uint64_t bucketSizeNs, const std::vector<sp<AnomalyTracker>>& anomalyTrackers,
+    DurationTracker(const ConfigKey& key, const string& name, const HashableDimensionKey& eventKey,
+                    sp<ConditionWizard> wizard, int conditionIndex, bool nesting,
+                    uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
+                    const std::vector<sp<AnomalyTracker>>& anomalyTrackers,
                     std::vector<DurationBucket>& bucket)
-        : mEventKey(eventKey),
+        : mConfigKey(key),
+          mName(name),
+          mEventKey(eventKey),
           mWizard(wizard),
           mConditionTrackerIndex(conditionIndex),
           mBucketSizeNs(bucketSizeNs),
@@ -138,6 +142,10 @@
             }
         }
     }
+    // A reference to the DurationMetricProducer's config key.
+    const ConfigKey& mConfigKey;
+
+    const std::string mName;
 
     HashableDimensionKey mEventKey;
 
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
index 06e743d..4b346dd 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
@@ -18,24 +18,50 @@
 
 #include "Log.h"
 #include "MaxDurationTracker.h"
+#include "guardrail/StatsdStats.h"
 
 namespace android {
 namespace os {
 namespace statsd {
 
-MaxDurationTracker::MaxDurationTracker(const HashableDimensionKey& eventKey,
+MaxDurationTracker::MaxDurationTracker(const ConfigKey& key, const string& name,
+                                       const HashableDimensionKey& eventKey,
                                        sp<ConditionWizard> wizard, int conditionIndex, bool nesting,
                                        uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
                                        const std::vector<sp<AnomalyTracker>>& anomalyTrackers,
                                        std::vector<DurationBucket>& bucket)
-    : DurationTracker(eventKey, wizard, conditionIndex, nesting, currentBucketStartNs, bucketSizeNs,
-                      anomalyTrackers, bucket) {
+    : DurationTracker(key, name, eventKey, wizard, conditionIndex, nesting, currentBucketStartNs,
+                      bucketSizeNs, anomalyTrackers, bucket) {
+}
+
+bool MaxDurationTracker::hitGuardRail(const HashableDimensionKey& newKey) {
+    // ===========GuardRail==============
+    if (mInfos.find(newKey) != mInfos.end()) {
+        // if the key existed, we are good!
+        return false;
+    }
+    // 1. Report the tuple count if the tuple count > soft limit
+    if (mInfos.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
+        size_t newTupleCount = mInfos.size() + 1;
+        StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mName + mEventKey,
+                                                           newTupleCount);
+        // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
+        if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
+            ALOGE("MaxDurTracker %s dropping data for dimension key %s", mName.c_str(),
+                  newKey.c_str());
+            return true;
+        }
+    }
+    return false;
 }
 
 void MaxDurationTracker::noteStart(const HashableDimensionKey& key, bool condition,
                                    const uint64_t eventTime, const ConditionKey& conditionKey) {
-    flushIfNeeded(eventTime);
     // this will construct a new DurationInfo if this key didn't exist.
+    if (hitGuardRail(key)) {
+        return;
+    }
+
     DurationInfo& duration = mInfos[key];
     duration.conditionKeys = conditionKey;
     VLOG("MaxDuration: key %s start condition %d", key.c_str(), condition);
@@ -63,7 +89,6 @@
 
 void MaxDurationTracker::noteStop(const HashableDimensionKey& key, const uint64_t eventTime,
                                   bool forceStop) {
-    flushIfNeeded(eventTime);
     declareAnomalyIfAlarmExpired(eventTime);
     VLOG("MaxDuration: key %s stop", key.c_str());
     if (mInfos.find(key) == mInfos.end()) {
@@ -85,7 +110,6 @@
                      (long long)duration.lastStartTime, (long long)eventTime,
                      (long long)durationTime);
                 duration.lastDuration = duration.lastDuration + durationTime;
-                duration.lastStartTime = -1;
                 VLOG("  record duration: %lld ", (long long)duration.lastDuration);
             }
             break;
@@ -223,7 +247,6 @@
 
 void MaxDurationTracker::noteConditionChanged(const HashableDimensionKey& key, bool conditionMet,
                                               const uint64_t timestamp) {
-    flushIfNeeded(timestamp);
     declareAnomalyIfAlarmExpired(timestamp);
     auto it = mInfos.find(key);
     if (it == mInfos.end()) {
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
index 0f79ffe..e0d1466 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
@@ -28,7 +28,8 @@
 // they stop or bucket expires.
 class MaxDurationTracker : public DurationTracker {
 public:
-    MaxDurationTracker(const HashableDimensionKey& eventKey, sp<ConditionWizard> wizard,
+    MaxDurationTracker(const ConfigKey& key, const string& name,
+                       const HashableDimensionKey& eventKey, sp<ConditionWizard> wizard,
                        int conditionIndex, bool nesting, uint64_t currentBucketStartNs,
                        uint64_t bucketSizeNs,
                        const std::vector<sp<AnomalyTracker>>& anomalyTrackers,
@@ -53,6 +54,9 @@
     void noteConditionChanged(const HashableDimensionKey& key, bool conditionMet,
                               const uint64_t timestamp);
 
+    // return true if we should not allow newKey to be tracked because we are above the threshold
+    bool hitGuardRail(const HashableDimensionKey& newKey);
+
     FRIEND_TEST(MaxDurationTrackerTest, TestSimpleMaxDuration);
     FRIEND_TEST(MaxDurationTrackerTest, TestCrossBucketBoundary);
     FRIEND_TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition);
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
index 29b6c89..abdfbc0 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
@@ -16,6 +16,7 @@
 #define DEBUG true
 #include "Log.h"
 #include "OringDurationTracker.h"
+#include "guardrail/StatsdStats.h"
 
 namespace android {
 namespace os {
@@ -23,22 +24,45 @@
 
 using std::pair;
 
-OringDurationTracker::OringDurationTracker(const HashableDimensionKey& eventKey,
+OringDurationTracker::OringDurationTracker(const ConfigKey& key, const string& name,
+                                           const HashableDimensionKey& eventKey,
                                            sp<ConditionWizard> wizard, int conditionIndex,
                                            bool nesting, uint64_t currentBucketStartNs,
                                            uint64_t bucketSizeNs,
                                            const std::vector<sp<AnomalyTracker>>& anomalyTrackers,
                                            std::vector<DurationBucket>& bucket)
-    : DurationTracker(eventKey, wizard, conditionIndex, nesting, currentBucketStartNs, bucketSizeNs,
-                      anomalyTrackers, bucket),
+    : DurationTracker(key, name, eventKey, wizard, conditionIndex, nesting, currentBucketStartNs,
+                      bucketSizeNs, anomalyTrackers, bucket),
       mStarted(),
       mPaused() {
     mLastStartTime = 0;
 }
 
+bool OringDurationTracker::hitGuardRail(const HashableDimensionKey& newKey) {
+    // ===========GuardRail==============
+    // 1. Report the tuple count if the tuple count > soft limit
+    if (mConditionKeyMap.find(newKey) != mConditionKeyMap.end()) {
+        return false;
+    }
+    if (mConditionKeyMap.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
+        size_t newTupleCount = mConditionKeyMap.size() + 1;
+        StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mName + mEventKey,
+                                                           newTupleCount);
+        // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
+        if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
+            ALOGE("OringDurTracker %s dropping data for dimension key %s", mName.c_str(),
+                  newKey.c_str());
+            return true;
+        }
+    }
+    return false;
+}
+
 void OringDurationTracker::noteStart(const HashableDimensionKey& key, bool condition,
                                      const uint64_t eventTime, const ConditionKey& conditionKey) {
-    flushIfNeeded(eventTime);
+    if (hitGuardRail(key)) {
+        return;
+    }
     if (condition) {
         if (mStarted.size() == 0) {
             mLastStartTime = eventTime;
@@ -59,7 +83,6 @@
 
 void OringDurationTracker::noteStop(const HashableDimensionKey& key, const uint64_t timestamp,
                                     const bool stopAll) {
-    flushIfNeeded(timestamp);
     declareAnomalyIfAlarmExpired(timestamp);
     VLOG("Oring: %s stop", key.c_str());
     auto it = mStarted.find(key);
@@ -72,7 +95,6 @@
         if (mStarted.empty()) {
             mDuration += (timestamp - mLastStartTime);
             detectAndDeclareAnomaly(timestamp, mCurrentBucketNum, mDuration);
-            mLastStartTime = -1;
             VLOG("record duration %lld, total %lld ", (long long)timestamp - mLastStartTime,
                  (long long)mDuration);
         }
@@ -92,7 +114,6 @@
 }
 
 void OringDurationTracker::noteStopAll(const uint64_t timestamp) {
-    flushIfNeeded(timestamp);
     declareAnomalyIfAlarmExpired(timestamp);
     if (!mStarted.empty()) {
         mDuration += (timestamp - mLastStartTime);
@@ -105,7 +126,6 @@
     mStarted.clear();
     mPaused.clear();
     mConditionKeyMap.clear();
-    mLastStartTime = -1;
 }
 
 bool OringDurationTracker::flushIfNeeded(uint64_t eventTime) {
@@ -122,7 +142,6 @@
     // Process the current bucket.
     if (mStarted.size() > 0) {
         mDuration += (current_info.mBucketEndNs - mLastStartTime);
-        mLastStartTime = current_info.mBucketEndNs;
     }
     if (mDuration > 0) {
         current_info.mDuration = mDuration;
@@ -138,17 +157,15 @@
             info.mBucketEndNs = info.mBucketStartNs + mBucketSizeNs;
             info.mBucketNum = mCurrentBucketNum + i;
             info.mDuration = mBucketSizeNs;
-            mLastStartTime = info.mBucketEndNs;
-            if (info.mDuration > 0) {
                 mBucket.push_back(info);
                 addPastBucketToAnomalyTrackers(info.mDuration, info.mBucketNum);
                 VLOG("  add filling bucket with duration %lld", (long long)info.mDuration);
-            }
         }
     }
     mCurrentBucketStartTimeNs += numBucketsForward * mBucketSizeNs;
     mCurrentBucketNum += numBucketsForward;
 
+    mLastStartTime = mCurrentBucketStartTimeNs;
     mDuration = 0;
 
     // if all stopped, then tell owner it's safe to remove this tracker.
@@ -156,7 +173,6 @@
 }
 
 void OringDurationTracker::onSlicedConditionMayChange(const uint64_t timestamp) {
-    flushIfNeeded(timestamp);
     declareAnomalyIfAlarmExpired(timestamp);
     vector<pair<HashableDimensionKey, int>> startedToPaused;
     vector<pair<HashableDimensionKey, int>> pausedToStarted;
@@ -179,8 +195,7 @@
         }
 
         if (mStarted.empty()) {
-            mDuration = (timestamp - mLastStartTime);
-            mLastStartTime = -1;
+            mDuration += (timestamp - mLastStartTime);
             VLOG("Duration add %lld , to %lld ", (long long)(timestamp - mLastStartTime),
                  (long long)mDuration);
             detectAndDeclareAnomaly(timestamp, mCurrentBucketNum, mDuration);
@@ -222,13 +237,12 @@
 }
 
 void OringDurationTracker::onConditionChanged(bool condition, const uint64_t timestamp) {
-    flushIfNeeded(timestamp);
     declareAnomalyIfAlarmExpired(timestamp);
     if (condition) {
         if (!mPaused.empty()) {
             VLOG("Condition true, all started");
             if (mStarted.empty()) {
-                mLastStartTime = -1;
+                mLastStartTime = timestamp;
             }
             if (mStarted.empty() && !mPaused.empty()) {
                 startAnomalyAlarm(timestamp);
@@ -239,8 +253,7 @@
     } else {
         if (!mStarted.empty()) {
             VLOG("Condition false, all paused");
-            mDuration = (timestamp - mLastStartTime);
-            mLastStartTime = -1;
+            mDuration += (timestamp - mLastStartTime);
             mPaused.insert(mStarted.begin(), mStarted.end());
             mStarted.clear();
             detectAndDeclareAnomaly(timestamp, mCurrentBucketNum, mDuration);
@@ -280,12 +293,12 @@
     pastNs += currRemainingBucketSizeNs;
 
     // Now deal with the past buckets, starting with the oldest.
-    for (int futBucketIdx = 0; futBucketIdx < anomalyTracker.getNumOfPastPackets();
+    for (int futBucketIdx = 0; futBucketIdx < anomalyTracker.getNumOfPastBuckets();
          futBucketIdx++) {
         // We now overwrite the oldest bucket with the previous 'current', and start a new
         // 'current'.
         pastNs -= anomalyTracker.getPastBucketValue(
-                mEventKey, mCurrentBucketNum - anomalyTracker.getNumOfPastPackets() + futBucketIdx);
+                mEventKey, mCurrentBucketNum - anomalyTracker.getNumOfPastBuckets() + futBucketIdx);
         leftNs = thresholdNs - pastNs;
         if (leftNs <= mBucketSizeNs) {  // Predict anomaly will occur in this bucket.
             return eventTimestampNs + currRemainingBucketSizeNs + (futBucketIdx * mBucketSizeNs) +
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
index ef32fdb..a8404a9 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
@@ -27,7 +27,8 @@
 // Tracks the "Or'd" duration -- if 2 durations are overlapping, they won't be double counted.
 class OringDurationTracker : public DurationTracker {
 public:
-    OringDurationTracker(const HashableDimensionKey& eventKey, sp<ConditionWizard> wizard,
+    OringDurationTracker(const ConfigKey& key, const string& name,
+                         const HashableDimensionKey& eventKey, sp<ConditionWizard> wizard,
                          int conditionIndex, bool nesting, uint64_t currentBucketStartNs,
                          uint64_t bucketSizeNs,
                          const std::vector<sp<AnomalyTracker>>& anomalyTrackers,
@@ -58,6 +59,9 @@
     int64_t mLastStartTime;
     std::map<HashableDimensionKey, ConditionKey> mConditionKeyMap;
 
+    // return true if we should not allow newKey to be tracked because we are above the threshold
+    bool hitGuardRail(const HashableDimensionKey& newKey);
+
     FRIEND_TEST(OringDurationTrackerTest, TestDurationOverlap);
     FRIEND_TEST(OringDurationTrackerTest, TestCrossBucketBoundary);
     FRIEND_TEST(OringDurationTrackerTest, TestDurationConditionChange);
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 4660263..9e5163f 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#define DEBUG true  // STOPSHIP if true
+#include "Log.h"
+
 #include "../condition/CombinationConditionTracker.h"
 #include "../condition/SimpleConditionTracker.h"
 #include "../external/StatsPullerManager.h"
@@ -134,7 +137,8 @@
     return true;
 }
 
-bool initConditions(const StatsdConfig& config, const unordered_map<string, int>& logTrackerMap,
+bool initConditions(const ConfigKey& key, const StatsdConfig& config,
+                    const unordered_map<string, int>& logTrackerMap,
                     unordered_map<string, int>& conditionTrackerMap,
                     vector<sp<ConditionTracker>>& allConditionTrackers,
                     unordered_map<int, std::vector<int>>& trackerToConditionMap) {
@@ -149,7 +153,7 @@
         switch (condition.contents_case()) {
             case Condition::ContentsCase::kSimpleCondition: {
                 allConditionTrackers.push_back(new SimpleConditionTracker(
-                        condition.name(), index, condition.simple_condition(), logTrackerMap));
+                        key, condition.name(), index, condition.simple_condition(), logTrackerMap));
                 break;
             }
             case Condition::ContentsCase::kCombination: {
@@ -184,7 +188,8 @@
     return true;
 }
 
-bool initMetrics(const StatsdConfig& config, const unordered_map<string, int>& logTrackerMap,
+bool initMetrics(const ConfigKey& key, const StatsdConfig& config,
+                 const unordered_map<string, int>& logTrackerMap,
                  const unordered_map<string, int>& conditionTrackerMap,
                  const vector<sp<LogMatchingTracker>>& allLogEntryMatchers,
                  vector<sp<ConditionTracker>>& allConditionTrackers,
@@ -219,9 +224,12 @@
 
         int conditionIndex = -1;
         if (metric.has_condition()) {
-            handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
-                                       metric.links(), allConditionTrackers, conditionIndex,
-                                       conditionToMetricMap);
+            bool good = handleMetricWithConditions(
+                    metric.condition(), metricIndex, conditionTrackerMap, metric.links(),
+                    allConditionTrackers, conditionIndex, conditionToMetricMap);
+            if (!good) {
+                return false;
+            }
         } else {
             if (metric.links_size() > 0) {
                 ALOGW("metrics has a EventConditionLink but doesn't have a condition");
@@ -230,7 +238,7 @@
         }
 
         sp<MetricProducer> countProducer =
-                new CountMetricProducer(metric, conditionIndex, wizard, startTimeNs);
+                new CountMetricProducer(key, metric, conditionIndex, wizard, startTimeNs);
         allMetricProducers.push_back(countProducer);
     }
 
@@ -287,9 +295,12 @@
         int conditionIndex = -1;
 
         if (metric.has_condition()) {
-            handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
-                                       metric.links(), allConditionTrackers, conditionIndex,
-                                       conditionToMetricMap);
+            bool good = handleMetricWithConditions(
+                    metric.condition(), metricIndex, conditionTrackerMap, metric.links(),
+                    allConditionTrackers, conditionIndex, conditionToMetricMap);
+            if (!good) {
+                return false;
+            }
         } else {
             if (metric.links_size() > 0) {
                 ALOGW("metrics has a EventConditionLink but doesn't have a condition");
@@ -298,8 +309,8 @@
         }
 
         sp<MetricProducer> durationMetric = new DurationMetricProducer(
-                metric, conditionIndex, trackerIndices[0], trackerIndices[1], trackerIndices[2],
-                nesting, wizard, internalDimension, startTimeNs);
+                key, metric, conditionIndex, trackerIndices[0], trackerIndices[1],
+                trackerIndices[2], nesting, wizard, internalDimension, startTimeNs);
 
         allMetricProducers.push_back(durationMetric);
     }
@@ -321,9 +332,12 @@
 
         int conditionIndex = -1;
         if (metric.has_condition()) {
-            handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
-                                       metric.links(), allConditionTrackers, conditionIndex,
-                                       conditionToMetricMap);
+            bool good = handleMetricWithConditions(
+                    metric.condition(), metricIndex, conditionTrackerMap, metric.links(),
+                    allConditionTrackers, conditionIndex, conditionToMetricMap);
+            if (!good) {
+                return false;
+            }
         } else {
             if (metric.links_size() > 0) {
                 ALOGW("metrics has a EventConditionLink but doesn't have a condition");
@@ -332,7 +346,7 @@
         }
 
         sp<MetricProducer> eventMetric =
-                new EventMetricProducer(metric, conditionIndex, wizard, startTimeNs);
+                new EventMetricProducer(key, metric, conditionIndex, wizard, startTimeNs);
 
         allMetricProducers.push_back(eventMetric);
     }
@@ -368,9 +382,12 @@
 
         int conditionIndex = -1;
         if (metric.has_condition()) {
-            handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
-                                       metric.links(), allConditionTrackers, conditionIndex,
-                                       conditionToMetricMap);
+            bool good = handleMetricWithConditions(
+                    metric.condition(), metricIndex, conditionTrackerMap, metric.links(),
+                    allConditionTrackers, conditionIndex, conditionToMetricMap);
+            if (!good) {
+                return false;
+            }
         } else {
             if (metric.links_size() > 0) {
                 ALOGW("metrics has a EventConditionLink but doesn't have a condition");
@@ -378,8 +395,8 @@
             }
         }
 
-        sp<MetricProducer> valueProducer =
-                new ValueMetricProducer(metric, conditionIndex, wizard, pullTagId, startTimeNs);
+        sp<MetricProducer> valueProducer = new ValueMetricProducer(key, metric, conditionIndex,
+                                                                   wizard, pullTagId, startTimeNs);
         allMetricProducers.push_back(valueProducer);
     }
 
@@ -414,9 +431,12 @@
 
         int conditionIndex = -1;
         if (metric.has_condition()) {
-            handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
-                                       metric.links(), allConditionTrackers, conditionIndex,
-                                       conditionToMetricMap);
+            bool good = handleMetricWithConditions(
+                    metric.condition(), metricIndex, conditionTrackerMap, metric.links(),
+                    allConditionTrackers, conditionIndex, conditionToMetricMap);
+            if (!good) {
+                return false;
+            }
         } else {
             if (metric.links_size() > 0) {
                 ALOGW("metrics has a EventConditionLink but doesn't have a condition");
@@ -424,8 +444,8 @@
             }
         }
 
-        sp<MetricProducer> gaugeProducer =
-                new GaugeMetricProducer(metric, conditionIndex, wizard, pullTagId, startTimeNs);
+        sp<MetricProducer> gaugeProducer = new GaugeMetricProducer(key, metric, conditionIndex,
+                                                                   wizard, pullTagId, startTimeNs);
         allMetricProducers.push_back(gaugeProducer);
     }
     return true;
@@ -442,16 +462,31 @@
                   alert.metric_name().c_str());
             return false;
         }
+        if (alert.trigger_if_sum_gt() < 0 || alert.number_of_buckets() <= 0) {
+            ALOGW("invalid alert: threshold=%lld num_buckets= %d",
+                  alert.trigger_if_sum_gt(), alert.number_of_buckets());
+            return false;
+        }
         const int metricIndex = itr->second;
-        sp<AnomalyTracker> anomalyTracker =
-                new AnomalyTracker(alert, allMetricProducers[metricIndex]->getBuckeSizeInNs());
+        if (alert.trigger_if_sum_gt() >
+                  (int64_t) alert.number_of_buckets()
+                  * allMetricProducers[metricIndex]->getBuckeSizeInNs()) {
+            ALOGW("invalid alert: threshold (%lld) > possible recordable value (%d x %lld)",
+                  alert.trigger_if_sum_gt(), alert.number_of_buckets(),
+                  (long long) allMetricProducers[metricIndex]->getBuckeSizeInNs());
+            return false;
+        }
+
+        // TODO: Give each MetricProducer a method called createAnomalyTracker(alert), which
+        //       creates either an AnomalyTracker or a DurationAnomalyTracker and returns it.
+        sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert);
         allMetricProducers[metricIndex]->addAnomalyTracker(anomalyTracker);
         allAnomalyTrackers.push_back(anomalyTracker);
     }
     return true;
 }
 
-bool initStatsdConfig(const StatsdConfig& config, set<int>& allTagIds,
+bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, set<int>& allTagIds,
                       vector<sp<LogMatchingTracker>>& allLogEntryMatchers,
                       vector<sp<ConditionTracker>>& allConditionTrackers,
                       vector<sp<MetricProducer>>& allMetricProducers,
@@ -469,13 +504,13 @@
     }
     ALOGD("initLogMatchingTrackers succeed...");
 
-    if (!initConditions(config, logTrackerMap, conditionTrackerMap, allConditionTrackers,
+    if (!initConditions(key, config, logTrackerMap, conditionTrackerMap, allConditionTrackers,
                         trackerToConditionMap)) {
         ALOGE("initConditionTrackers failed");
         return false;
     }
 
-    if (!initMetrics(config, logTrackerMap, conditionTrackerMap, allLogEntryMatchers,
+    if (!initMetrics(key, config, logTrackerMap, conditionTrackerMap, allLogEntryMatchers,
                      allConditionTrackers, allMetricProducers, conditionToMetricMap,
                      trackerToMetricMap, metricProducerMap)) {
         ALOGE("initMetricProducers failed");
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h
index 7d7e0c3..e7cbd53 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/metrics_manager_util.h
@@ -36,6 +36,7 @@
 
 // Initialize the LogMatchingTrackers.
 // input:
+// [key]: the config key that this config belongs to
 // [config]: the input StatsdConfig
 // output:
 // [logTrackerMap]: this map should contain matcher name to index mapping
@@ -48,6 +49,7 @@
 
 // Initialize ConditionTrackers
 // input:
+// [key]: the config key that this config belongs to
 // [config]: the input config
 // [logTrackerMap]: LogMatchingTracker name to index mapping from previous step.
 // output:
@@ -55,7 +57,7 @@
 // [allConditionTrackers]: stores the sp to all the ConditionTrackers
 // [trackerToConditionMap]: contain the mapping from index of
 //                        log tracker to condition trackers that use the log tracker
-bool initConditions(const StatsdConfig& config,
+bool initConditions(const ConfigKey& key, const StatsdConfig& config,
                     const std::unordered_map<std::string, int>& logTrackerMap,
                     std::unordered_map<std::string, int>& conditionTrackerMap,
                     std::vector<sp<ConditionTracker>>& allConditionTrackers,
@@ -64,6 +66,7 @@
 
 // Initialize MetricProducers.
 // input:
+// [key]: the config key that this config belongs to
 // [config]: the input config
 // [logTrackerMap]: LogMatchingTracker name to index mapping from previous step.
 // [conditionTrackerMap]: condition name to index mapping
@@ -73,7 +76,8 @@
 //                          the list of MetricProducer index
 // [trackerToMetricMap]: contains the mapping from log tracker to MetricProducer index.
 bool initMetrics(
-        const StatsdConfig& config, const std::unordered_map<std::string, int>& logTrackerMap,
+        const ConfigKey& key, const StatsdConfig& config,
+        const std::unordered_map<std::string, int>& logTrackerMap,
         const std::unordered_map<std::string, int>& conditionTrackerMap,
         const std::unordered_map<int, std::vector<EventConditionLink>>& eventConditionLinks,
         const vector<sp<LogMatchingTracker>>& allLogEntryMatchers,
@@ -84,7 +88,7 @@
 
 // Initialize MetricsManager from StatsdConfig.
 // Parameters are the members of MetricsManager. See MetricsManager for declaration.
-bool initStatsdConfig(const StatsdConfig& config, std::set<int>& allTagIds,
+bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, std::set<int>& allTagIds,
                       std::vector<sp<LogMatchingTracker>>& allLogEntryMatchers,
                       std::vector<sp<ConditionTracker>>& allConditionTrackers,
                       std::vector<sp<MetricProducer>>& allMetricProducers,
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 4783cd89..e7e1d43 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -172,3 +172,52 @@
 
   repeated ConfigMetricsReport reports = 2;
 }
+
+message StatsdStatsReport {
+    optional int32 stats_begin_time_sec = 1;
+
+    optional int32 stats_end_time_sec = 2;
+
+    message MatcherStats {
+        optional string name = 1;
+        optional int32 matched_times = 2;
+    }
+
+    message ConditionStats {
+        optional string name = 1;
+        optional int32 max_tuple_counts = 2;
+    }
+
+    message MetricStats {
+        optional string name = 1;
+        optional int32 max_tuple_counts = 2;
+    }
+
+    message ConfigStats {
+        optional int32 uid = 1;
+        optional string name = 2;
+        optional int32 creation_time_sec = 3;
+        optional int32 deletion_time_sec = 4;
+        optional int32 metric_count = 5;
+        optional int32 condition_count = 6;
+        optional int32 matcher_count = 7;
+        optional int32 alert_count = 8;
+        optional bool is_valid = 9;
+
+        repeated int32 broadcast_sent_time_sec = 10;
+        repeated int32 data_drop_time_sec = 11;
+        repeated int32 dump_report_time_sec = 12;
+        repeated MatcherStats matcher_stats = 13;
+        repeated ConditionStats condition_stats = 14;
+        repeated MetricStats metric_stats = 15;
+    }
+
+    repeated ConfigStats config_stats = 3;
+
+    message AtomStats {
+        optional int32 tag = 1;
+        optional int32 count = 2;
+    }
+
+    repeated AtomStats atom_stats = 7;
+}
\ No newline at end of file
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index 96abe6f..62f06a7 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -40,7 +40,7 @@
 
 void StorageManager::writeFile(const char* file, const void* buffer, int numBytes) {
     int fd = open(file, O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR);
-    if (fd != -1) {
+    if (fd == -1) {
         VLOG("Attempt to access %s but failed", file);
         return;
     }
@@ -129,7 +129,7 @@
 
 void StorageManager::appendConfigMetricsReport(const char* path, ProtoOutputStream& proto) {
     unique_ptr<DIR, decltype(&closedir)> dir(opendir(path), closedir);
-    if (dir != NULL) {
+    if (dir == NULL) {
         VLOG("Path %s does not exist", path);
         return;
     }
diff --git a/cmds/statsd/tests/ConfigManager_test.cpp b/cmds/statsd/tests/ConfigManager_test.cpp
index 618aef6..696fddf 100644
--- a/cmds/statsd/tests/ConfigManager_test.cpp
+++ b/cmds/statsd/tests/ConfigManager_test.cpp
@@ -62,7 +62,8 @@
 }
 
 TEST(ConfigManagerTest, TestFakeConfig) {
-    auto metricsManager = std::make_unique<MetricsManager>(build_fake_config());
+    auto metricsManager =
+            std::make_unique<MetricsManager>(ConfigKey(0, "test"), build_fake_config());
     EXPECT_TRUE(metricsManager->isConfigValid());
 }
 
diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp
index 3dd4e70..5384e0c 100644
--- a/cmds/statsd/tests/MetricsManager_test.cpp
+++ b/cmds/statsd/tests/MetricsManager_test.cpp
@@ -40,6 +40,8 @@
 
 // TODO: ADD MORE TEST CASES.
 
+const ConfigKey kConfigKey(0, "test");
+
 StatsdConfig buildGoodConfig() {
     StatsdConfig config;
     config.set_name("12345");
@@ -163,6 +165,25 @@
     return config;
 }
 
+StatsdConfig buildMissingCondition() {
+    StatsdConfig config;
+    config.set_name("12345");
+
+    CountMetric* metric = config.add_count_metric();
+    metric->set_name("3");
+    metric->set_what("SCREEN_EVENT");
+    metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
+    metric->set_condition("SOME_CONDITION");
+
+    LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
+    eventMatcher->set_name("SCREEN_EVENT");
+
+    SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
+    simpleLogEntryMatcher->set_tag(2);
+
+    return config;
+}
+
 StatsdConfig buildDimensionMetricsWithMultiTags() {
     StatsdConfig config;
     config.set_name("12345");
@@ -254,9 +275,9 @@
     unordered_map<int, std::vector<int>> trackerToMetricMap;
     unordered_map<int, std::vector<int>> trackerToConditionMap;
 
-    EXPECT_TRUE(initStatsdConfig(config, allTagIds, allLogEntryMatchers, allConditionTrackers,
-                                 allMetricProducers, allAnomalyTrackers, conditionToMetricMap,
-                                 trackerToMetricMap, trackerToConditionMap));
+    EXPECT_TRUE(initStatsdConfig(kConfigKey, config, allTagIds, allLogEntryMatchers,
+                                 allConditionTrackers, allMetricProducers, allAnomalyTrackers,
+                                 conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
     EXPECT_EQ(1u, allMetricProducers.size());
     EXPECT_EQ(1u, allAnomalyTrackers.size());
 }
@@ -272,9 +293,9 @@
     unordered_map<int, std::vector<int>> trackerToMetricMap;
     unordered_map<int, std::vector<int>> trackerToConditionMap;
 
-    EXPECT_FALSE(initStatsdConfig(config, allTagIds, allLogEntryMatchers, allConditionTrackers,
-                                  allMetricProducers, allAnomalyTrackers, conditionToMetricMap,
-                                  trackerToMetricMap, trackerToConditionMap));
+    EXPECT_FALSE(initStatsdConfig(kConfigKey, config, allTagIds, allLogEntryMatchers,
+                                  allConditionTrackers, allMetricProducers, allAnomalyTrackers,
+                                  conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
 }
 
 TEST(MetricsManagerTest, TestCircleLogMatcherDependency) {
@@ -288,9 +309,9 @@
     unordered_map<int, std::vector<int>> trackerToMetricMap;
     unordered_map<int, std::vector<int>> trackerToConditionMap;
 
-    EXPECT_FALSE(initStatsdConfig(config, allTagIds, allLogEntryMatchers, allConditionTrackers,
-                                  allMetricProducers, allAnomalyTrackers, conditionToMetricMap,
-                                  trackerToMetricMap, trackerToConditionMap));
+    EXPECT_FALSE(initStatsdConfig(kConfigKey, config, allTagIds, allLogEntryMatchers,
+                                  allConditionTrackers, allMetricProducers, allAnomalyTrackers,
+                                  conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
 }
 
 TEST(MetricsManagerTest, TestMissingMatchers) {
@@ -303,9 +324,24 @@
     unordered_map<int, std::vector<int>> conditionToMetricMap;
     unordered_map<int, std::vector<int>> trackerToMetricMap;
     unordered_map<int, std::vector<int>> trackerToConditionMap;
-    EXPECT_FALSE(initStatsdConfig(config, allTagIds, allLogEntryMatchers, allConditionTrackers,
-                                  allMetricProducers, allAnomalyTrackers, conditionToMetricMap,
-                                  trackerToMetricMap, trackerToConditionMap));
+    EXPECT_FALSE(initStatsdConfig(kConfigKey, config, allTagIds, allLogEntryMatchers,
+                                  allConditionTrackers, allMetricProducers, allAnomalyTrackers,
+                                  conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
+}
+
+TEST(MetricsManagerTest, TestMissingCondition) {
+    StatsdConfig config = buildMissingCondition();
+    set<int> allTagIds;
+    vector<sp<LogMatchingTracker>> allLogEntryMatchers;
+    vector<sp<ConditionTracker>> allConditionTrackers;
+    vector<sp<MetricProducer>> allMetricProducers;
+    std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
+    unordered_map<int, std::vector<int>> conditionToMetricMap;
+    unordered_map<int, std::vector<int>> trackerToMetricMap;
+    unordered_map<int, std::vector<int>> trackerToConditionMap;
+    EXPECT_FALSE(initStatsdConfig(kConfigKey, config, allTagIds, allLogEntryMatchers,
+                                  allConditionTrackers, allMetricProducers, allAnomalyTrackers,
+                                  conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
 }
 
 TEST(MetricsManagerTest, TestCircleConditionDependency) {
@@ -319,9 +355,9 @@
     unordered_map<int, std::vector<int>> trackerToMetricMap;
     unordered_map<int, std::vector<int>> trackerToConditionMap;
 
-    EXPECT_FALSE(initStatsdConfig(config, allTagIds, allLogEntryMatchers, allConditionTrackers,
-                                  allMetricProducers, allAnomalyTrackers, conditionToMetricMap,
-                                  trackerToMetricMap, trackerToConditionMap));
+    EXPECT_FALSE(initStatsdConfig(kConfigKey, config, allTagIds, allLogEntryMatchers,
+                                  allConditionTrackers, allMetricProducers, allAnomalyTrackers,
+                                  conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
 }
 
 TEST(MetricsManagerTest, testAlertWithUnknownMetric) {
@@ -335,9 +371,9 @@
     unordered_map<int, std::vector<int>> trackerToMetricMap;
     unordered_map<int, std::vector<int>> trackerToConditionMap;
 
-    EXPECT_FALSE(initStatsdConfig(config, allTagIds, allLogEntryMatchers, allConditionTrackers,
-                                  allMetricProducers, allAnomalyTrackers, conditionToMetricMap,
-                                  trackerToMetricMap, trackerToConditionMap));
+    EXPECT_FALSE(initStatsdConfig(kConfigKey, config, allTagIds, allLogEntryMatchers,
+                                  allConditionTrackers, allMetricProducers, allAnomalyTrackers,
+                                  conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
 }
 
 #else
diff --git a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
index e0200f27..65c2a05 100644
--- a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
+++ b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
@@ -51,7 +51,7 @@
     alert.set_refractory_period_secs(2 * bucketSizeNs / NS_PER_SEC);
     alert.set_trigger_if_sum_gt(2);
 
-    AnomalyTracker anomalyTracker(alert, bucketSizeNs);
+    AnomalyTracker anomalyTracker(alert);
 
     std::shared_ptr<DimToValMap> bucket0 = MockBucket({{"a", 1}, {"b", 2}, {"c", 1}});
     int64_t eventTimestamp0 = 10;
@@ -168,7 +168,7 @@
     alert.set_refractory_period_secs(2 * bucketSizeNs / NS_PER_SEC);
     alert.set_trigger_if_sum_gt(2);
 
-    AnomalyTracker anomalyTracker(alert, bucketSizeNs);
+    AnomalyTracker anomalyTracker(alert);
 
     std::shared_ptr<DimToValMap> bucket9 = MockBucket({{"a", 1}, {"b", 2}, {"c", 1}});
     std::shared_ptr<DimToValMap> bucket16 = MockBucket({{"b", 4}});
diff --git a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
index 11fb011..8b0b6a4 100644
--- a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
+++ b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
@@ -28,6 +28,8 @@
 namespace os {
 namespace statsd {
 
+const ConfigKey kConfigKey(0, "test");
+
 SimpleCondition getWakeLockHeldCondition(bool countNesting, bool defaultFalse,
                                          bool outputSlicedUid) {
     SimpleCondition simpleCondition;
@@ -76,8 +78,8 @@
     trackerNameIndexMap["SCREEN_TURNED_ON"] = 0;
     trackerNameIndexMap["SCREEN_TURNED_OFF"] = 1;
 
-    SimpleConditionTracker conditionTracker("SCREEN_IS_ON", 0 /*tracker index*/, simpleCondition,
-                                            trackerNameIndexMap);
+    SimpleConditionTracker conditionTracker(kConfigKey, "SCREEN_IS_ON", 0 /*tracker index*/,
+                                            simpleCondition, trackerNameIndexMap);
 
     LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
 
@@ -158,8 +160,9 @@
     trackerNameIndexMap["SCREEN_TURNED_ON"] = 0;
     trackerNameIndexMap["SCREEN_TURNED_OFF"] = 1;
 
-    SimpleConditionTracker conditionTracker("SCREEN_IS_ON", 0 /*condition tracker index*/,
-                                            simpleCondition, trackerNameIndexMap);
+    SimpleConditionTracker conditionTracker(kConfigKey, "SCREEN_IS_ON",
+                                            0 /*condition tracker index*/, simpleCondition,
+                                            trackerNameIndexMap);
 
     LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
 
@@ -227,8 +230,9 @@
     trackerNameIndexMap["WAKE_LOCK_RELEASE"] = 1;
     trackerNameIndexMap["RELEASE_ALL"] = 2;
 
-    SimpleConditionTracker conditionTracker(conditionName, 0 /*condition tracker index*/,
-                                            simpleCondition, trackerNameIndexMap);
+    SimpleConditionTracker conditionTracker(kConfigKey, conditionName,
+                                            0 /*condition tracker index*/, simpleCondition,
+                                            trackerNameIndexMap);
     int uid = 111;
 
     LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
@@ -238,6 +242,7 @@
     vector<MatchingState> matcherState;
     matcherState.push_back(MatchingState::kMatched);
     matcherState.push_back(MatchingState::kNotMatched);
+    matcherState.push_back(MatchingState::kNotMatched);
     vector<sp<ConditionTracker>> allConditions;
     vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
     vector<bool> changedCache(1, false);
@@ -308,8 +313,9 @@
     trackerNameIndexMap["WAKE_LOCK_RELEASE"] = 1;
     trackerNameIndexMap["RELEASE_ALL"] = 2;
 
-    SimpleConditionTracker conditionTracker(conditionName, 0 /*condition tracker index*/,
-                                            simpleCondition, trackerNameIndexMap);
+    SimpleConditionTracker conditionTracker(kConfigKey, conditionName,
+                                            0 /*condition tracker index*/, simpleCondition,
+                                            trackerNameIndexMap);
     int uid1 = 111;
     string uid1_wl1 = "wl1_1";
     int uid2 = 222;
@@ -322,6 +328,7 @@
     vector<MatchingState> matcherState;
     matcherState.push_back(MatchingState::kMatched);
     matcherState.push_back(MatchingState::kNotMatched);
+    matcherState.push_back(MatchingState::kNotMatched);
     vector<sp<ConditionTracker>> allConditions;
     vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
     vector<bool> changedCache(1, false);
@@ -392,8 +399,9 @@
     trackerNameIndexMap["WAKE_LOCK_RELEASE"] = 1;
     trackerNameIndexMap["RELEASE_ALL"] = 2;
 
-    SimpleConditionTracker conditionTracker(conditionName, 0 /*condition tracker index*/,
-                                            simpleCondition, trackerNameIndexMap);
+    SimpleConditionTracker conditionTracker(kConfigKey, conditionName,
+                                            0 /*condition tracker index*/, simpleCondition,
+                                            trackerNameIndexMap);
     int uid1 = 111;
     int uid2 = 222;
 
diff --git a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
new file mode 100644
index 0000000..b14b52c
--- /dev/null
+++ b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
@@ -0,0 +1,232 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/guardrail/StatsdStats.h"
+#include "statslog.h"
+
+#include <gtest/gtest.h>
+#include <vector>
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using std::vector;
+
+TEST(StatsdStatsTest, TestValidConfigAdd) {
+    StatsdStats stats;
+    string name = "StatsdTest";
+    ConfigKey key(0, name);
+    const int metricsCount = 10;
+    const int conditionsCount = 20;
+    const int matchersCount = 30;
+    const int alertsCount = 10;
+    stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount,
+                             true /*valid config*/);
+    vector<uint8_t> output;
+    stats.dumpStats(&output, false /*reset stats*/);
+
+    StatsdStatsReport report;
+    bool good = report.ParseFromArray(&output[0], output.size());
+    EXPECT_TRUE(good);
+    EXPECT_EQ(1, report.config_stats_size());
+    const auto& configReport = report.config_stats(0);
+    EXPECT_EQ(0, configReport.uid());
+    EXPECT_EQ(name, configReport.name());
+    EXPECT_EQ(metricsCount, configReport.metric_count());
+    EXPECT_EQ(conditionsCount, configReport.condition_count());
+    EXPECT_EQ(matchersCount, configReport.matcher_count());
+    EXPECT_EQ(alertsCount, configReport.alert_count());
+    EXPECT_EQ(true, configReport.is_valid());
+    EXPECT_FALSE(configReport.has_deletion_time_sec());
+}
+
+TEST(StatsdStatsTest, TestInvalidConfigAdd) {
+    StatsdStats stats;
+    string name = "StatsdTest";
+    ConfigKey key(0, name);
+    const int metricsCount = 10;
+    const int conditionsCount = 20;
+    const int matchersCount = 30;
+    const int alertsCount = 10;
+    stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount,
+                             false /*bad config*/);
+    vector<uint8_t> output;
+    stats.dumpStats(&output, false);
+
+    StatsdStatsReport report;
+    bool good = report.ParseFromArray(&output[0], output.size());
+    EXPECT_TRUE(good);
+    EXPECT_EQ(1, report.config_stats_size());
+    const auto& configReport = report.config_stats(0);
+    // The invalid config should be put into icebox with a deletion time.
+    EXPECT_TRUE(configReport.has_deletion_time_sec());
+}
+
+TEST(StatsdStatsTest, TestConfigRemove) {
+    StatsdStats stats;
+    string name = "StatsdTest";
+    ConfigKey key(0, name);
+    const int metricsCount = 10;
+    const int conditionsCount = 20;
+    const int matchersCount = 30;
+    const int alertsCount = 10;
+    stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount, true);
+    vector<uint8_t> output;
+    stats.dumpStats(&output, false);
+    StatsdStatsReport report;
+    bool good = report.ParseFromArray(&output[0], output.size());
+    EXPECT_TRUE(good);
+    EXPECT_EQ(1, report.config_stats_size());
+    const auto& configReport = report.config_stats(0);
+    EXPECT_FALSE(configReport.has_deletion_time_sec());
+
+    stats.noteConfigRemoved(key);
+    stats.dumpStats(&output, false);
+    good = report.ParseFromArray(&output[0], output.size());
+    EXPECT_TRUE(good);
+    EXPECT_EQ(1, report.config_stats_size());
+    const auto& configReport2 = report.config_stats(0);
+    EXPECT_TRUE(configReport2.has_deletion_time_sec());
+}
+
+TEST(StatsdStatsTest, TestSubStats) {
+    StatsdStats stats;
+    ConfigKey key(0, "test");
+    stats.noteConfigReceived(key, 2, 3, 4, 5, true);
+
+    stats.noteMatcherMatched(key, "matcher1");
+    stats.noteMatcherMatched(key, "matcher1");
+    stats.noteMatcherMatched(key, "matcher2");
+
+    stats.noteConditionDimensionSize(key, "condition1", 250);
+    stats.noteConditionDimensionSize(key, "condition1", 240);
+
+    stats.noteMetricDimensionSize(key, "metric1", 201);
+    stats.noteMetricDimensionSize(key, "metric1", 202);
+
+    // broadcast-> 2
+    stats.noteBroadcastSent(key);
+    stats.noteBroadcastSent(key);
+
+    // data drop -> 1
+    stats.noteDataDropped(key);
+
+    // dump report -> 3
+    stats.noteMetricsReportSent(key);
+    stats.noteMetricsReportSent(key);
+    stats.noteMetricsReportSent(key);
+
+    vector<uint8_t> output;
+    stats.dumpStats(&output, true);  // Dump and reset stats
+    StatsdStatsReport report;
+    bool good = report.ParseFromArray(&output[0], output.size());
+    EXPECT_TRUE(good);
+    EXPECT_EQ(1, report.config_stats_size());
+    const auto& configReport = report.config_stats(0);
+    EXPECT_EQ(2, configReport.broadcast_sent_time_sec_size());
+    EXPECT_EQ(1, configReport.data_drop_time_sec_size());
+    EXPECT_EQ(3, configReport.dump_report_time_sec_size());
+
+    EXPECT_EQ(2, configReport.matcher_stats_size());
+
+    // matcher1 is the first in the list
+    if (!configReport.matcher_stats(0).name().compare("matcher1")) {
+        EXPECT_EQ(2, configReport.matcher_stats(0).matched_times());
+        EXPECT_EQ(1, configReport.matcher_stats(1).matched_times());
+        EXPECT_EQ("matcher2", configReport.matcher_stats(1).name());
+    } else {
+        // matcher1 is the second in the list.
+        EXPECT_EQ(1, configReport.matcher_stats(0).matched_times());
+        EXPECT_EQ("matcher2", configReport.matcher_stats(0).name());
+
+        EXPECT_EQ(2, configReport.matcher_stats(1).matched_times());
+        EXPECT_EQ("matcher1", configReport.matcher_stats(1).name());
+    }
+
+    EXPECT_EQ(1, configReport.condition_stats_size());
+    EXPECT_EQ("condition1", configReport.condition_stats(0).name());
+    EXPECT_EQ(250, configReport.condition_stats(0).max_tuple_counts());
+
+    EXPECT_EQ(1, configReport.metric_stats_size());
+    EXPECT_EQ("metric1", configReport.metric_stats(0).name());
+    EXPECT_EQ(202, configReport.metric_stats(0).max_tuple_counts());
+
+    // after resetting the stats, some new events come
+    stats.noteMatcherMatched(key, "matcher99");
+    stats.noteConditionDimensionSize(key, "condition99", 300);
+    stats.noteMetricDimensionSize(key, "metric99", 270);
+
+    // now the config stats should only contain the stats about the new event.
+    stats.dumpStats(&output, false);
+    good = report.ParseFromArray(&output[0], output.size());
+    EXPECT_TRUE(good);
+    EXPECT_EQ(1, report.config_stats_size());
+    const auto& configReport2 = report.config_stats(0);
+    EXPECT_EQ(1, configReport2.matcher_stats_size());
+    EXPECT_EQ("matcher99", configReport2.matcher_stats(0).name());
+    EXPECT_EQ(1, configReport2.matcher_stats(0).matched_times());
+
+    EXPECT_EQ(1, configReport2.condition_stats_size());
+    EXPECT_EQ("condition99", configReport2.condition_stats(0).name());
+    EXPECT_EQ(300, configReport2.condition_stats(0).max_tuple_counts());
+
+    EXPECT_EQ(1, configReport2.metric_stats_size());
+    EXPECT_EQ("metric99", configReport2.metric_stats(0).name());
+    EXPECT_EQ(270, configReport2.metric_stats(0).max_tuple_counts());
+}
+
+TEST(StatsdStatsTest, TestAtomLog) {
+    StatsdStats stats;
+    time_t now = time(nullptr);
+    // old event, we get it from the stats buffer. should be ignored.
+    stats.noteAtomLogged(android::util::SENSOR_STATE_CHANGED, 1000);
+
+    stats.noteAtomLogged(android::util::SENSOR_STATE_CHANGED, now + 1);
+    stats.noteAtomLogged(android::util::SENSOR_STATE_CHANGED, now + 2);
+    stats.noteAtomLogged(android::util::DROPBOX_ERROR_CHANGED, now + 3);
+    // pulled event, should ignore
+    stats.noteAtomLogged(android::util::WIFI_BYTES_TRANSFERRED, now + 4);
+
+    vector<uint8_t> output;
+    stats.dumpStats(&output, false);
+    StatsdStatsReport report;
+    bool good = report.ParseFromArray(&output[0], output.size());
+    EXPECT_TRUE(good);
+
+    EXPECT_EQ(2, report.atom_stats_size());
+    bool sensorAtomGood = false;
+    bool dropboxAtomGood = false;
+
+    for (const auto& atomStats : report.atom_stats()) {
+        if (atomStats.tag() == android::util::SENSOR_STATE_CHANGED && atomStats.count() == 2) {
+            sensorAtomGood = true;
+        }
+        if (atomStats.tag() == android::util::DROPBOX_ERROR_CHANGED && atomStats.count() == 1) {
+            dropboxAtomGood = true;
+        }
+    }
+
+    EXPECT_TRUE(dropboxAtomGood);
+    EXPECT_TRUE(sensorAtomGood);
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
index 35e08af..2cbeaaa 100644
--- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -32,6 +32,8 @@
 namespace os {
 namespace statsd {
 
+const ConfigKey kConfigKey(0, "test");
+
 TEST(CountMetricProducerTest, TestNonDimensionalEvents) {
     int64_t bucketStartTimeNs = 10000000000;
     int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
@@ -48,7 +50,7 @@
 
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
 
-    CountMetricProducer countProducer(metric, -1 /*-1 meaning no condition*/, wizard,
+    CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
                                       bucketStartTimeNs);
 
     // 2 events in bucket 1.
@@ -106,7 +108,7 @@
 
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
 
-    CountMetricProducer countProducer(metric, 1, wizard, bucketStartTimeNs);
+    CountMetricProducer countProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs);
 
     countProducer.onConditionChanged(true, bucketStartTimeNs);
     countProducer.onMatchedLogEvent(1 /*matcher index*/, event1, false /*pulled*/);
@@ -161,7 +163,7 @@
 
     EXPECT_CALL(*wizard, query(_, key2)).WillOnce(Return(ConditionState::kTrue));
 
-    CountMetricProducer countProducer(metric, 1 /*condition tracker index*/, wizard,
+    CountMetricProducer countProducer(kConfigKey, metric, 1 /*condition tracker index*/, wizard,
                                       bucketStartTimeNs);
 
     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1, false);
@@ -194,14 +196,14 @@
     int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
     int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
 
-    sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, bucketSizeNs);
+    sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert);
 
     CountMetric metric;
     metric.set_name("1");
     metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
 
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    CountMetricProducer countProducer(metric, -1 /*-1 meaning no condition*/, wizard,
+    CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
                                       bucketStartTimeNs);
     countProducer.addAnomalyTracker(anomalyTracker);
 
diff --git a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
index 18d177c..724ad59 100644
--- a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
@@ -32,6 +32,8 @@
 namespace os {
 namespace statsd {
 
+const ConfigKey kConfigKey(0, "test");
+
 TEST(EventMetricProducerTest, TestNoCondition) {
     uint64_t bucketStartTimeNs = 10000000000;
     uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
@@ -45,7 +47,7 @@
 
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
 
-    EventMetricProducer eventProducer(metric, -1 /*-1 meaning no condition*/, wizard,
+    EventMetricProducer eventProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
                                       bucketStartTimeNs);
 
     eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1, false /*pulled*/);
@@ -69,7 +71,7 @@
 
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
 
-    EventMetricProducer eventProducer(metric, 1, wizard, bucketStartTimeNs);
+    EventMetricProducer eventProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs);
 
     eventProducer.onConditionChanged(true /*condition*/, bucketStartTimeNs);
     eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1, false /*pulled*/);
@@ -111,7 +113,7 @@
 
     EXPECT_CALL(*wizard, query(_, key2)).WillOnce(Return(ConditionState::kTrue));
 
-    EventMetricProducer eventProducer(metric, 1, wizard, bucketStartTimeNs);
+    EventMetricProducer eventProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs);
 
     eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1, false /*pulled*/);
     eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2, false /*pulled*/);
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index b9e2b8a..85f5008 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -148,7 +148,7 @@
     alert.set_metric_name("1");
     alert.set_trigger_if_sum_gt(25);
     alert.set_number_of_buckets(2);
-    sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, bucketSizeNs);
+    sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert);
     gaugeProducer.addAnomalyTracker(anomalyTracker);
 
     std::shared_ptr<LogEvent> event1 = std::make_shared<LogEvent>(1, bucketStartTimeNs + 1);
diff --git a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
index 9e169bb..5d47437 100644
--- a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
@@ -36,6 +36,8 @@
 namespace os {
 namespace statsd {
 
+const ConfigKey kConfigKey(0, "test");
+
 TEST(MaxDurationTrackerTest, TestSimpleMaxDuration) {
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
 
@@ -45,8 +47,8 @@
     uint64_t bucketStartTimeNs = 10000000000;
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
 
-    MaxDurationTracker tracker("event", wizard, -1, false, bucketStartTimeNs, bucketSizeNs, {},
-                               buckets);
+    MaxDurationTracker tracker(kConfigKey, "metric", "event", wizard, -1, false, bucketStartTimeNs,
+                               bucketSizeNs, {}, buckets);
 
     tracker.noteStart("1", true, bucketStartTimeNs, key1);
     // Event starts again. This would not change anything as it already starts.
@@ -72,13 +74,14 @@
     uint64_t bucketStartTimeNs = 10000000000;
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
 
-    MaxDurationTracker tracker("event", wizard, -1, false, bucketStartTimeNs, bucketSizeNs, {},
-                               buckets);
+    MaxDurationTracker tracker(kConfigKey, "metric", "event", wizard, -1, false, bucketStartTimeNs,
+                               bucketSizeNs, {}, buckets);
 
     tracker.noteStart("1", true, bucketStartTimeNs + 1, key1);
 
     // Another event starts in this bucket.
     tracker.noteStart("2", true, bucketStartTimeNs + 20, key1);
+    tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 40);
     tracker.noteStopAll(bucketStartTimeNs + bucketSizeNs + 40);
     EXPECT_TRUE(tracker.mInfos.empty());
     EXPECT_EQ(1u, buckets.size());
@@ -99,8 +102,8 @@
     uint64_t bucketStartTimeNs = 10000000000;
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
 
-    MaxDurationTracker tracker("event", wizard, -1, false, bucketStartTimeNs, bucketSizeNs, {},
-                               buckets);
+    MaxDurationTracker tracker(kConfigKey, "metric", "event", wizard, -1, false, bucketStartTimeNs,
+                               bucketSizeNs, {}, buckets);
 
     // The event starts.
     tracker.noteStart("", true, bucketStartTimeNs + 1, key1);
@@ -108,20 +111,9 @@
     // Starts again. Does not change anything.
     tracker.noteStart("", true, bucketStartTimeNs + bucketSizeNs + 1, key1);
 
-    // Flushes at early 2nd bucket. The event still does not stop yet.
-    tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
-    EXPECT_EQ(1u, buckets.size());
-    EXPECT_EQ((unsigned long long)(bucketSizeNs - 1), buckets[0].mDuration);
-
-    // Flushes at the end of the 2nd bucket. The event still does not stop yet.
-    tracker.flushIfNeeded(bucketStartTimeNs + (2 * bucketSizeNs));
-    EXPECT_EQ(2u, buckets.size());
-    EXPECT_EQ((unsigned long long)(bucketSizeNs - 1), buckets[0].mDuration);
-    EXPECT_EQ((unsigned long long)bucketSizeNs, buckets[1].mDuration);
-
     // The event stops at early 4th bucket.
+    tracker.flushIfNeeded(bucketStartTimeNs + (3 * bucketSizeNs) + 20);
     tracker.noteStop("", bucketStartTimeNs + (3 * bucketSizeNs) + 20, false /*stop all*/);
-    tracker.flushIfNeeded(bucketStartTimeNs + (3 * bucketSizeNs) + 21);
     EXPECT_EQ(3u, buckets.size());
     EXPECT_EQ((unsigned long long)(bucketSizeNs - 1), buckets[0].mDuration);
     EXPECT_EQ((unsigned long long)bucketSizeNs, buckets[1].mDuration);
@@ -137,8 +129,8 @@
     uint64_t bucketStartTimeNs = 10000000000;
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
 
-    MaxDurationTracker tracker("event", wizard, -1, true, bucketStartTimeNs, bucketSizeNs, {},
-                               buckets);
+    MaxDurationTracker tracker(kConfigKey, "metric", "event", wizard, -1, true, bucketStartTimeNs,
+                               bucketSizeNs, {}, buckets);
 
     // 2 starts
     tracker.noteStart("", true, bucketStartTimeNs + 1, key1);
@@ -178,33 +170,19 @@
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
     int64_t durationTimeNs = 2 * 1000;
 
-    MaxDurationTracker tracker("event", wizard, 1, false, bucketStartTimeNs, bucketSizeNs, {},
-                               buckets);
+    MaxDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, false, bucketStartTimeNs,
+                               bucketSizeNs, {}, buckets);
     EXPECT_TRUE(tracker.mAnomalyTrackers.empty());
 
     tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
-    tracker.onSlicedConditionMayChange(eventStartTimeNs + 2 * bucketSizeNs + 5);
-    EXPECT_EQ(2u, buckets.size());
-    EXPECT_EQ(bucketSizeNs - 1, buckets[0].mDuration);
-    EXPECT_EQ(bucketSizeNs, buckets[1].mDuration);
 
-    tracker.noteStop("2:maps", eventStartTimeNs + 2 * bucketSizeNs + durationTimeNs, false);
-    EXPECT_EQ(2u, buckets.size());
-    EXPECT_EQ(bucketSizeNs - 1, buckets[0].mDuration);
-    EXPECT_EQ(bucketSizeNs, buckets[1].mDuration);
-    EXPECT_TRUE(tracker.mInfos.empty());
-    EXPECT_EQ(6LL, tracker.mDuration);
+    tracker.onSlicedConditionMayChange(eventStartTimeNs + 5);
 
-    tracker.noteStart("2:maps", false, eventStartTimeNs + 3 * bucketSizeNs + 10, key1);
-    EXPECT_EQ(1u, tracker.mInfos.size());
-    for (const auto& itr : tracker.mInfos) {
-        EXPECT_EQ(DurationState::kPaused, itr.second.state);
-        EXPECT_EQ(0LL, itr.second.lastDuration);
-    }
-    EXPECT_EQ(3u, buckets.size());
-    EXPECT_EQ(bucketSizeNs - 1, buckets[0].mDuration);
-    EXPECT_EQ(bucketSizeNs, buckets[1].mDuration);
-    EXPECT_EQ(6ULL, buckets[2].mDuration);
+    tracker.noteStop("2:maps", eventStartTimeNs + durationTimeNs, false);
+
+    tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
+    EXPECT_EQ(1u, buckets.size());
+    EXPECT_EQ(5ULL, buckets[0].mDuration);
 }
 
 TEST(MaxDurationTrackerTest, TestAnomalyDetection) {
@@ -223,9 +201,9 @@
     uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
     uint64_t bucketSizeNs = 30 * NS_PER_SEC;
 
-    sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, bucketSizeNs);
-    MaxDurationTracker tracker("event", wizard, -1, true, bucketStartTimeNs, bucketSizeNs,
-                               {anomalyTracker}, buckets);
+    sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert);
+    MaxDurationTracker tracker(kConfigKey, "metric", "event", wizard, -1, true, bucketStartTimeNs,
+                               bucketSizeNs, {anomalyTracker}, buckets);
 
     tracker.noteStart("1", true, eventStartTimeNs, key1);
     tracker.noteStop("1", eventStartTimeNs + 10, false);
@@ -233,6 +211,7 @@
     EXPECT_EQ(10LL, tracker.mDuration);
 
     tracker.noteStart("2", true, eventStartTimeNs + 20, key1);
+    tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC);
     tracker.noteStop("2", eventStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC, false);
     EXPECT_EQ((long long)(4 * NS_PER_SEC + 1LL), tracker.mDuration);
     EXPECT_EQ(anomalyTracker->mLastAlarmTimestampNs,
diff --git a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
index f4edffd..6913c81 100644
--- a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
@@ -34,6 +34,8 @@
 namespace os {
 namespace statsd {
 
+const ConfigKey kConfigKey(0, "test");
+
 TEST(OringDurationTrackerTest, TestDurationOverlap) {
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
 
@@ -47,8 +49,8 @@
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
     uint64_t durationTimeNs = 2 * 1000;
 
-    OringDurationTracker tracker("event", wizard, 1, false, bucketStartTimeNs, bucketSizeNs, {},
-                                 buckets);
+    OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, false, bucketStartTimeNs,
+                                 bucketSizeNs, {}, buckets);
 
     tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
     EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime);
@@ -73,8 +75,8 @@
     uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
 
-    OringDurationTracker tracker("event", wizard, 1, true, bucketStartTimeNs, bucketSizeNs, {},
-                                 buckets);
+    OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, true, bucketStartTimeNs,
+                                 bucketSizeNs, {}, buckets);
 
     tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
     tracker.noteStart("2:maps", true, eventStartTimeNs + 10, key1);  // overlapping wl
@@ -99,8 +101,8 @@
     uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
 
-    OringDurationTracker tracker("event", wizard, 1, true, bucketStartTimeNs, bucketSizeNs, {},
-                                 buckets);
+    OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, true, bucketStartTimeNs,
+                                 bucketSizeNs, {}, buckets);
 
     tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
     tracker.noteStart("3:maps", true, eventStartTimeNs + 10, key1);  // overlapping wl
@@ -125,15 +127,15 @@
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
     uint64_t durationTimeNs = 2 * 1000;
 
-    OringDurationTracker tracker("event", wizard, 1, true, bucketStartTimeNs, bucketSizeNs, {},
-                                 buckets);
+    OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, true, bucketStartTimeNs,
+                                 bucketSizeNs, {}, buckets);
 
     tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
     EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime);
+    tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs);
     tracker.noteStart("2:maps", true, eventStartTimeNs + 2 * bucketSizeNs, key1);
     EXPECT_EQ((long long)(bucketStartTimeNs + 2 * bucketSizeNs), tracker.mLastStartTime);
 
-    tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs);
     EXPECT_EQ(2u, buckets.size());
     EXPECT_EQ(bucketSizeNs - 1, buckets[0].mDuration);
     EXPECT_EQ(bucketSizeNs, buckets[1].mDuration);
@@ -162,17 +164,52 @@
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
     uint64_t durationTimeNs = 2 * 1000;
 
-    OringDurationTracker tracker("event", wizard, 1, false, bucketStartTimeNs, bucketSizeNs, {},
-                                 buckets);
+    OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, false, bucketStartTimeNs,
+                                 bucketSizeNs, {}, buckets);
 
     tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
 
-    tracker.onSlicedConditionMayChange(eventStartTimeNs + 2 * bucketSizeNs + 5);
-    tracker.noteStop("2:maps", eventStartTimeNs + 2 * bucketSizeNs + durationTimeNs, false);
-    tracker.flushIfNeeded(bucketStartTimeNs + 2 * bucketSizeNs + durationTimeNs);
-    EXPECT_EQ(2u, buckets.size());
-    EXPECT_EQ(bucketSizeNs - 1, buckets[0].mDuration);
-    EXPECT_EQ(bucketSizeNs, buckets[1].mDuration);
+    tracker.onSlicedConditionMayChange(eventStartTimeNs + 5);
+
+    tracker.noteStop("2:maps", eventStartTimeNs + durationTimeNs, false);
+
+    tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
+    EXPECT_EQ(1u, buckets.size());
+    EXPECT_EQ(5ULL, buckets[0].mDuration);
+}
+
+TEST(OringDurationTrackerTest, TestDurationConditionChange2) {
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+    ConditionKey key1;
+    key1["APP_BACKGROUND"] = "1:maps|";
+
+    EXPECT_CALL(*wizard, query(_, key1))
+            .Times(2)
+            .WillOnce(Return(ConditionState::kFalse))
+            .WillOnce(Return(ConditionState::kTrue));
+
+    vector<DurationBucket> buckets;
+
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
+    uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+    uint64_t durationTimeNs = 2 * 1000;
+
+    OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, false, bucketStartTimeNs,
+                                 bucketSizeNs, {}, buckets);
+
+    tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
+    // condition to false; record duration 5n
+    tracker.onSlicedConditionMayChange(eventStartTimeNs + 5);
+    // condition to true.
+    tracker.onSlicedConditionMayChange(eventStartTimeNs + 1000);
+    // 2nd duration: 1000ns
+    tracker.noteStop("2:maps", eventStartTimeNs + durationTimeNs, false);
+
+    tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
+    EXPECT_EQ(1u, buckets.size());
+    EXPECT_EQ(1005ULL, buckets[0].mDuration);
 }
 
 TEST(OringDurationTrackerTest, TestDurationConditionChangeNested) {
@@ -190,8 +227,8 @@
     uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
 
-    OringDurationTracker tracker("event", wizard, 1, true, bucketStartTimeNs, bucketSizeNs, {},
-                                 buckets);
+    OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, true, bucketStartTimeNs,
+                                 bucketSizeNs, {}, buckets);
 
     tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
     tracker.noteStart("2:maps", true, eventStartTimeNs + 2, key1);
@@ -223,9 +260,9 @@
     uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
     uint64_t bucketSizeNs = 30 * NS_PER_SEC;
 
-    sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, bucketSizeNs);
-    OringDurationTracker tracker("event", wizard, 1, true, bucketStartTimeNs, bucketSizeNs,
-                                 {anomalyTracker}, buckets);
+    sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert);
+    OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, true, bucketStartTimeNs,
+                                 bucketSizeNs, {anomalyTracker}, buckets);
 
     // Nothing in the past bucket.
     tracker.noteStart("", true, eventStartTimeNs, key1);
@@ -242,6 +279,7 @@
               tracker.predictAnomalyTimestampNs(*anomalyTracker, event1StartTimeNs));
 
     uint64_t event1StopTimeNs = eventStartTimeNs + bucketSizeNs + 10;
+    tracker.flushIfNeeded(event1StopTimeNs);
     tracker.noteStop("1", event1StopTimeNs, false);
     EXPECT_EQ(1u, buckets.size());
     EXPECT_EQ(3ULL + bucketStartTimeNs + bucketSizeNs - eventStartTimeNs - 10,
@@ -282,15 +320,14 @@
     uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
     uint64_t bucketSizeNs = 30 * NS_PER_SEC;
 
-    sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, bucketSizeNs);
-    OringDurationTracker tracker("event", wizard, 1, true /*nesting*/, bucketStartTimeNs,
-                                 bucketSizeNs, {anomalyTracker}, buckets);
+    sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert);
+    OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, true /*nesting*/,
+                                 bucketStartTimeNs, bucketSizeNs, {anomalyTracker}, buckets);
 
     tracker.noteStart("", true, eventStartTimeNs, key1);
     tracker.noteStop("", eventStartTimeNs + 10, false);
     EXPECT_EQ(anomalyTracker->mLastAlarmTimestampNs, -1);
     EXPECT_TRUE(tracker.mStarted.empty());
-    EXPECT_EQ(-1LL, tracker.mLastStartTime);
     EXPECT_EQ(10LL, tracker.mDuration);
 
     EXPECT_EQ(0u, tracker.mStarted.size());
@@ -299,6 +336,7 @@
     EXPECT_EQ(1u, anomalyTracker->mAlarms.size());
     EXPECT_EQ((long long)(51ULL * NS_PER_SEC),
               (long long)(anomalyTracker->mAlarms.begin()->second->timestampSec * NS_PER_SEC));
+    tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 25);
     tracker.noteStop("", eventStartTimeNs + 2 * bucketSizeNs + 25, false);
     EXPECT_EQ(anomalyTracker->getSumOverPastBuckets("event"), (long long)(bucketSizeNs));
     EXPECT_EQ((long long)(eventStartTimeNs + 2 * bucketSizeNs + 25),
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 1ed3636..9d78466 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -12,8 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "metrics_test_helper.h"
 #include "src/metrics/ValueMetricProducer.h"
+#include "metrics_test_helper.h"
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -22,11 +22,11 @@
 
 using namespace testing;
 using android::sp;
+using std::make_shared;
 using std::set;
+using std::shared_ptr;
 using std::unordered_map;
 using std::vector;
-using std::shared_ptr;
-using std::make_shared;
 
 #ifdef __ANDROID__
 
@@ -34,6 +34,7 @@
 namespace os {
 namespace statsd {
 
+const ConfigKey kConfigKey(0, "test");
 /*
  * Tests pulled atoms with no conditions
  */
@@ -42,7 +43,7 @@
     int64_t bucketSizeNs = 60 * 1000 * 1000 * 1000LL;
 
     int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
-    int64_t bucket3StartTimeNs = bucketStartTimeNs + 2*bucketSizeNs;
+    int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
 
     ValueMetric metric;
     metric.set_name("1");
@@ -54,12 +55,13 @@
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     // TODO: pending refactor of StatsPullerManager
     // For now we still need this so that it doesn't do real pulling.
-    shared_ptr<MockStatsPullerManager> pullerManager = make_shared<StrictMock<MockStatsPullerManager>>();
+    shared_ptr<MockStatsPullerManager> pullerManager =
+            make_shared<StrictMock<MockStatsPullerManager>>();
     EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return());
     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
 
-    ValueMetricProducer valueProducer(metric, -1 /*-1 meaning no condition*/, wizard,tagId,
-                                      bucketStartTimeNs, pullerManager);
+    ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                                      tagId, bucketStartTimeNs, pullerManager);
 
     vector<shared_ptr<LogEvent>> allData;
     allData.clear();
@@ -144,41 +146,43 @@
     int tagId = 1;
 
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    shared_ptr<MockStatsPullerManager> pullerManager = make_shared<StrictMock<MockStatsPullerManager>>();
+    shared_ptr<MockStatsPullerManager> pullerManager =
+            make_shared<StrictMock<MockStatsPullerManager>>();
     EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return());
     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
 
-    EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Invoke([] (int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-        int64_t bucketStartTimeNs = 10000000000;
-        int64_t bucketSizeNs = 60 * 1000 * 1000 * 1000LL;
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                int64_t bucketStartTimeNs = 10000000000;
+                int64_t bucketSizeNs = 60 * 1000 * 1000 * 1000LL;
 
-        int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
-        int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
-        data->clear();
-        shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-        event->write(1);
-        event->write(100);
-        event->init();
-        data->push_back(event);
-        return true;
-    }))
-    .WillOnce(Invoke([] (int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-        int64_t bucketStartTimeNs = 10000000000;
-        int64_t bucketSizeNs = 60 * 1000 * 1000 * 1000LL;
+                int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
+                int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+                event->write(1);
+                event->write(100);
+                event->init();
+                data->push_back(event);
+                return true;
+            }))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                int64_t bucketStartTimeNs = 10000000000;
+                int64_t bucketSizeNs = 60 * 1000 * 1000 * 1000LL;
 
-        int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
-        int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
-        data->clear();
-        shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 10);
-        event->write(1);
-        event->write(120);
-        event->init();
-        data->push_back(event);
-        return true;
-    }));
+                int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
+                int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 10);
+                event->write(1);
+                event->write(120);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
 
-    ValueMetricProducer valueProducer(metric, 1, wizard,tagId,
-                                      bucketStartTimeNs, pullerManager);
+    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, tagId, bucketStartTimeNs,
+                                      pullerManager);
 
     valueProducer.onConditionChanged(true, bucketStartTimeNs + 10);
 
@@ -241,10 +245,11 @@
     int tagId = 1;
 
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    shared_ptr<MockStatsPullerManager> pullerManager = make_shared<StrictMock<MockStatsPullerManager>>();
+    shared_ptr<MockStatsPullerManager> pullerManager =
+            make_shared<StrictMock<MockStatsPullerManager>>();
 
-    ValueMetricProducer valueProducer(metric, -1, wizard,-1,
-                                      bucketStartTimeNs, pullerManager);
+    ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, -1, bucketStartTimeNs,
+                                      pullerManager);
 
     shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
     event1->write(1);
diff --git a/config/compiled-classes-phone b/config/compiled-classes-phone
index 8684d0a..afa802c 100644
--- a/config/compiled-classes-phone
+++ b/config/compiled-classes-phone
@@ -4607,20 +4607,8 @@
 android.view.WindowManagerGlobal$1
 android.view.WindowManagerGlobal$2
 android.view.WindowManagerImpl
-android.view.WindowManagerInternal
-android.view.WindowManagerInternal$AppTransitionListener
-android.view.WindowManagerInternal$MagnificationCallbacks
-android.view.WindowManagerInternal$OnHardKeyboardStatusChangeListener
-android.view.WindowManagerInternal$WindowsForAccessibilityCallback
-android.view.WindowManagerPolicy
-android.view.WindowManagerPolicy$InputConsumer
-android.view.WindowManagerPolicy$OnKeyguardExitResult
-android.view.WindowManagerPolicy$PointerEventListener
-android.view.WindowManagerPolicy$ScreenOffListener
-android.view.WindowManagerPolicy$ScreenOnListener
-android.view.WindowManagerPolicy$StartingSurface
-android.view.WindowManagerPolicy$WindowManagerFuncs
-android.view.WindowManagerPolicy$WindowState
+android.view.WindowManagerPolicyConstants
+android.view.WindowManagerPolicyConstants$PointerEventListener
 android.view.accessibility.AccessibilityEvent
 android.view.accessibility.AccessibilityEvent$1
 android.view.accessibility.AccessibilityEventSource
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index a46b3c7..d7efa91 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -283,4 +283,20 @@
      * @param token The IApplicationToken for the activity
      */
     public abstract void setFocusedActivity(IBinder token);
+
+    /**
+     * Set a uid that is allowed to bypass stopped app switches, launching an app
+     * whenever it wants.
+     *
+     * @param type Type of the caller -- unique string the caller supplies to identify itself
+     * and disambiguate with other calles.
+     * @param uid The uid of the app to be allowed, or -1 to clear the uid for this type.
+     * @param userId The user it is allowed for.
+     */
+    public abstract void setAllowAppSwitches(@NonNull String type, int uid, int userId);
+
+    /**
+     * @return true if runtime was restarted, false if it's normal boot
+     */
+    public abstract boolean isRuntimeRestarted();
 }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 5f34322..b0d020a 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -59,11 +59,10 @@
 import android.os.Looper;
 import android.os.Process;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.os.storage.IStorageManager;
+import android.os.storage.StorageManager;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.OsConstants;
@@ -2457,7 +2456,8 @@
      * unable to create, they are filtered by replacing with {@code null}.
      */
     private File[] ensureExternalDirsExistOrFilter(File[] dirs) {
-        File[] result = new File[dirs.length];
+        final StorageManager sm = getSystemService(StorageManager.class);
+        final File[] result = new File[dirs.length];
         for (int i = 0; i < dirs.length; i++) {
             File dir = dirs[i];
             if (!dir.exists()) {
@@ -2466,15 +2466,8 @@
                     if (!dir.exists()) {
                         // Failing to mkdir() may be okay, since we might not have
                         // enough permissions; ask vold to create on our behalf.
-                        final IStorageManager storageManager = IStorageManager.Stub.asInterface(
-                                ServiceManager.getService("mount"));
                         try {
-                            final int res = storageManager.mkdirs(
-                                    getPackageName(), dir.getAbsolutePath());
-                            if (res != 0) {
-                                Log.w(TAG, "Failed to ensure " + dir + ": " + res);
-                                dir = null;
-                            }
+                            sm.mkdirs(dir);
                         } catch (Exception e) {
                             Log.w(TAG, "Failed to ensure " + dir + ": " + e);
                             dir = null;
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 4fc649e..2d6308c 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -473,7 +473,7 @@
     /**
      * Notify the system that the keyguard is going away.
      *
-     * @param flags See {@link android.view.WindowManagerPolicy#KEYGUARD_GOING_AWAY_FLAG_TO_SHADE}
+     * @param flags See {@link android.view.WindowManagerPolicyConstants#KEYGUARD_GOING_AWAY_FLAG_TO_SHADE}
      *              etc.
      */
     void keyguardGoingAway(int flags);
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index 2c1fad1..80399ae 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -40,6 +40,13 @@
  */
 @TestApi
 public class WindowConfiguration implements Parcelable, Comparable<WindowConfiguration> {
+    /**
+     * bounds that can differ from app bounds, which may include things such as insets.
+     *
+     * TODO: Investigate combining with {@link mAppBounds}. Can the latter be a product of the
+     * former?
+     */
+    private Rect mBounds = new Rect();
 
     /**
      * {@link android.graphics.Rect} defining app bounds. The dimensions override usages of
@@ -117,22 +124,26 @@
     })
     public @interface ActivityType {}
 
+    /** Bit that indicates that the {@link #mBounds} changed.
+     * @hide */
+    public static final int WINDOW_CONFIG_BOUNDS = 1 << 0;
     /** Bit that indicates that the {@link #mAppBounds} changed.
      * @hide */
-    public static final int WINDOW_CONFIG_APP_BOUNDS = 1 << 0;
+    public static final int WINDOW_CONFIG_APP_BOUNDS = 1 << 1;
     /** Bit that indicates that the {@link #mWindowingMode} changed.
      * @hide */
-    public static final int WINDOW_CONFIG_WINDOWING_MODE = 1 << 1;
+    public static final int WINDOW_CONFIG_WINDOWING_MODE = 1 << 2;
     /** Bit that indicates that the {@link #mActivityType} changed.
      * @hide */
-    public static final int WINDOW_CONFIG_ACTIVITY_TYPE = 1 << 2;
+    public static final int WINDOW_CONFIG_ACTIVITY_TYPE = 1 << 3;
 
     /** @hide */
     @IntDef(flag = true,
             value = {
+                    WINDOW_CONFIG_BOUNDS,
                     WINDOW_CONFIG_APP_BOUNDS,
                     WINDOW_CONFIG_WINDOWING_MODE,
-                    WINDOW_CONFIG_ACTIVITY_TYPE,
+                    WINDOW_CONFIG_ACTIVITY_TYPE
             })
     public @interface WindowConfig {}
 
@@ -151,12 +162,14 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
+        dest.writeParcelable(mBounds, flags);
         dest.writeParcelable(mAppBounds, flags);
         dest.writeInt(mWindowingMode);
         dest.writeInt(mActivityType);
     }
 
     private void readFromParcel(Parcel source) {
+        mBounds = source.readParcelable(Rect.class.getClassLoader());
         mAppBounds = source.readParcelable(Rect.class.getClassLoader());
         mWindowingMode = source.readInt();
         mActivityType = source.readInt();
@@ -181,6 +194,19 @@
     };
 
     /**
+     * Sets the bounds to the provided {@link Rect}.
+     * @param rect the new bounds value.
+     */
+    public void setBounds(Rect rect) {
+        if (rect == null) {
+            mBounds.setEmpty();
+            return;
+        }
+
+        mBounds.set(rect);
+    }
+
+    /**
      * Set {@link #mAppBounds} to the input Rect.
      * @param rect The rect value to set {@link #mAppBounds} to.
      * @see #getAppBounds()
@@ -212,6 +238,11 @@
         return mAppBounds;
     }
 
+    /** @see #setBounds(Rect) */
+    public Rect getBounds() {
+        return mBounds;
+    }
+
     public void setWindowingMode(@WindowingMode int windowingMode) {
         mWindowingMode = windowingMode;
     }
@@ -244,6 +275,7 @@
     }
 
     public void setTo(WindowConfiguration other) {
+        setBounds(other.mBounds);
         setAppBounds(other.mAppBounds);
         setWindowingMode(other.mWindowingMode);
         setActivityType(other.mActivityType);
@@ -258,6 +290,7 @@
     /** @hide */
     public void setToDefaults() {
         setAppBounds(null);
+        setBounds(null);
         setWindowingMode(WINDOWING_MODE_UNDEFINED);
         setActivityType(ACTIVITY_TYPE_UNDEFINED);
     }
@@ -272,6 +305,11 @@
      */
     public @WindowConfig int updateFrom(@NonNull WindowConfiguration delta) {
         int changed = 0;
+        // Only allow override if bounds is not empty
+        if (!delta.mBounds.isEmpty() && !delta.mBounds.equals(mBounds)) {
+            changed |= WINDOW_CONFIG_BOUNDS;
+            setBounds(delta.mBounds);
+        }
         if (delta.mAppBounds != null && !delta.mAppBounds.equals(mAppBounds)) {
             changed |= WINDOW_CONFIG_APP_BOUNDS;
             setAppBounds(delta.mAppBounds);
@@ -303,6 +341,10 @@
     public @WindowConfig long diff(WindowConfiguration other, boolean compareUndefined) {
         long changes = 0;
 
+        if (!mBounds.equals(other.mBounds)) {
+            changes |= WINDOW_CONFIG_BOUNDS;
+        }
+
         // Make sure that one of the values is not null and that they are not equal.
         if ((compareUndefined || other.mAppBounds != null)
                 && mAppBounds != other.mAppBounds
@@ -340,6 +382,16 @@
             n = mAppBounds.bottom - that.mAppBounds.bottom;
             if (n != 0) return n;
         }
+
+        n = mBounds.left - that.mBounds.left;
+        if (n != 0) return n;
+        n = mBounds.top - that.mBounds.top;
+        if (n != 0) return n;
+        n = mBounds.right - that.mBounds.right;
+        if (n != 0) return n;
+        n = mBounds.bottom - that.mBounds.bottom;
+        if (n != 0) return n;
+
         n = mWindowingMode - that.mWindowingMode;
         if (n != 0) return n;
         n = mActivityType - that.mActivityType;
@@ -367,6 +419,8 @@
         if (mAppBounds != null) {
             result = 31 * result + mAppBounds.hashCode();
         }
+        result = 31 * result + mBounds.hashCode();
+
         result = 31 * result + mWindowingMode;
         result = 31 * result + mActivityType;
         return result;
@@ -375,7 +429,8 @@
     /** @hide */
     @Override
     public String toString() {
-        return "{mAppBounds=" + mAppBounds
+        return "{ mBounds=" + mBounds
+                + " mAppBounds=" + mAppBounds
                 + " mWindowingMode=" + windowingModeToString(mWindowingMode)
                 + " mActivityType=" + activityTypeToString(mActivityType) + "}";
     }
diff --git a/core/java/android/app/admin/ConnectEvent.java b/core/java/android/app/admin/ConnectEvent.java
index ffd38e2..f06a925 100644
--- a/core/java/android/app/admin/ConnectEvent.java
+++ b/core/java/android/app/admin/ConnectEvent.java
@@ -32,29 +32,30 @@
 public final class ConnectEvent extends NetworkEvent implements Parcelable {
 
     /** The destination IP address. */
-    private final String ipAddress;
+    private final String mIpAddress;
 
     /** The destination port number. */
-    private final int port;
+    private final int mPort;
 
     /** @hide */
     public ConnectEvent(String ipAddress, int port, String packageName, long timestamp) {
         super(packageName, timestamp);
-        this.ipAddress = ipAddress;
-        this.port = port;
+        this.mIpAddress = ipAddress;
+        this.mPort = port;
     }
 
     private ConnectEvent(Parcel in) {
-        this.ipAddress = in.readString();
-        this.port = in.readInt();
-        this.packageName = in.readString();
-        this.timestamp = in.readLong();
+        this.mIpAddress = in.readString();
+        this.mPort = in.readInt();
+        this.mPackageName = in.readString();
+        this.mTimestamp = in.readLong();
+        this.mId = in.readLong();
     }
 
     public InetAddress getInetAddress() {
         try {
             // ipAddress is already an address, not a host name, no DNS resolution will happen.
-            return InetAddress.getByName(ipAddress);
+            return InetAddress.getByName(mIpAddress);
         } catch (UnknownHostException e) {
             // Should never happen as we aren't passing a host name.
             return InetAddress.getLoopbackAddress();
@@ -62,13 +63,13 @@
     }
 
     public int getPort() {
-        return port;
+        return mPort;
     }
 
     @Override
     public String toString() {
-        return String.format("ConnectEvent(%s, %d, %d, %s)", ipAddress, port, timestamp,
-                packageName);
+        return String.format("ConnectEvent(%s, %d, %d, %s)", mIpAddress, mPort, mTimestamp,
+                mPackageName);
     }
 
     public static final Parcelable.Creator<ConnectEvent> CREATOR
@@ -96,10 +97,10 @@
     public void writeToParcel(Parcel out, int flags) {
         // write parcel token first
         out.writeInt(PARCEL_TOKEN_CONNECT_EVENT);
-        out.writeString(ipAddress);
-        out.writeInt(port);
-        out.writeString(packageName);
-        out.writeLong(timestamp);
+        out.writeString(mIpAddress);
+        out.writeInt(mPort);
+        out.writeString(mPackageName);
+        out.writeLong(mTimestamp);
+        out.writeLong(mId);
     }
 }
-
diff --git a/core/java/android/app/admin/DnsEvent.java b/core/java/android/app/admin/DnsEvent.java
index f84c5b0..4ddf13e 100644
--- a/core/java/android/app/admin/DnsEvent.java
+++ b/core/java/android/app/admin/DnsEvent.java
@@ -34,46 +34,47 @@
 public final class DnsEvent extends NetworkEvent implements Parcelable {
 
     /** The hostname that was looked up. */
-    private final String hostname;
+    private final String mHostname;
 
     /** Contains (possibly a subset of) the IP addresses returned. */
-    private final String[] ipAddresses;
+    private final String[] mIpAddresses;
 
     /**
      * The number of IP addresses returned from the DNS lookup event. May be different from the
      * length of ipAddresses if there were too many addresses to log.
      */
-    private final int ipAddressesCount;
+    private final int mIpAddressesCount;
 
     /** @hide */
     public DnsEvent(String hostname, String[] ipAddresses, int ipAddressesCount,
             String packageName, long timestamp) {
         super(packageName, timestamp);
-        this.hostname = hostname;
-        this.ipAddresses = ipAddresses;
-        this.ipAddressesCount = ipAddressesCount;
+        this.mHostname = hostname;
+        this.mIpAddresses = ipAddresses;
+        this.mIpAddressesCount = ipAddressesCount;
     }
 
     private DnsEvent(Parcel in) {
-        this.hostname = in.readString();
-        this.ipAddresses = in.createStringArray();
-        this.ipAddressesCount = in.readInt();
-        this.packageName = in.readString();
-        this.timestamp = in.readLong();
+        this.mHostname = in.readString();
+        this.mIpAddresses = in.createStringArray();
+        this.mIpAddressesCount = in.readInt();
+        this.mPackageName = in.readString();
+        this.mTimestamp = in.readLong();
+        this.mId = in.readLong();
     }
 
     /** Returns the hostname that was looked up. */
     public String getHostname() {
-        return hostname;
+        return mHostname;
     }
 
     /** Returns (possibly a subset of) the IP addresses returned. */
     public List<InetAddress> getInetAddresses() {
-        if (ipAddresses == null || ipAddresses.length == 0) {
+        if (mIpAddresses == null || mIpAddresses.length == 0) {
             return Collections.emptyList();
         }
-        final List<InetAddress> inetAddresses = new ArrayList<>(ipAddresses.length);
-        for (final String ipAddress : ipAddresses) {
+        final List<InetAddress> inetAddresses = new ArrayList<>(mIpAddresses.length);
+        for (final String ipAddress : mIpAddresses) {
             try {
                 // ipAddress is already an address, not a host name, no DNS resolution will happen.
                 inetAddresses.add(InetAddress.getByName(ipAddress));
@@ -90,14 +91,14 @@
      * addresses to log.
      */
     public int getTotalResolvedAddressCount() {
-        return ipAddressesCount;
+        return mIpAddressesCount;
     }
 
     @Override
     public String toString() {
-        return String.format("DnsEvent(%s, %s, %d, %d, %s)", hostname,
-                (ipAddresses == null) ? "NONE" : String.join(" ", ipAddresses),
-                ipAddressesCount, timestamp, packageName);
+        return String.format("DnsEvent(%s, %s, %d, %d, %s)", mHostname,
+                (mIpAddresses == null) ? "NONE" : String.join(" ", mIpAddresses),
+                mIpAddressesCount, mTimestamp, mPackageName);
     }
 
     public static final Parcelable.Creator<DnsEvent> CREATOR
@@ -125,11 +126,11 @@
     public void writeToParcel(Parcel out, int flags) {
         // write parcel token first
         out.writeInt(PARCEL_TOKEN_DNS_EVENT);
-        out.writeString(hostname);
-        out.writeStringArray(ipAddresses);
-        out.writeInt(ipAddressesCount);
-        out.writeString(packageName);
-        out.writeLong(timestamp);
+        out.writeString(mHostname);
+        out.writeStringArray(mIpAddresses);
+        out.writeInt(mIpAddressesCount);
+        out.writeString(mPackageName);
+        out.writeLong(mTimestamp);
+        out.writeLong(mId);
     }
 }
-
diff --git a/core/java/android/app/admin/NetworkEvent.java b/core/java/android/app/admin/NetworkEvent.java
index 2646c3f..947e4fe 100644
--- a/core/java/android/app/admin/NetworkEvent.java
+++ b/core/java/android/app/admin/NetworkEvent.java
@@ -18,8 +18,8 @@
 
 import android.content.pm.PackageManager;
 import android.os.Parcel;
-import android.os.Parcelable;
 import android.os.ParcelFormatException;
+import android.os.Parcelable;
 
 /**
  * An abstract class that represents a network event.
@@ -32,10 +32,13 @@
     static final int PARCEL_TOKEN_CONNECT_EVENT = 2;
 
     /** The package name of the UID that performed the query. */
-    String packageName;
+    String mPackageName;
 
     /** The timestamp of the event being reported in milliseconds. */
-    long timestamp;
+    long mTimestamp;
+
+    /** The id of the event. */
+    long mId;
 
     /** @hide */
     NetworkEvent() {
@@ -44,8 +47,8 @@
 
     /** @hide */
     NetworkEvent(String packageName, long timestamp) {
-        this.packageName = packageName;
-        this.timestamp = timestamp;
+        this.mPackageName = packageName;
+        this.mTimestamp = timestamp;
     }
 
     /**
@@ -53,7 +56,7 @@
      * {@link PackageManager#getNameForUid}.
      */
     public String getPackageName() {
-        return packageName;
+        return mPackageName;
     }
 
     /**
@@ -61,7 +64,20 @@
      * the time the event was reported and midnight, January 1, 1970 UTC.
      */
     public long getTimestamp() {
-        return timestamp;
+        return mTimestamp;
+    }
+
+    /** @hide */
+    public void setId(long id) {
+        this.mId = id;
+    }
+
+    /**
+     * Returns the id of the event, where the id monotonically increases for each event. The id
+     * is reset when the device reboots, and when network logging is enabled.
+     */
+    public long getId() {
+        return this.mId;
     }
 
     @Override
@@ -95,4 +111,3 @@
     @Override
     public abstract void writeToParcel(Parcel out, int flags);
 }
-
diff --git a/core/java/android/app/slice/Slice.java b/core/java/android/app/slice/Slice.java
index c5f2272..ddc5760 100644
--- a/core/java/android/app/slice/Slice.java
+++ b/core/java/android/app/slice/Slice.java
@@ -58,6 +58,16 @@
     public @interface SliceHint{ }
 
     /**
+     * The meta-data key that allows an activity to easily be linked directly to a slice.
+     * <p>
+     * An activity can be statically linked to a slice uri by including a meta-data item
+     * for this key that contains a valid slice uri for the same application declaring
+     * the activity.
+     * @hide
+     */
+    public static final String SLICE_METADATA_KEY = "android.metadata.SLICE_URI";
+
+    /**
      * Hint that this content is a title of other content in the slice. This can also indicate that
      * the content should be used in the shortcut representation of the slice (icon, label, action),
      * normally this should be indicated by adding the hint on the action containing that content.
diff --git a/core/java/android/content/pm/InstantAppInfo.java b/core/java/android/content/pm/InstantAppInfo.java
index 67afc92..cb04fc3 100644
--- a/core/java/android/content/pm/InstantAppInfo.java
+++ b/core/java/android/content/pm/InstantAppInfo.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -31,6 +32,7 @@
  *
  * @hide
  */
+@SystemApi
 public final class InstantAppInfo implements Parcelable {
     private final ApplicationInfo mApplicationInfo;
 
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 68bb562..ebeaad7 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1258,9 +1258,12 @@
                 }
             }
 
-            pkg.setCodePath(packageDir.getAbsolutePath());
+            pkg.setCodePath(packageDir.getCanonicalPath());
             pkg.setUse32bitAbi(lite.use32bitAbi);
             return pkg;
+        } catch (IOException e) {
+            throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+                    "Failed to get path: " + lite.baseCodePath, e);
         } finally {
             IoUtils.closeQuietly(assetLoader);
         }
@@ -1289,9 +1292,12 @@
 
         try {
             final Package pkg = parseBaseApk(apkFile, assets, flags);
-            pkg.setCodePath(apkFile.getAbsolutePath());
+            pkg.setCodePath(apkFile.getCanonicalPath());
             pkg.setUse32bitAbi(lite.use32bitAbi);
             return pkg;
+        } catch (IOException e) {
+            throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+                    "Failed to get path: " + apkFile, e);
         } finally {
             IoUtils.closeQuietly(assets);
         }
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index ef77d6e..8935745 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
+import android.app.KeyguardManager;
 import android.content.Context;
 import android.graphics.Point;
 import android.media.projection.MediaProjection;
@@ -27,7 +28,6 @@
 import android.util.SparseArray;
 import android.view.Display;
 import android.view.Surface;
-import android.view.WindowManagerPolicy;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -254,8 +254,8 @@
      * </p>
      *
      * @see #createVirtualDisplay
-     * @see WindowManagerPolicy#isKeyguardSecure(int)
-     * @see WindowManagerPolicy#isKeyguardTrustedLw()
+     * @see KeyguardManager#isDeviceSecure()
+     * @see KeyguardManager#isDeviceLocked()
      * @hide
      */
     // TODO: Update name and documentation and un-hide the flag. Don't change the value before that.
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index ee75fd4..f468e5d 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -31,16 +31,10 @@
 import java.util.StringJoiner;
 
 /**
- * Representation of the capabilities of a network. This object serves two
- * purposes:
- * <ul>
- * <li>An expression of the current capabilities of an active network, typically
- * expressed through
+ * Representation of the capabilities of an active network. Instances are
+ * typically obtained through
  * {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)}
  * or {@link ConnectivityManager#getNetworkCapabilities(Network)}.
- * <li>An expression of the future capabilities of a desired network, typically
- * expressed through {@link NetworkRequest}.
- * </ul>
  * <p>
  * This replaces the old {@link ConnectivityManager#TYPE_MOBILE} method of
  * network selection. Rather than indicate a need for Wi-Fi because an
@@ -79,7 +73,7 @@
      */
     public void clearAll() {
         mNetworkCapabilities = mTransportTypes = 0;
-        mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = 0;
+        mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
         mNetworkSpecifier = null;
         mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
     }
@@ -359,6 +353,7 @@
 
     /**
      * Sets all the capabilities set on this {@code NetworkCapability} instance.
+     * This overwrites any existing capabilities.
      *
      * @hide
      */
@@ -582,6 +577,7 @@
 
     /**
      * Sets all the transports set on this {@code NetworkCapability} instance.
+     * This overwrites any existing transports.
      *
      * @hide
      */
@@ -780,7 +776,7 @@
      * Signal strength. This is a signed integer, and higher values indicate better signal.
      * The exact units are bearer-dependent. For example, Wi-Fi uses RSSI.
      */
-    private int mSignalStrength;
+    private int mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
 
     /**
      * Sets the signal strength. This is a signed integer, with higher values indicating a stronger
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 25b1705..97ded2d 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -16,6 +16,7 @@
 
 package android.net;
 
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -32,7 +33,7 @@
      * The {@link NetworkCapabilities} that define this request.
      * @hide
      */
-    public final NetworkCapabilities networkCapabilities;
+    public final @NonNull NetworkCapabilities networkCapabilities;
 
     /**
      * Identifies the request.  NetworkRequests should only be constructed by
@@ -307,7 +308,7 @@
         return 0;
     }
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeParcelable(networkCapabilities, flags);
+        networkCapabilities.writeToParcel(dest, flags);
         dest.writeInt(legacyType);
         dest.writeInt(requestId);
         dest.writeString(type.name());
@@ -315,7 +316,7 @@
     public static final Creator<NetworkRequest> CREATOR =
         new Creator<NetworkRequest>() {
             public NetworkRequest createFromParcel(Parcel in) {
-                NetworkCapabilities nc = (NetworkCapabilities)in.readParcelable(null);
+                NetworkCapabilities nc = NetworkCapabilities.CREATOR.createFromParcel(in);
                 int legacyType = in.readInt();
                 int requestId = in.readInt();
                 Type type = Type.valueOf(in.readString());  // IllegalArgumentException if invalid.
diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java
index 95e3802..b00cb48 100644
--- a/core/java/android/net/NetworkState.java
+++ b/core/java/android/net/NetworkState.java
@@ -18,6 +18,7 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.Slog;
 
 /**
  * Snapshot of network state.
@@ -43,6 +44,16 @@
         this.network = network;
         this.subscriberId = subscriberId;
         this.networkId = networkId;
+
+        // This object is an atomic view of a network, so the various components
+        // should always agree on roaming state.
+        if (networkInfo != null && networkCapabilities != null) {
+            if (networkInfo.isRoaming() == networkCapabilities
+                    .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)) {
+                Slog.wtf("NetworkState", "Roaming state disagreement between " + networkInfo
+                        + " and " + networkCapabilities);
+            }
+        }
     }
 
     public NetworkState(Parcel in) {
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index af91e81..811091e 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -224,6 +224,7 @@
      *   - Always On Display (screen doze mode) time and power
      * New in version 28:
      *   - Light/Deep Doze power
+     *   - WiFi Multicast Wakelock statistics (count & duration)
      */
     static final int CHECKIN_VERSION = 28;
 
@@ -313,6 +314,8 @@
     private static final String CAMERA_DATA = "cam";
     private static final String VIDEO_DATA = "vid";
     private static final String AUDIO_DATA = "aud";
+    private static final String WIFI_MULTICAST_TOTAL_DATA = "wmct";
+    private static final String WIFI_MULTICAST_DATA = "wmc";
 
     public static final String RESULT_RECEIVER_CONTROLLER_KEY = "controller_activity";
 
@@ -516,6 +519,13 @@
         public abstract ArrayMap<String, ? extends Wakelock> getWakelockStats();
 
         /**
+         * Returns the WiFi Multicast Wakelock statistics.
+         *
+         * @return a Timer Object for the per uid Multicast statistics.
+         */
+        public abstract Timer getMulticastWakelockStats();
+
+        /**
          * Returns a mapping containing sync statistics.
          *
          * @return a Map from Strings to Timer objects.
@@ -3363,13 +3373,16 @@
                 screenDozeTime / 1000);
 
 
-        // Calculate wakelock times across all uids.
+        // Calculate both wakelock and wifi multicast wakelock times across all uids.
         long fullWakeLockTimeTotal = 0;
         long partialWakeLockTimeTotal = 0;
+        long multicastWakeLockTimeTotalMicros = 0;
+        int multicastWakeLockCountTotal = 0;
 
         for (int iu = 0; iu < NU; iu++) {
             final Uid u = uidStats.valueAt(iu);
 
+            // First calculating the wakelock stats
             final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks
                     = u.getWakelockStats();
             for (int iw=wakelocks.size()-1; iw>=0; iw--) {
@@ -3387,6 +3400,13 @@
                         rawRealtime, which);
                 }
             }
+
+            // Now calculating the wifi multicast wakelock stats
+            final Timer mcTimer = u.getMulticastWakelockStats();
+            if (mcTimer != null) {
+                multicastWakeLockTimeTotalMicros += mcTimer.getTotalTimeLocked(rawRealtime, which);
+                multicastWakeLockCountTotal += mcTimer.getCountLocked(which);
+            }
         }
 
         // Dump network stats
@@ -3502,6 +3522,11 @@
         }
         dumpLine(pw, 0 /* uid */, category, WIFI_SIGNAL_STRENGTH_COUNT_DATA, args);
 
+        // Dump Multicast total stats
+        dumpLine(pw, 0 /* uid */, category, WIFI_MULTICAST_TOTAL_DATA,
+                multicastWakeLockTimeTotalMicros / 1000,
+                multicastWakeLockCountTotal);
+
         if (which == STATS_SINCE_UNPLUGGED) {
             dumpLine(pw, 0 /* uid */, category, BATTERY_LEVEL_DATA, getDischargeStartLevel(),
                     getDischargeCurrentLevel());
@@ -3828,6 +3853,18 @@
                 }
             }
 
+            // WiFi Multicast Wakelock Statistics
+            final Timer mcTimer = u.getMulticastWakelockStats();
+            if (mcTimer != null) {
+                final long totalMcWakelockTimeMs =
+                        mcTimer.getTotalTimeLocked(rawRealtime, which) / 1000 ;
+                final int countMcWakelock = mcTimer.getCountLocked(which);
+                if(totalMcWakelockTimeMs > 0) {
+                    dumpLine(pw, uid, category, WIFI_MULTICAST_DATA,
+                            totalMcWakelockTimeMs, countMcWakelock);
+                }
+            }
+
             final ArrayMap<String, ? extends Timer> syncs = u.getSyncStats();
             for (int isy=syncs.size()-1; isy>=0; isy--) {
                 final Timer timer = syncs.valueAt(isy);
@@ -4327,15 +4364,18 @@
             pw.print("  Connectivity changes: "); pw.println(connChanges);
         }
 
-        // Calculate wakelock times across all uids.
+        // Calculate both wakelock and wifi multicast wakelock times across all uids.
         long fullWakeLockTimeTotalMicros = 0;
         long partialWakeLockTimeTotalMicros = 0;
+        long multicastWakeLockTimeTotalMicros = 0;
+        int multicastWakeLockCountTotal = 0;
 
         final ArrayList<TimerEntry> timers = new ArrayList<>();
 
         for (int iu = 0; iu < NU; iu++) {
             final Uid u = uidStats.valueAt(iu);
 
+            // First calculate wakelock statistics
             final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks
                     = u.getWakelockStats();
             for (int iw=wakelocks.size()-1; iw>=0; iw--) {
@@ -4363,6 +4403,13 @@
                     }
                 }
             }
+
+            // Next calculate wifi multicast wakelock statistics
+            final Timer mcTimer = u.getMulticastWakelockStats();
+            if (mcTimer != null) {
+                multicastWakeLockTimeTotalMicros += mcTimer.getTotalTimeLocked(rawRealtime, which);
+                multicastWakeLockCountTotal += mcTimer.getCountLocked(which);
+            }
         }
 
         final long mobileRxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
@@ -4392,6 +4439,20 @@
             pw.println(sb.toString());
         }
 
+        if (multicastWakeLockTimeTotalMicros != 0) {
+            sb.setLength(0);
+            sb.append(prefix);
+            sb.append("  Total WiFi Multicast wakelock Count: ");
+            sb.append(multicastWakeLockCountTotal);
+            pw.println(sb.toString());
+
+            sb.setLength(0);
+            sb.append(prefix);
+            sb.append("  Total WiFi Multicast wakelock time: ");
+            formatTimeMsNoSpace(sb, (multicastWakeLockTimeTotalMicros + 500) / 1000);
+            pw.println(sb.toString());
+        }
+
         pw.println("");
         pw.print(prefix);
         sb.setLength(0);
@@ -5309,6 +5370,24 @@
                 }
             }
 
+            // Calculate multicast wakelock stats
+            final Timer mcTimer = u.getMulticastWakelockStats();
+            if (mcTimer != null) {
+                final long multicastWakeLockTimeMicros = mcTimer.getTotalTimeLocked(rawRealtime, which);
+                final int multicastWakeLockCount = mcTimer.getCountLocked(which);
+
+                if (multicastWakeLockTimeMicros > 0) {
+                    sb.setLength(0);
+                    sb.append(prefix);
+                    sb.append("    WiFi Multicast Wakelock");
+                    sb.append(" count = ");
+                    sb.append(multicastWakeLockCount);
+                    sb.append(" time = ");
+                    formatTimeMsNoSpace(sb, (multicastWakeLockTimeMicros + 500) / 1000);
+                    pw.println(sb.toString());
+                }
+            }
+
             final ArrayMap<String, ? extends Timer> syncs = u.getSyncStats();
             for (int isy=syncs.size()-1; isy>=0; isy--) {
                 final Timer timer = syncs.valueAt(isy);
@@ -7085,6 +7164,10 @@
                 proto.end(wToken);
             }
 
+            // Wifi Multicast Wakelock (WIFI_MULTICAST_WAKELOCK_DATA)
+            dumpTimer(proto, UidProto.WIFI_MULTICAST_WAKELOCK, u.getMulticastWakelockStats(),
+                    rawRealtimeUs, which);
+
             // Wakeup alarms (WAKEUP_ALARM_DATA)
             for (int ipkg = packageStats.size() - 1; ipkg >= 0; --ipkg) {
                 final Uid.Pkg ps = packageStats.valueAt(ipkg);
@@ -7341,6 +7424,30 @@
                 getLongestDeviceIdleModeTime(DEVICE_IDLE_MODE_LIGHT));
         proto.end(mToken);
 
+        // Wifi multicast wakelock total stats (WIFI_MULTICAST_WAKELOCK_TOTAL_DATA)
+        // Calculate multicast wakelock stats across all uids.
+        long multicastWakeLockTimeTotalUs = 0;
+        int multicastWakeLockCountTotal = 0;
+
+        for (int iu = 0; iu < uidStats.size(); iu++) {
+            final Uid u = uidStats.valueAt(iu);
+
+            final Timer mcTimer = u.getMulticastWakelockStats();
+
+            if (mcTimer != null) {
+                multicastWakeLockTimeTotalUs +=
+                        mcTimer.getTotalTimeLocked(rawRealtimeUs, which);
+                multicastWakeLockCountTotal += mcTimer.getCountLocked(which);
+            }
+        }
+
+        final long wmctToken = proto.start(SystemProto.WIFI_MULTICAST_WAKELOCK_TOTAL);
+        proto.write(SystemProto.WifiMulticastWakelockTotal.DURATION_MS,
+                multicastWakeLockTimeTotalUs / 1000);
+        proto.write(SystemProto.WifiMulticastWakelockTotal.COUNT,
+                multicastWakeLockCountTotal);
+        proto.end(wmctToken);
+
         // Power use item (POWER_USE_ITEM_DATA)
         final List<BatterySipper> sippers = helper.getUsageList();
         if (sippers != null) {
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 6ebf3b9..02c7bd6 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -19,9 +19,11 @@
 import android.Manifest;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
+import android.app.Application;
 import android.content.Context;
 import android.text.TextUtils;
 import android.util.Slog;
+import android.view.View;
 
 import com.android.internal.telephony.TelephonyProperties;
 
@@ -761,6 +763,80 @@
          * <p>Applications targeting this or a later release will get these
          * new changes in behavior:</p>
          * <ul>
+         * <li><a href="{@docRoot}about/versions/oreo/background.html">Background execution limits</a>
+         * are applied to the application.</li>
+         * <li>The behavior of AccountManager's
+         * {@link android.accounts.AccountManager#getAccountsByType},
+         * {@link android.accounts.AccountManager#getAccountsByTypeAndFeatures}, and
+         * {@link android.accounts.AccountManager#hasFeatures} has changed as documented there.</li>
+         * <li>{@link android.app.ActivityManager.RunningAppProcessInfo#IMPORTANCE_PERCEPTIBLE_PRE_26}
+         * is now returned as
+         * {@link android.app.ActivityManager.RunningAppProcessInfo#IMPORTANCE_PERCEPTIBLE}.</li>
+         * <li>The {@link android.app.NotificationManager} now requires the use of notification
+         * channels.</li>
+         * <li>Changes to the strict mode that are set in
+         * {@link Application#onCreate Application.onCreate} will no longer be clobbered after
+         * that function returns.</li>
+         * <li>A shared library apk with native code will have that native code included in
+         * the library path of its clients.</li>
+         * <li>{@link android.content.Context#getSharedPreferences Context.getSharedPreferences}
+         * in credential encrypted storage will throw an exception before the user is unlocked.</li>
+         * <li>Attempting to retrieve a {@link Context#FINGERPRINT_SERVICE} on a device that
+         * does not support that feature will now throw a runtime exception.</li>
+         * <li>{@link android.app.Fragment} will stop any active view animations when
+         * the fragment is stopped.</li>
+         * <li>Some compatibility code in Resources that attempts to use the default Theme
+         * the app may be using will be turned off, requiring the app to explicitly request
+         * resources with the right theme.</li>
+         * <li>{@link android.content.ContentResolver#notifyChange ContentResolver.notifyChange} and
+         * {@link android.content.ContentResolver#registerContentObserver
+         * ContentResolver.registerContentObserver}
+         * will throw a SecurityException if the caller does not have permission to access
+         * the provider (or the provider doesn't exit); otherwise the call will be silently
+         * ignored.</li>
+         * <li>{@link android.hardware.camera2.CameraDevice#createCaptureRequest
+         * CameraDevice.createCaptureRequest} will enable
+         * {@link android.hardware.camera2.CaptureRequest#CONTROL_ENABLE_ZSL} by default for
+         * still image capture.</li>
+         * <li>WallpaperManager's {@link android.app.WallpaperManager#getWallpaperFile},
+         * {@link android.app.WallpaperManager#getDrawable},
+         * {@link android.app.WallpaperManager#getFastDrawable},
+         * {@link android.app.WallpaperManager#peekDrawable}, and
+         * {@link android.app.WallpaperManager#peekFastDrawable} will throw an exception
+         * if you can not access the wallpaper.</li>
+         * <li>The behavior of
+         * {@link android.hardware.usb.UsbDeviceConnection#requestWait UsbDeviceConnection.requestWait}
+         * is modified as per the documentation there.</li>
+         * <li>{@link StrictMode.VmPolicy.Builder#detectAll StrictMode.VmPolicy.Builder.detectAll}
+         * will also enable {@link StrictMode.VmPolicy.Builder#detectContentUriWithoutPermission}
+         * and {@link StrictMode.VmPolicy.Builder#detectUntaggedSockets}.</li>
+         * <li>{@link StrictMode.ThreadPolicy.Builder#detectAll StrictMode.ThreadPolicy.Builder.detectAll}
+         * will also enable {@link StrictMode.ThreadPolicy.Builder#detectUnbufferedIo}.</li>
+         * <li>{@link android.provider.DocumentsContract}'s various methods will throw failure
+         * exceptions back to the caller instead of returning null.
+         * <li>{@link View#hasFocusable View.hasFocusable} now includes auto-focusable views.</li>
+         * <li>{@link android.view.SurfaceView} will no longer always change the underlying
+         * Surface object when something about it changes; apps need to look at the current
+         * state of the object to determine which things they are interested in have changed.</li>
+         * <li>{@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY} must be
+         * used for overlay windows, other system overlay window types are not allowed.</li>
+         * <li>{@link android.view.ViewTreeObserver#addOnDrawListener
+         * ViewTreeObserver.addOnDrawListener} will throw an exception if called from within
+         * onDraw.</li>
+         * <li>{@link android.graphics.Canvas#setBitmap Canvas.setBitmap} will no longer preserve
+         * the current matrix and clip stack of the canvas.</li>
+         * <li>{@link android.widget.ListPopupWindow#setHeight ListPopupWindow.setHeight}
+         * will throw an exception if a negative height is supplied.</li>
+         * <li>{@link android.widget.TextView} will use internationalized input for numbers,
+         * dates, and times.</li>
+         * <li>{@link android.widget.Toast} must be used for showing toast windows; the toast
+         * window type can not be directly used.</li>
+         * <li>{@link android.net.wifi.WifiManager#getConnectionInfo WifiManager.getConnectionInfo}
+         * requires that the caller hold the location permission to return BSSID/SSID</li>
+         * <li>{@link android.net.wifi.p2p.WifiP2pManager#requestPeers WifiP2pManager.requestPeers}
+         * requires the caller hold the location permission.</li>
+         * <li>{@link android.R.attr#maxAspectRatio} defaults to 0, meaning there is no restriction
+         * on the app's maximum aspect ratio (so it can be stretched to fill larger screens).</li>
          * <li>{@link android.R.attr#focusable} defaults to a new state ({@code auto}) where it will
          * inherit the value of {@link android.R.attr#clickable} unless explicitly overridden.</li>
          * <li>A default theme-appropriate focus-state highlight will be supplied to all Views
@@ -772,6 +848,15 @@
 
         /**
          * O MR1.
+         *
+         * <p>Applications targeting this or a later release will get these
+         * new changes in behavior:</p>
+         * <ul>
+         * <li>Apps exporting and linking to apk shared libraries must explicitly
+         * enumerate all signing certificates in a consistent order.</li>
+         * <li>{@link android.R.attr#screenOrientation} can not be used to request a fixed
+         * orientation if the associated activity is not fullscreen and opaque.</li>
+         * </ul>
          */
         public static final int O_MR1 = 27;
 
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 36121d4..62bb385 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -20,6 +20,7 @@
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.ExceptionUtils;
 import android.util.Log;
 import android.util.Size;
 import android.util.SizeF;
@@ -1866,7 +1867,14 @@
             if (remoteStackTrace != null) {
                 RemoteException cause = new RemoteException(
                         "Remote stack trace:\n" + remoteStackTrace, null, false, false);
-                e.initCause(cause);
+                try {
+                    Throwable rootCause = ExceptionUtils.getRootCause(e);
+                    if (rootCause != null) {
+                        rootCause.initCause(cause);
+                    }
+                } catch (RuntimeException ex) {
+                    Log.e(TAG, "Cannot set cause " + cause + " for " + e, ex);
+                }
             }
             SneakyThrow.sneakyThrow(e);
         }
diff --git a/core/java/android/os/UEventObserver.java b/core/java/android/os/UEventObserver.java
index 5c80ca6..69a3922 100644
--- a/core/java/android/os/UEventObserver.java
+++ b/core/java/android/os/UEventObserver.java
@@ -108,7 +108,7 @@
      * UEventObserver after this call. Repeated calls have no effect.
      */
     public final void stopObserving() {
-        final UEventThread t = getThread();
+        final UEventThread t = peekThread();
         if (t != null) {
             t.removeObserver(this);
         }
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 2ffc7b0..3b53260 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -112,7 +112,7 @@
      * path belongs to a volume managed by vold, and that path is either
      * external storage data or OBB directory belonging to calling app.
      */
-    int mkdirs(in String callingPkg, in String path) = 34;
+    void mkdirs(in String callingPkg, in String path) = 34;
     /**
      * Determines the type of the encryption password
      * @return PasswordType
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 0b007dd..4796712 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1123,6 +1123,15 @@
         return FileUtils.roundStorageSize(Environment.getDataDirectory().getTotalSpace());
     }
 
+    /** {@hide} */
+    public void mkdirs(File file) {
+        try {
+            mStorageManager.mkdirs(mContext.getOpPackageName(), file.getAbsolutePath());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     /** @removed */
     public @NonNull StorageVolume[] getVolumeList() {
         return getVolumeList(mContext.getUserId(), 0);
diff --git a/core/java/android/provider/SearchIndexablesContract.java b/core/java/android/provider/SearchIndexablesContract.java
index ff8b9dd..adf437c 100644
--- a/core/java/android/provider/SearchIndexablesContract.java
+++ b/core/java/android/provider/SearchIndexablesContract.java
@@ -62,11 +62,25 @@
     public static final String NON_INDEXABLES_KEYS = "non_indexables_key";
 
     /**
+     * Site map pairs data key
+     *
+     * @hide
+     */
+    public static final String SITE_MAP_PAIRS_KEYS = "site_map_pairs";
+
+    /**
      * ContentProvider path for non indexable data keys.
      */
     public static final String NON_INDEXABLES_KEYS_PATH = SETTINGS + "/" + NON_INDEXABLES_KEYS;
 
     /**
+     * ContentProvider path for sitemap keys.
+     *
+     * @hide
+     */
+    public static final String SITE_MAP_PAIRS_PATH = SETTINGS + "/" + SITE_MAP_PAIRS_KEYS;
+
+    /**
      * Indexable xml resources columns.
      */
     public static final String[] INDEXABLES_XML_RES_COLUMNS = new String[] {
@@ -113,6 +127,18 @@
     };
 
     /**
+     * Columns for site map queries.
+     *
+     * @hide
+     */
+    public static final String[] SITE_MAP_COLUMNS = new String[] {
+            SiteMapColumns.PARENT_CLASS,
+            SiteMapColumns.PARENT_TITLE,
+            SiteMapColumns.CHILD_CLASS,
+            SiteMapColumns.CHILD_TITLE,
+    };
+
+    /**
      * Indexable raw data columns indices.
      */
     public static final int COLUMN_INDEX_RAW_RANK = 0;
@@ -169,6 +195,16 @@
     }
 
     /**
+     * @hide
+     */
+    public static final class SiteMapColumns {
+        public static final String PARENT_CLASS = "parent_class";
+        public static final String CHILD_CLASS = "child_class";
+        public static final String PARENT_TITLE = "parent_title";
+        public static final String CHILD_TITLE = "child_title";
+    }
+
+    /**
      * Constants related to a {@link SearchIndexableData}.
      *
      * This is the raw data that is stored into an Index. This is related to
diff --git a/core/java/android/provider/SearchIndexablesProvider.java b/core/java/android/provider/SearchIndexablesProvider.java
index 3120e54..138e77b 100644
--- a/core/java/android/provider/SearchIndexablesProvider.java
+++ b/core/java/android/provider/SearchIndexablesProvider.java
@@ -72,6 +72,7 @@
     private static final int MATCH_RES_CODE = 1;
     private static final int MATCH_RAW_CODE = 2;
     private static final int MATCH_NON_INDEXABLE_KEYS_CODE = 3;
+    private static final int MATCH_SITE_MAP_PAIRS_CODE = 4;
 
     /**
      * Implementation is provided by the parent class.
@@ -87,6 +88,8 @@
                 MATCH_RAW_CODE);
         mMatcher.addURI(mAuthority, SearchIndexablesContract.NON_INDEXABLES_KEYS_PATH,
                 MATCH_NON_INDEXABLE_KEYS_CODE);
+        mMatcher.addURI(mAuthority, SearchIndexablesContract.SITE_MAP_PAIRS_PATH,
+                MATCH_SITE_MAP_PAIRS_CODE);
 
         // Sanity check our setup
         if (!info.exported) {
@@ -112,6 +115,8 @@
                 return queryRawData(null);
             case MATCH_NON_INDEXABLE_KEYS_CODE:
                 return queryNonIndexableKeys(null);
+            case MATCH_SITE_MAP_PAIRS_CODE:
+                return querySiteMapPairs();
             default:
                 throw new UnsupportedOperationException("Unknown Uri " + uri);
         }
@@ -150,6 +155,17 @@
      */
     public abstract Cursor queryNonIndexableKeys(String[] projection);
 
+    /**
+     * Returns a {@link Cursor}, where rows are [parent class, child class] entries to form a site
+     * map. The list of pairs should be as complete as possible.
+     *
+     * @hide
+     */
+    public Cursor querySiteMapPairs() {
+        // By default no-op.
+        return null;
+    }
+
     @Override
     public String getType(Uri uri) {
         switch (mMatcher.match(uri)) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 9945755..729c0ff 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9379,6 +9379,9 @@
         /** {@hide} */
         public static final String
                 BLUETOOTH_PAN_PRIORITY_PREFIX = "bluetooth_pan_priority_";
+        /** {@hide} */
+        public static final String
+                BLUETOOTH_HEARING_AID_PRIORITY_PREFIX = "bluetooth_hearing_aid_priority_";
 
         /**
          * Activity manager specific settings.
@@ -9745,6 +9748,14 @@
         }
 
         /**
+         * Get the key that retrieves a bluetooth hearing aid priority.
+         * @hide
+         */
+        public static final String getBluetoothHearingAidPriorityKey(String address) {
+            return BLUETOOTH_HEARING_AID_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
+        }
+
+        /**
          * Get the key that retrieves a bluetooth map priority.
          * @hide
          */
diff --git a/core/java/android/service/autofill/ISaveCallback.aidl b/core/java/android/service/autofill/ISaveCallback.aidl
index e260c73..a9364fe 100644
--- a/core/java/android/service/autofill/ISaveCallback.aidl
+++ b/core/java/android/service/autofill/ISaveCallback.aidl
@@ -16,12 +16,14 @@
 
 package android.service.autofill;
 
+import android.content.IntentSender;
+
 /**
  * Interface to receive the result of a save request.
  *
  * @hide
  */
 interface ISaveCallback {
-    void onSuccess();
+    void onSuccess(in IntentSender intentSender);
     void onFailure(CharSequence message);
 }
diff --git a/core/java/android/service/autofill/NegationValidator.java b/core/java/android/service/autofill/NegationValidator.java
new file mode 100644
index 0000000..a963f9f
--- /dev/null
+++ b/core/java/android/service/autofill/NegationValidator.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+import static android.view.autofill.Helper.sDebug;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Validator used to implement a {@code NOT} logical operation.
+ *
+ * @hide
+ */
+final class NegationValidator extends InternalValidator {
+    @NonNull private final InternalValidator mValidator;
+
+    NegationValidator(@NonNull InternalValidator validator) {
+        mValidator = Preconditions.checkNotNull(validator);
+    }
+
+    @Override
+    public boolean isValid(@NonNull ValueFinder finder) {
+        return !mValidator.isValid(finder);
+    }
+
+    /////////////////////////////////////
+    // Object "contract" methods. //
+    /////////////////////////////////////
+    @Override
+    public String toString() {
+        if (!sDebug) return super.toString();
+
+        return "NegationValidator: [validator=" + mValidator + "]";
+    }
+
+    /////////////////////////////////////
+    // Parcelable "contract" methods. //
+    /////////////////////////////////////
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeParcelable(mValidator, flags);
+    }
+
+    public static final Parcelable.Creator<NegationValidator> CREATOR =
+            new Parcelable.Creator<NegationValidator>() {
+        @Override
+        public NegationValidator createFromParcel(Parcel parcel) {
+            return new NegationValidator(parcel.readParcelable(null));
+        }
+
+        @Override
+        public NegationValidator[] newArray(int size) {
+            return new NegationValidator[size];
+        }
+    };
+}
diff --git a/core/java/android/service/autofill/SaveCallback.java b/core/java/android/service/autofill/SaveCallback.java
index 7207f1d..855981a 100644
--- a/core/java/android/service/autofill/SaveCallback.java
+++ b/core/java/android/service/autofill/SaveCallback.java
@@ -16,9 +16,14 @@
 
 package android.service.autofill;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.Activity;
+import android.content.IntentSender;
 import android.os.RemoteException;
 
+import com.android.internal.util.Preconditions;
+
 /**
  * Handles save requests from the {@link AutofillService} into the {@link Activity} being
  * autofilled.
@@ -36,18 +41,33 @@
      * Notifies the Android System that an
      * {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)} was successfully handled
      * by the service.
-     *
-     * <p>If the service could not handle the request right away&mdash;for example, because it must
-     * launch an activity asking the user to authenticate first or because the network is
-     * down&mdash;it should still call {@link #onSuccess()}.
-     *
-     * @throws RuntimeException if an error occurred while calling the Android System.
      */
     public void onSuccess() {
+        onSuccessInternal(null);
+    }
+
+    /**
+     * Notifies the Android System that an
+     * {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)} was successfully handled
+     * by the service.
+     *
+     * <p>This method is useful when the service requires extra work&mdash;for example, launching an
+     * activity asking the user to authenticate first &mdash;before it can process the request,
+     * as the intent will be launched from the context of the activity being autofilled and hence
+     * will be part of that activity's stack.
+     *
+     * @param intentSender intent that will be launched from the context of activity being
+     * autofilled.
+     */
+    public void onSuccess(@NonNull IntentSender intentSender) {
+        onSuccessInternal(Preconditions.checkNotNull(intentSender));
+    }
+
+    private void onSuccessInternal(@Nullable IntentSender intentSender) {
         assertNotCalled();
         mCalled = true;
         try {
-            mCallback.onSuccess();
+            mCallback.onSuccess(intentSender);
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
         }
@@ -63,11 +83,10 @@
      * the {@link SaveRequest} and call {@link #onSuccess()} instead.
      *
      * <p><b>Note:</b> The Android System displays an UI with the supplied error message; if
-     * you prefer to show your own message, call {@link #onSuccess()} instead.
+     * you prefer to show your own message, call {@link #onSuccess()} or
+     * {@link #onSuccess(IntentSender)} instead.
      *
      * @param message error message to be displayed to the user.
-     *
-     * @throws RuntimeException if an error occurred while calling the Android System.
      */
     public void onFailure(CharSequence message) {
         assertNotCalled();
diff --git a/core/java/android/service/autofill/Validators.java b/core/java/android/service/autofill/Validators.java
index 51b503c..1c83868 100644
--- a/core/java/android/service/autofill/Validators.java
+++ b/core/java/android/service/autofill/Validators.java
@@ -52,6 +52,19 @@
         return new OptionalValidators(getInternalValidators(validators));
     }
 
+    /**
+     * Creates a validator that is valid only if {@code validator} is not.
+     *
+     * @throws IllegalArgumentException if {@code validator} is an instance of a class that is not
+     * provided by the Android System.
+     */
+    @NonNull
+    public static Validator not(@NonNull Validator validator) {
+        Preconditions.checkArgument(validator instanceof InternalValidator,
+                "validator not provided by Android System: " + validator);
+        return new NegationValidator((InternalValidator) validator);
+    }
+
     private static InternalValidator[] getInternalValidators(Validator[] validators) {
         Preconditions.checkArrayElementsNotNull(validators, "validators");
 
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 1c6275f..dd0ae33 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -889,7 +889,8 @@
                             mFinalStableInsets.set(mDispatchedStableInsets);
                             WindowInsets insets = new WindowInsets(mFinalSystemInsets,
                                     null, mFinalStableInsets,
-                                    getResources().getConfiguration().isScreenRound(), false);
+                                    getResources().getConfiguration().isScreenRound(), false,
+                                    null /* displayCutout */);
                             if (DEBUG) {
                                 Log.v(TAG, "dispatching insets=" + insets);
                             }
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 6a44cdb..9673be0 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -20,6 +20,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.RequiresPermission;
+import android.app.KeyguardManager;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -209,8 +210,8 @@
      * </p>
      *
      * @see DisplayManager#VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD
-     * @see WindowManagerPolicy#isKeyguardSecure(int)
-     * @see WindowManagerPolicy#isKeyguardTrustedLw()
+     * @see KeyguardManager#isDeviceSecure()
+     * @see KeyguardManager#isDeviceLocked()
      * @see #getFlags
      * @hide
      */
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
new file mode 100644
index 0000000..19cd42e
--- /dev/null
+++ b/core/java/android/view/DisplayCutout.java
@@ -0,0 +1,408 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
+import android.annotation.NonNull;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a part of the display that is not functional for displaying content.
+ *
+ * <p>{@code DisplayCutout} is immutable.
+ *
+ * @hide will become API
+ */
+public final class DisplayCutout {
+
+    private static final Rect ZERO_RECT = new Rect(0, 0, 0, 0);
+    private static final ArrayList<Point> EMPTY_LIST = new ArrayList<>();
+
+    /**
+     * An instance where {@link #hasCutout()} returns {@code false}.
+     *
+     * @hide
+     */
+    public static final DisplayCutout NO_CUTOUT =
+            new DisplayCutout(ZERO_RECT, ZERO_RECT, EMPTY_LIST);
+
+    private final Rect mSafeInsets;
+    private final Rect mBoundingRect;
+    private final List<Point> mBoundingPolygon;
+
+    /**
+     * Creates a DisplayCutout instance.
+     *
+     * NOTE: the Rects passed into this instance are not copied and MUST remain unchanged.
+     *
+     * @hide
+     */
+    @VisibleForTesting
+    public DisplayCutout(Rect safeInsets, Rect boundingRect, List<Point> boundingPolygon) {
+        mSafeInsets = safeInsets != null ? safeInsets : ZERO_RECT;
+        mBoundingRect = boundingRect != null ? boundingRect : ZERO_RECT;
+        mBoundingPolygon = boundingPolygon != null ? boundingPolygon : EMPTY_LIST;
+    }
+
+    /**
+     * Returns whether there is a cutout.
+     *
+     * If false, the safe insets will all return zero, and the bounding box or polygon will be
+     * empty or outside the content view.
+     *
+     * @return {@code true} if there is a cutout, {@code false} otherwise
+     */
+    public boolean hasCutout() {
+        return !mSafeInsets.equals(ZERO_RECT);
+    }
+
+    /** Returns the inset from the top which avoids the display cutout. */
+    public int getSafeInsetTop() {
+        return mSafeInsets.top;
+    }
+
+    /** Returns the inset from the bottom which avoids the display cutout. */
+    public int getSafeInsetBottom() {
+        return mSafeInsets.bottom;
+    }
+
+    /** Returns the inset from the left which avoids the display cutout. */
+    public int getSafeInsetLeft() {
+        return mSafeInsets.left;
+    }
+
+    /** Returns the inset from the right which avoids the display cutout. */
+    public int getSafeInsetRight() {
+        return mSafeInsets.right;
+    }
+
+    /**
+     * Obtains the safe insets in a rect.
+     *
+     * @param out a rect which is set to the safe insets.
+     * @hide
+     */
+    public void getSafeInsets(@NonNull Rect out) {
+        out.set(mSafeInsets);
+    }
+
+    /**
+     * Obtains the bounding rect of the cutout.
+     *
+     * @param outRect is filled with the bounding rect of the cutout. Coordinates are relative
+     *         to the top-left corner of the content view.
+     */
+    public void getBoundingRect(@NonNull Rect outRect) {
+        outRect.set(mBoundingRect);
+    }
+
+    /**
+     * Obtains the bounding polygon of the cutout.
+     *
+     * @param outPolygon is filled with a list of points representing the corners of a convex
+     *         polygon which covers the cutout. Coordinates are relative to the
+     *         top-left corner of the content view.
+     */
+    public void getBoundingPolygon(List<Point> outPolygon) {
+        outPolygon.clear();
+        for (int i = 0; i < mBoundingPolygon.size(); i++) {
+            outPolygon.add(new Point(mBoundingPolygon.get(i)));
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        int result = mSafeInsets.hashCode();
+        result = result * 31 + mBoundingRect.hashCode();
+        result = result * 31 + mBoundingPolygon.hashCode();
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+        if (o instanceof DisplayCutout) {
+            DisplayCutout c = (DisplayCutout) o;
+            return mSafeInsets.equals(c.mSafeInsets)
+                    && mBoundingRect.equals(c.mBoundingRect)
+                    && mBoundingPolygon.equals(c.mBoundingPolygon);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return "DisplayCutout{insets=" + mSafeInsets
+                + " bounding=" + mBoundingRect
+                + "}";
+    }
+
+    /**
+     * Insets the reference frame of the cutout in the given directions.
+     *
+     * @return a copy of this instance which has been inset
+     * @hide
+     */
+    public DisplayCutout inset(int insetLeft, int insetTop, int insetRight, int insetBottom) {
+        if (mBoundingRect.isEmpty()
+                || insetLeft == 0 && insetTop == 0 && insetRight == 0 && insetBottom == 0) {
+            return this;
+        }
+
+        Rect safeInsets = new Rect(mSafeInsets);
+        Rect boundingRect = new Rect(mBoundingRect);
+        ArrayList<Point> boundingPolygon = new ArrayList<>();
+        getBoundingPolygon(boundingPolygon);
+
+        // Note: it's not really well defined what happens when the inset is negative, because we
+        // don't know if the safe inset needs to expand in general.
+        if (insetTop > 0 || safeInsets.top > 0) {
+            safeInsets.top = atLeastZero(safeInsets.top - insetTop);
+        }
+        if (insetBottom > 0 || safeInsets.bottom > 0) {
+            safeInsets.bottom = atLeastZero(safeInsets.bottom - insetBottom);
+        }
+        if (insetLeft > 0 || safeInsets.left > 0) {
+            safeInsets.left = atLeastZero(safeInsets.left - insetLeft);
+        }
+        if (insetRight > 0 || safeInsets.right > 0) {
+            safeInsets.right = atLeastZero(safeInsets.right - insetRight);
+        }
+
+        boundingRect.offset(-insetLeft, -insetTop);
+        offset(boundingPolygon, -insetLeft, -insetTop);
+
+        return new DisplayCutout(safeInsets, boundingRect, boundingPolygon);
+    }
+
+    /**
+     * Calculates the safe insets relative to the given reference frame.
+     *
+     * @return a copy of this instance with the safe insets calculated
+     * @hide
+     */
+    public DisplayCutout calculateRelativeTo(Rect frame) {
+        if (mBoundingRect.isEmpty() || !Rect.intersects(frame, mBoundingRect)) {
+            return NO_CUTOUT;
+        }
+
+        Rect boundingRect = new Rect(mBoundingRect);
+        ArrayList<Point> boundingPolygon = new ArrayList<>();
+        getBoundingPolygon(boundingPolygon);
+
+        return DisplayCutout.calculateRelativeTo(frame, boundingRect, boundingPolygon);
+    }
+
+    private static DisplayCutout calculateRelativeTo(Rect frame, Rect boundingRect,
+            ArrayList<Point> boundingPolygon) {
+        Rect safeRect = new Rect();
+        int bestArea = 0;
+        int bestVariant = 0;
+        for (int variant = ROTATION_0; variant <= ROTATION_270; variant++) {
+            int area = calculateInsetVariantArea(frame, boundingRect, variant, safeRect);
+            if (bestArea < area) {
+                bestArea = area;
+                bestVariant = variant;
+            }
+        }
+        calculateInsetVariantArea(frame, boundingRect, bestVariant, safeRect);
+        if (safeRect.isEmpty()) {
+            // The entire frame overlaps with the cutout.
+            safeRect.set(0, frame.height(), 0, 0);
+        } else {
+            // Convert safeRect to insets relative to frame. We're reusing the rect here to avoid
+            // an allocation.
+            safeRect.set(
+                    Math.max(0, safeRect.left - frame.left),
+                    Math.max(0, safeRect.top - frame.top),
+                    Math.max(0, frame.right - safeRect.right),
+                    Math.max(0, frame.bottom - safeRect.bottom));
+        }
+
+        boundingRect.offset(-frame.left, -frame.top);
+        offset(boundingPolygon, -frame.left, -frame.top);
+
+        return new DisplayCutout(safeRect, boundingRect, boundingPolygon);
+    }
+
+    private static int calculateInsetVariantArea(Rect frame, Rect boundingRect, int variant,
+            Rect outSafeRect) {
+        switch (variant) {
+            case ROTATION_0:
+                outSafeRect.set(frame.left, frame.top, frame.right, boundingRect.top);
+                break;
+            case ROTATION_90:
+                outSafeRect.set(frame.left, frame.top, boundingRect.left, frame.bottom);
+                break;
+            case ROTATION_180:
+                outSafeRect.set(frame.left, boundingRect.bottom, frame.right, frame.bottom);
+                break;
+            case ROTATION_270:
+                outSafeRect.set(boundingRect.right, frame.top, frame.right, frame.bottom);
+                break;
+        }
+
+        return outSafeRect.isEmpty() ? 0 : outSafeRect.width() * outSafeRect.height();
+    }
+
+    private static int atLeastZero(int value) {
+        return value < 0 ? 0 : value;
+    }
+
+    private static void offset(ArrayList<Point> points, int dx, int dy) {
+        for (int i = 0; i < points.size(); i++) {
+            points.get(i).offset(dx, dy);
+        }
+    }
+
+    /**
+     * Creates an instance from a bounding polygon.
+     *
+     * @hide
+     */
+    public static DisplayCutout fromBoundingPolygon(List<Point> points) {
+        Rect boundingRect = new Rect(Integer.MAX_VALUE, Integer.MAX_VALUE,
+                Integer.MIN_VALUE, Integer.MIN_VALUE);
+        ArrayList<Point> boundingPolygon = new ArrayList<>();
+
+        for (int i = 0; i < points.size(); i++) {
+            Point point = points.get(i);
+            boundingRect.left = Math.min(boundingRect.left, point.x);
+            boundingRect.right = Math.max(boundingRect.right, point.x);
+            boundingRect.top = Math.min(boundingRect.top, point.y);
+            boundingRect.bottom = Math.max(boundingRect.bottom, point.y);
+            boundingPolygon.add(new Point(point));
+        }
+
+        return new DisplayCutout(ZERO_RECT, boundingRect, boundingPolygon);
+    }
+
+    /**
+     * Helper class for passing {@link DisplayCutout} through binder.
+     *
+     * Needed, because {@code readFromParcel} cannot be used with immutable classes.
+     *
+     * @hide
+     */
+    public static final class ParcelableWrapper implements Parcelable {
+
+        private DisplayCutout mInner;
+
+        public ParcelableWrapper() {
+            this(NO_CUTOUT);
+        }
+
+        public ParcelableWrapper(DisplayCutout cutout) {
+            mInner = cutout;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            if (mInner == NO_CUTOUT) {
+                out.writeInt(0);
+            } else {
+                out.writeInt(1);
+                out.writeTypedObject(mInner.mSafeInsets, flags);
+                out.writeTypedObject(mInner.mBoundingRect, flags);
+                out.writeTypedList(mInner.mBoundingPolygon, flags);
+            }
+        }
+
+        /**
+         * Similar to {@link Creator#createFromParcel(Parcel)}, but reads into an existing
+         * instance.
+         *
+         * Needed for AIDL out parameters.
+         */
+        public void readFromParcel(Parcel in) {
+            mInner = readCutout(in);
+        }
+
+        public static final Creator<ParcelableWrapper> CREATOR = new Creator<ParcelableWrapper>() {
+            @Override
+            public ParcelableWrapper createFromParcel(Parcel in) {
+                return new ParcelableWrapper(readCutout(in));
+            }
+
+            @Override
+            public ParcelableWrapper[] newArray(int size) {
+                return new ParcelableWrapper[size];
+            }
+        };
+
+        private static DisplayCutout readCutout(Parcel in) {
+            if (in.readInt() == 0) {
+                return NO_CUTOUT;
+            }
+
+            ArrayList<Point> boundingPolygon = new ArrayList<>();
+
+            Rect safeInsets = in.readTypedObject(Rect.CREATOR);
+            Rect boundingRect = in.readTypedObject(Rect.CREATOR);
+            in.readTypedList(boundingPolygon, Point.CREATOR);
+
+            return new DisplayCutout(safeInsets, boundingRect, boundingPolygon);
+        }
+
+        public DisplayCutout get() {
+            return mInner;
+        }
+
+        public void set(ParcelableWrapper cutout) {
+            mInner = cutout.get();
+        }
+
+        public void set(DisplayCutout cutout) {
+            mInner = cutout;
+        }
+
+        @Override
+        public int hashCode() {
+            return mInner.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            return o instanceof ParcelableWrapper
+                    && mInner.equals(((ParcelableWrapper) o).mInner);
+        }
+
+        @Override
+        public String toString() {
+            return String.valueOf(mInner);
+        }
+    }
+}
diff --git a/core/java/android/view/InputFilter.java b/core/java/android/view/InputFilter.java
index d0dab40..0ab4dc0 100644
--- a/core/java/android/view/InputFilter.java
+++ b/core/java/android/view/InputFilter.java
@@ -72,21 +72,21 @@
  * </p><p>
  * The early policy interception decides whether an input event should be delivered
  * to applications or dropped.  The policy indicates its decision by setting the
- * {@link WindowManagerPolicy#FLAG_PASS_TO_USER} policy flag.  The input filter may
+ * {@link WindowManagerPolicyConstants#FLAG_PASS_TO_USER} policy flag.  The input filter may
  * sometimes receive events that do not have this flag set.  It should take note of
  * the fact that the policy intends to drop the event, clean up its state, and
  * then send appropriate cancellation events to the dispatcher if needed.
  * </p><p>
  * For example, suppose the input filter is processing a gesture and one of the touch events
- * it receives does not have the {@link WindowManagerPolicy#FLAG_PASS_TO_USER} flag set.
+ * it receives does not have the {@link WindowManagerPolicyConstants#FLAG_PASS_TO_USER} flag set.
  * The input filter should clear its internal state about the gesture and then send key or
  * motion events to the dispatcher to cancel any keys or pointers that are down.
  * </p><p>
  * Corollary: Events that get sent to the dispatcher should usually include the
- * {@link WindowManagerPolicy#FLAG_PASS_TO_USER} flag.  Otherwise, they will be dropped!
+ * {@link WindowManagerPolicyConstants#FLAG_PASS_TO_USER} flag.  Otherwise, they will be dropped!
  * </p><p>
  * It may be prudent to disable automatic key repeating for synthetic key events
- * by setting the {@link WindowManagerPolicy#FLAG_DISABLE_KEY_REPEAT} policy flag.
+ * by setting the {@link WindowManagerPolicyConstants#FLAG_DISABLE_KEY_REPEAT} policy flag.
  * </p>
  *
  * @hide
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 4eab496e..578679b 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -17,9 +17,9 @@
 package android.view;
 
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
-import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_OVERLAY_SUBLAYER;
-import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_SUBLAYER;
-import static android.view.WindowManagerPolicy.APPLICATION_PANEL_SUBLAYER;
+import static android.view.WindowManagerPolicyConstants.APPLICATION_MEDIA_OVERLAY_SUBLAYER;
+import static android.view.WindowManagerPolicyConstants.APPLICATION_MEDIA_SUBLAYER;
+import static android.view.WindowManagerPolicyConstants.APPLICATION_PANEL_SUBLAYER;
 
 import android.content.Context;
 import android.content.res.CompatibilityInfo.Translator;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e36a298..345e300 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2929,6 +2929,7 @@
      *        1                          PFLAG3_TEMPORARY_DETACH
      *       1                           PFLAG3_NO_REVEAL_ON_FOCUS
      *      1                            PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT
+     *     1                             PFLAG3_SCREEN_READER_FOCUSABLE
      * |-------|-------|-------|-------|
      */
 
@@ -3209,6 +3210,12 @@
      */
     static final int PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT = 0x8000000;
 
+    /**
+     * Works like focusable for screen readers, but without the side effects on input focus.
+     * @see #setScreenReaderFocusable(boolean)
+     */
+    private static final int PFLAG3_SCREEN_READER_FOCUSABLE = 0x10000000;
+
     /* End of masks for mPrivateFlags3 */
 
     /**
@@ -5344,6 +5351,11 @@
                         setDefaultFocusHighlightEnabled(a.getBoolean(attr, true));
                     }
                     break;
+                case R.styleable.View_screenReaderFocusable:
+                    if (a.peekValue(attr) != null) {
+                        setScreenReaderFocusable(a.getBoolean(attr, false));
+                    }
+                    break;
             }
         }
 
@@ -8394,6 +8406,7 @@
         info.setEnabled(isEnabled());
         info.setClickable(isClickable());
         info.setFocusable(isFocusable());
+        info.setScreenReaderFocusable(isScreenReaderFocusable());
         info.setFocused(isFocused());
         info.setAccessibilityFocused(isAccessibilityFocused());
         info.setSelected(isSelected());
@@ -10350,6 +10363,45 @@
     }
 
     /**
+     * Returns whether the view should be treated as a focusable unit by screen reader
+     * accessibility tools.
+     * @see #setScreenReaderFocusable(boolean)
+     *
+     * @return Whether the view should be treated as a focusable unit by screen reader.
+     */
+    public boolean isScreenReaderFocusable() {
+        return (mPrivateFlags3 & PFLAG3_SCREEN_READER_FOCUSABLE) != 0;
+    }
+
+    /**
+     * When screen readers (one type of accessibility tool) decide what should be read to the
+     * user, they typically look for input focusable ({@link #isFocusable()}) parents of
+     * non-focusable text items, and read those focusable parents and their non-focusable children
+     * as a unit. In some situations, this behavior is desirable for views that should not take
+     * input focus. Setting an item to be screen reader focusable requests that the view be
+     * treated as a unit by screen readers without any effect on input focusability. The default
+     * value of {@code false} lets screen readers use other signals, like focusable, to determine
+     * how to group items.
+     *
+     * @param screenReaderFocusable Whether the view should be treated as a unit by screen reader
+     *                              accessibility tools.
+     */
+    public void setScreenReaderFocusable(boolean screenReaderFocusable) {
+        int pflags3 = mPrivateFlags3;
+        if (screenReaderFocusable) {
+            pflags3 |= PFLAG3_SCREEN_READER_FOCUSABLE;
+        } else {
+            pflags3 &= ~PFLAG3_SCREEN_READER_FOCUSABLE;
+        }
+
+        if (pflags3 != mPrivateFlags3) {
+            mPrivateFlags3 = pflags3;
+            notifyViewAccessibilityStateChangedIfNeeded(
+                    AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+        }
+    }
+
+    /**
      * Find the nearest view in the specified direction that can take focus.
      * This does not actually give focus to that view.
      *
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 929beae..122df93 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2591,7 +2591,7 @@
             boolean alreadyDispatchedToNewTouchTarget = false;
             if (!canceled && !intercepted) {
 
-                // If the event is targeting accessiiblity focus we give it to the
+                // If the event is targeting accessibility focus we give it to the
                 // view that has accessibility focus and if it does not handle it
                 // we clear the flag and dispatch the event to all children as usual.
                 // We are looking up the accessibility focused host to avoid keeping
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e9509b7..1c9d863 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1563,7 +1563,7 @@
             mLastWindowInsets = new WindowInsets(contentInsets,
                     null /* windowDecorInsets */, stableInsets,
                     mContext.getResources().getConfiguration().isScreenRound(),
-                    mAttachInfo.mAlwaysConsumeNavBar);
+                    mAttachInfo.mAlwaysConsumeNavBar, null /* displayCutout */);
         }
         return mLastWindowInsets;
     }
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 750931a..df124ac 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -17,6 +17,7 @@
 
 package android.view;
 
+import android.annotation.NonNull;
 import android.graphics.Rect;
 
 /**
@@ -36,6 +37,7 @@
     private Rect mStableInsets;
     private Rect mTempRect;
     private boolean mIsRound;
+    private DisplayCutout mDisplayCutout;
 
     /**
      * In multi-window we force show the navigation bar. Because we don't want that the surface size
@@ -47,6 +49,7 @@
     private boolean mSystemWindowInsetsConsumed = false;
     private boolean mWindowDecorInsetsConsumed = false;
     private boolean mStableInsetsConsumed = false;
+    private boolean mCutoutConsumed = false;
 
     private static final Rect EMPTY_RECT = new Rect(0, 0, 0, 0);
 
@@ -59,12 +62,12 @@
     public static final WindowInsets CONSUMED;
 
     static {
-        CONSUMED = new WindowInsets(null, null, null, false, false);
+        CONSUMED = new WindowInsets(null, null, null, false, false, null);
     }
 
     /** @hide */
     public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets, Rect stableInsets,
-            boolean isRound, boolean alwaysConsumeNavBar) {
+            boolean isRound, boolean alwaysConsumeNavBar, DisplayCutout displayCutout) {
         mSystemWindowInsetsConsumed = systemWindowInsets == null;
         mSystemWindowInsets = mSystemWindowInsetsConsumed ? EMPTY_RECT : systemWindowInsets;
 
@@ -76,6 +79,9 @@
 
         mIsRound = isRound;
         mAlwaysConsumeNavBar = alwaysConsumeNavBar;
+
+        mCutoutConsumed = displayCutout == null;
+        mDisplayCutout = mCutoutConsumed ? DisplayCutout.NO_CUTOUT : displayCutout;
     }
 
     /**
@@ -92,11 +98,13 @@
         mStableInsetsConsumed = src.mStableInsetsConsumed;
         mIsRound = src.mIsRound;
         mAlwaysConsumeNavBar = src.mAlwaysConsumeNavBar;
+        mDisplayCutout = src.mDisplayCutout;
+        mCutoutConsumed = src.mCutoutConsumed;
     }
 
     /** @hide */
     public WindowInsets(Rect systemWindowInsets) {
-        this(systemWindowInsets, null, null, false, false);
+        this(systemWindowInsets, null, null, false, false, null);
     }
 
     /**
@@ -260,10 +268,35 @@
      * @return true if any inset values are nonzero
      */
     public boolean hasInsets() {
-        return hasSystemWindowInsets() || hasWindowDecorInsets() || hasStableInsets();
+        return hasSystemWindowInsets() || hasWindowDecorInsets() || hasStableInsets()
+                || mDisplayCutout.hasCutout();
     }
 
     /**
+     * @return the display cutout
+     * @see DisplayCutout
+     * @hide pending API
+     */
+    @NonNull
+    public DisplayCutout getDisplayCutout() {
+        return mDisplayCutout;
+    }
+
+    /**
+     * Returns a copy of this WindowInsets with the cutout fully consumed.
+     *
+     * @return A modified copy of this WindowInsets
+     * @hide pending API
+     */
+    public WindowInsets consumeCutout() {
+        final WindowInsets result = new WindowInsets(this);
+        result.mDisplayCutout = DisplayCutout.NO_CUTOUT;
+        result.mCutoutConsumed = true;
+        return result;
+    }
+
+
+    /**
      * Check if these insets have been fully consumed.
      *
      * <p>Insets are considered "consumed" if the applicable <code>consume*</code> methods
@@ -277,7 +310,8 @@
      * @return true if the insets have been fully consumed.
      */
     public boolean isConsumed() {
-        return mSystemWindowInsetsConsumed && mWindowDecorInsetsConsumed && mStableInsetsConsumed;
+        return mSystemWindowInsetsConsumed && mWindowDecorInsetsConsumed && mStableInsetsConsumed
+                && mCutoutConsumed;
     }
 
     /**
@@ -495,7 +529,9 @@
     public String toString() {
         return "WindowInsets{systemWindowInsets=" + mSystemWindowInsets
                 + " windowDecorInsets=" + mWindowDecorInsets
-                + " stableInsets=" + mStableInsets +
-                (isRound() ? " round}" : "}");
+                + " stableInsets=" + mStableInsets
+                + (mDisplayCutout.hasCutout() ? " cutout=" + mDisplayCutout : "")
+                + (isRound() ? " round" : "")
+                + "}";
     }
 }
diff --git a/core/java/android/view/WindowManagerPolicyConstants.java b/core/java/android/view/WindowManagerPolicyConstants.java
new file mode 100644
index 0000000..21943bd
--- /dev/null
+++ b/core/java/android/view/WindowManagerPolicyConstants.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import android.annotation.SystemApi;
+
+/**
+ * Constants for interfacing with WindowManagerService and WindowManagerPolicyInternal.
+ * @hide
+ */
+public interface WindowManagerPolicyConstants {
+    // Policy flags.  These flags are also defined in frameworks/base/include/ui/Input.h.
+    int FLAG_WAKE = 0x00000001;
+    int FLAG_VIRTUAL = 0x00000002;
+
+    int FLAG_INJECTED = 0x01000000;
+    int FLAG_TRUSTED = 0x02000000;
+    int FLAG_FILTERED = 0x04000000;
+    int FLAG_DISABLE_KEY_REPEAT = 0x08000000;
+
+    int FLAG_INTERACTIVE = 0x20000000;
+    int FLAG_PASS_TO_USER = 0x40000000;
+
+    // Flags for IActivityManager.keyguardGoingAway()
+    int KEYGUARD_GOING_AWAY_FLAG_TO_SHADE = 1 << 0;
+    int KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS = 1 << 1;
+    int KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER = 1 << 2;
+
+    // Flags used for indicating whether the internal and/or external input devices
+    // of some type are available.
+    int PRESENCE_INTERNAL = 1 << 0;
+    int PRESENCE_EXTERNAL = 1 << 1;
+
+    /**
+     * Sticky broadcast of the current HDMI plugged state.
+     */
+    String ACTION_HDMI_PLUGGED = "android.intent.action.HDMI_PLUGGED";
+
+    /**
+     * Extra in {@link #ACTION_HDMI_PLUGGED} indicating the state: true if
+     * plugged in to HDMI, false if not.
+     */
+    String EXTRA_HDMI_PLUGGED_STATE = "state";
+
+    /**
+     * Set to {@code true} when intent was invoked from pressing the home key.
+     * @hide
+     */
+    @SystemApi
+    String EXTRA_FROM_HOME_KEY = "android.intent.extra.FROM_HOME_KEY";
+
+    // TODO: move this to a more appropriate place.
+    interface PointerEventListener {
+        /**
+         * 1. onPointerEvent will be called on the service.UiThread.
+         * 2. motionEvent will be recycled after onPointerEvent returns so if it is needed later a
+         * copy() must be made and the copy must be recycled.
+         **/
+        void onPointerEvent(MotionEvent motionEvent);
+
+        /**
+         * @see #onPointerEvent(MotionEvent)
+         **/
+        default void onPointerEvent(MotionEvent motionEvent, int displayId) {
+            if (displayId == DEFAULT_DISPLAY) {
+                onPointerEvent(motionEvent);
+            }
+        }
+    }
+
+    /** Screen turned off because of a device admin */
+    int OFF_BECAUSE_OF_ADMIN = 1;
+    /** Screen turned off because of power button */
+    int OFF_BECAUSE_OF_USER = 2;
+    /** Screen turned off because of timeout */
+    int OFF_BECAUSE_OF_TIMEOUT = 3;
+
+    int APPLICATION_LAYER = 2;
+    int APPLICATION_MEDIA_SUBLAYER = -2;
+    int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
+    int APPLICATION_PANEL_SUBLAYER = 1;
+    int APPLICATION_SUB_PANEL_SUBLAYER = 2;
+    int APPLICATION_ABOVE_SUB_PANEL_SUBLAYER = 3;
+
+    /**
+     * Convert the off reason to a human readable format.
+     */
+    static String offReasonToString(int why) {
+        switch (why) {
+            case OFF_BECAUSE_OF_ADMIN:
+                return "OFF_BECAUSE_OF_ADMIN";
+            case OFF_BECAUSE_OF_USER:
+                return "OFF_BECAUSE_OF_USER";
+            case OFF_BECAUSE_OF_TIMEOUT:
+                return "OFF_BECAUSE_OF_TIMEOUT";
+            default:
+                return Integer.toString(why);
+        }
+    }
+}
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 9bdd3ff..faea920 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -635,6 +635,8 @@
 
     private static final int BOOLEAN_PROPERTY_IMPORTANCE = 0x0040000;
 
+    private static final int BOOLEAN_PROPERTY_SCREEN_READER_FOCUSABLE = 0x0080000;
+
     private static final int BOOLEAN_PROPERTY_IS_SHOWING_HINT = 0x0100000;
 
     /**
@@ -2321,6 +2323,37 @@
     }
 
     /**
+     * Returns whether the node is explicitly marked as a focusable unit by a screen reader. Note
+     * that {@code false} indicates that it is not explicitly marked, not that the node is not
+     * a focusable unit. Screen readers should generally used other signals, such as
+     * {@link #isFocusable()}, or the presence of text in a node, to determine what should receive
+     * focus.
+     *
+     * @return {@code true} if the node is specifically marked as a focusable unit for screen
+     *         readers, {@code false} otherwise.
+     *
+     * @see View#isScreenReaderFocusable()
+     */
+    public boolean isScreenReaderFocusable() {
+        return getBooleanProperty(BOOLEAN_PROPERTY_SCREEN_READER_FOCUSABLE);
+    }
+
+    /**
+     * Sets whether the node should be considered a focusable unit by a screen reader.
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     *
+     * @param screenReaderFocusable {@code true} if the node is a focusable unit for screen readers,
+     *                              {@code false} otherwise.
+     */
+    public void setScreenReaderFocusable(boolean screenReaderFocusable) {
+        setBooleanProperty(BOOLEAN_PROPERTY_SCREEN_READER_FOCUSABLE, screenReaderFocusable);
+    }
+
+    /**
      * Returns whether the node's text represents a hint for the user to enter text. It should only
      * be {@code true} if the node has editable text.
      *
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index d0c2d86..05cba1e 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -119,7 +119,6 @@
 import com.android.internal.util.GrowingArrayUtils;
 import com.android.internal.util.Preconditions;
 import com.android.internal.widget.EditableInputConnection;
-import com.android.internal.widget.Magnifier;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
diff --git a/core/java/com/android/internal/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
similarity index 85%
rename from core/java/com/android/internal/widget/Magnifier.java
rename to core/java/android/widget/Magnifier.java
index f79a7f5..bd48f45 100644
--- a/core/java/com/android/internal/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -11,10 +11,10 @@
  * 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
+ * limitations under the License.
  */
 
-package com.android.internal.widget;
+package android.widget;
 
 import android.annotation.FloatRange;
 import android.annotation.NonNull;
@@ -32,15 +32,13 @@
 import android.view.Surface;
 import android.view.SurfaceView;
 import android.view.View;
-import android.widget.ImageView;
-import android.widget.PopupWindow;
 
-import com.android.internal.R;
 import com.android.internal.util.Preconditions;
 
 /**
- * Android magnifier widget. Can be used by any view which is attached to window.
+ * Android magnifier widget. Can be used by any view which is attached to a window.
  */
+@UiThread
 public final class Magnifier {
     // Use this to specify that a previous configuration value does not exist.
     private static final int NONEXISTENT_PREVIOUS_CONFIG_VALUE = -1;
@@ -75,16 +73,20 @@
      *
      * @param view the view for which this magnifier is attached
      */
-    @UiThread
     public Magnifier(@NonNull View view) {
         mView = Preconditions.checkNotNull(view);
         final Context context = mView.getContext();
-        final float elevation = context.getResources().getDimension(R.dimen.magnifier_elevation);
-        final View content = LayoutInflater.from(context).inflate(R.layout.magnifier, null);
-        content.findViewById(R.id.magnifier_inner).setClipToOutline(true);
-        mWindowWidth = context.getResources().getDimensionPixelSize(R.dimen.magnifier_width);
-        mWindowHeight = context.getResources().getDimensionPixelSize(R.dimen.magnifier_height);
-        mZoomScale = context.getResources().getFloat(R.dimen.magnifier_zoom_scale);
+        final float elevation = context.getResources().getDimension(
+                com.android.internal.R.dimen.magnifier_elevation);
+        final View content = LayoutInflater.from(context).inflate(
+                com.android.internal.R.layout.magnifier, null);
+        content.findViewById(com.android.internal.R.id.magnifier_inner).setClipToOutline(true);
+        mWindowWidth = context.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.magnifier_width);
+        mWindowHeight = context.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.magnifier_height);
+        mZoomScale = context.getResources().getFloat(
+                com.android.internal.R.dimen.magnifier_zoom_scale);
 
         mWindow = new PopupWindow(context);
         mWindow.setContentView(content);
@@ -104,13 +106,16 @@
      * Shows the magnifier on the screen.
      *
      * @param xPosInView horizontal coordinate of the center point of the magnifier source relative
-     *        to the view. The lower end is clamped to 0
+     *        to the view. The lower end is clamped to 0 and the higher end is clamped to the view
+     *        width.
      * @param yPosInView vertical coordinate of the center point of the magnifier source
-     *        relative to the view. The lower end is clamped to 0
+     *        relative to the view. The lower end is clamped to 0 and the higher end is clamped to
+     *        the view height.
      */
-    public void show(@FloatRange(from=0) float xPosInView, @FloatRange(from=0) float yPosInView) {
-        xPosInView = Math.max(0, xPosInView);
-        yPosInView = Math.max(0, yPosInView);
+    public void show(@FloatRange(from = 0) float xPosInView,
+            @FloatRange(from = 0) float yPosInView) {
+        xPosInView = Math.max(0, Math.min(xPosInView, mView.getWidth()));
+        yPosInView = Math.max(0, Math.min(yPosInView, mView.getHeight()));
 
         configureCoordinates(xPosInView, yPosInView);
 
@@ -136,7 +141,7 @@
     }
 
     /**
-     * Dismisses the magnifier from the screen.
+     * Dismisses the magnifier from the screen. Calling this on a dismissed magnifier is a no-op.
      */
     public void dismiss() {
         mWindow.dismiss();
@@ -155,27 +160,6 @@
         }
     }
 
-    /**
-     * @return the height of the magnifier window.
-     */
-    public int getHeight() {
-        return mWindowHeight;
-    }
-
-    /**
-     * @return the width of the magnifier window.
-     */
-    public int getWidth() {
-        return mWindowWidth;
-    }
-
-    /**
-     * @return the zoom scale of the magnifier.
-     */
-    public float getZoomScale() {
-        return mZoomScale;
-    }
-
     private void configureCoordinates(float xPosInView, float yPosInView) {
         final float posX;
         final float posY;
@@ -195,7 +179,7 @@
         mCenterZoomCoords.y = Math.round(posY);
 
         final int verticalMagnifierOffset = mView.getContext().getResources().getDimensionPixelSize(
-                R.dimen.magnifier_offset);
+                com.android.internal.R.dimen.magnifier_offset);
         mWindowCoords.x = mCenterZoomCoords.x - mWindowWidth / 2;
         mWindowCoords.y = mCenterZoomCoords.y - mWindowHeight / 2 - verticalMagnifierOffset;
     }
@@ -231,6 +215,7 @@
     }
 
     private ImageView getImageView() {
-        return mWindow.getContentView().findViewById(R.id.magnifier_image);
+        return mWindow.getContentView().findViewById(
+                com.android.internal.R.id.magnifier_image);
     }
 }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 6ede72d..56d0bb2 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -6020,6 +6020,11 @@
         }
 
         @Override
+        public Timer getMulticastWakelockStats() {
+            return mWifiMulticastTimer;
+        }
+
+        @Override
         public ArrayMap<String, ? extends BatteryStats.Timer> getSyncStats() {
             return mSyncStats.getMap();
         }
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index e53162c..5847033 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -32,7 +32,7 @@
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.ViewConfiguration;
-import android.view.WindowManagerPolicy.PointerEventListener;
+import android.view.WindowManagerPolicyConstants.PointerEventListener;
 import android.view.MotionEvent.PointerCoords;
 
 import java.util.ArrayList;
diff --git a/core/java/com/android/package.html b/core/java/com/android/package.html
deleted file mode 100644
index db6f78b..0000000
--- a/core/java/com/android/package.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<body>
-{@hide}
-</body>
\ No newline at end of file
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 5990d7b..2e8c27a 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -130,8 +130,10 @@
     chunk->paddingRight = int(chunk->paddingRight * scale + 0.5f);
     chunk->paddingBottom = int(chunk->paddingBottom * scale + 0.5f);
 
-    scaleDivRange(chunk->getXDivs(), chunk->numXDivs, scale, scaledWidth);
-    scaleDivRange(chunk->getYDivs(), chunk->numYDivs, scale, scaledHeight);
+    // The max value for the divRange is one pixel less than the actual max to ensure that the size
+    // of the last div is not zero. A div of size 0 is considered invalid input and will not render.
+    scaleDivRange(chunk->getXDivs(), chunk->numXDivs, scale, scaledWidth - 1);
+    scaleDivRange(chunk->getYDivs(), chunk->numYDivs, scale, scaledHeight - 1);
 }
 
 class ScaleCheckingAllocator : public SkBitmap::HeapAllocator {
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 32ef3dc..1407ae4 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -776,7 +776,10 @@
       }
 
       // Assign system_server to the correct memory cgroup.
-      if (!WriteStringToFile(StringPrintf("%d", pid), "/dev/memcg/system/tasks")) {
+      // Not all devices mount /dev/memcg so check for the file first
+      // to avoid unnecessarily printing errors and denials in the logs.
+      if (!access("/dev/memcg/system/tasks", F_OK) &&
+                !WriteStringToFile(StringPrintf("%d", pid), "/dev/memcg/system/tasks")) {
         ALOGE("couldn't write %d to /dev/memcg/system/tasks", pid);
       }
   }
diff --git a/core/proto/android/os/batterystats.proto b/core/proto/android/os/batterystats.proto
index 0a3344f..cff1879 100644
--- a/core/proto/android/os/batterystats.proto
+++ b/core/proto/android/os/batterystats.proto
@@ -395,6 +395,12 @@
   };
   repeated WakeupReason wakeup_reason = 22;
 
+  message WifiMulticastWakelockTotal {
+    optional int64 duration_ms = 1;
+    optional int32 count = 2;
+  }
+  optional WifiMulticastWakelockTotal wifi_multicast_wakelock_total = 23;
+
   message WifiSignalStrength {
     enum Name {
       NONE = 0;
@@ -406,7 +412,7 @@
     optional Name name = 1;
     optional TimerProto total = 2;
   };
-  repeated WifiSignalStrength wifi_signal_strength = 23;
+  repeated WifiSignalStrength wifi_signal_strength = 24;
 
   message WifiState {
     enum Name {
@@ -422,7 +428,7 @@
     optional Name name = 1;
     optional TimerProto total = 2;
   };
-  repeated WifiState wifi_state = 24;
+  repeated WifiState wifi_state = 25;
 
   message WifiSupplicantState {
     enum Name {
@@ -443,7 +449,7 @@
     optional Name name = 1;
     optional TimerProto total = 2;
   };
-  repeated WifiSupplicantState wifi_supplicant_state = 25;
+  repeated WifiSupplicantState wifi_supplicant_state = 26;
 }
 
 message TimerProto {
@@ -775,4 +781,12 @@
     optional TimerProto background_scan = 4;
   };
   optional Wifi wifi = 27;
+
+  // WiFi Multicast Wakelock
+  // This timer tracks the duration and count for the app to request the
+  // wakelock for wifi multicast traffic.
+  // This wakelock disables the filtering of multicast packets to reach the host
+  // processor, and results in a power penalty.
+  // It is useful to monitor the applications resulting in that
+  optional TimerProto wifi_multicast_wakelock = 28;
 }
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index 5d5aea2..3229140 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -281,6 +281,7 @@
     optional SettingProto bluetooth_pbap_client_priority_prefix = 209;
     optional SettingProto bluetooth_sap_priority_prefix = 210;
     optional SettingProto bluetooth_pan_priority_prefix = 211;
+    optional SettingProto bluetooth_hearing_aid_priority_prefix = 345;
     optional SettingProto activity_manager_constants = 317;
     optional SettingProto device_idle_constants = 212;
     optional SettingProto device_idle_constants_watch = 213;
@@ -387,7 +388,7 @@
     optional SettingProto enable_deletion_helper_no_threshold_toggle = 340;
     optional SettingProto notification_snooze_options = 341;
 
-    // Next tag = 345;
+    // Next tag = 346;
 }
 
 message SecureSettingsProto {
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 4ad3afb..b4240cd 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -79,7 +79,8 @@
     <string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"কোনো ভয়েস/জরুরী পরিষেবা নেই"</string>
     <string name="RestrictedStateContent" msgid="4278821484643362350">"সাময়িকভাবে মোবাইল নেটওয়ার্ক আপনার অবস্থানে এই পরিষেবা দিচ্ছে না"</string>
     <string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"নেটওয়ার্কের সিগন্যাল নেই"</string>
-    <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"রিসেপশন উন্নত করতে সেটিংস &gt; নেটওয়ার্ক এবং ইন্টারনেট &gt; মোবাইল নেটওয়ার্ক &gt; পছন্দের নেটওয়ার্কের ধরণ এ গিয়ে নির্বাচিত নেটওয়ার্কের ধরণ পরিবর্তন করে দেখুন।"</string>
+    <!-- no translation found for NetworkPreferenceSwitchSummary (7056776609127756440) -->
+    <skip />
     <string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"ওয়াই-ফাই কলিং সক্রিয় আছে"</string>
     <string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"জরুরি কলের জন্য মোবাইল নেটওয়ার্ক থাকতে হবে।"</string>
     <string name="notification_channel_network_alert" msgid="4427736684338074967">"সতর্কতা"</string>
@@ -1051,6 +1052,12 @@
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"সিস্টেম সেটিংস&gt; অ্যাপ্স&gt; ডাউনলোড করাগুলি এ এটি পুনঃসক্ষম করুন৷"</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g>, বর্তমান প্রদর্শনের আকারের সেটিংস সমর্থন করে না এবং অপ্রত্যাশিত আচরণ করতে পারে৷"</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"সর্বদা দেখান"</string>
+    <!-- no translation found for unsupported_compile_sdk_message (5030433583092006591) -->
+    <skip />
+    <!-- no translation found for unsupported_compile_sdk_show (2681877855260970231) -->
+    <skip />
+    <!-- no translation found for unsupported_compile_sdk_check_update (3312723623323216101) -->
+    <skip />
     <string name="smv_application" msgid="3307209192155442829">"অ্যাপ্লিকেশানটি <xliff:g id="APPLICATION">%1$s</xliff:g> (প্রক্রিয়া <xliff:g id="PROCESS">%2$s</xliff:g>) তার স্ব-প্রয়োগ করা কঠোর মোড নীতি লঙ্ঘন করেছে৷"</string>
     <string name="smv_process" msgid="5120397012047462446">"প্রক্রিয়াটি <xliff:g id="PROCESS">%1$s</xliff:g> তার স্ব-প্রয়োগ করা কঠোর মোড নীতি লঙ্ঘন করেছে৷"</string>
     <string name="android_upgrading_title" msgid="1584192285441405746">"Android আপগ্রেড করা হচ্ছে..."</string>
@@ -1074,7 +1081,7 @@
     <string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> মেমরি সীমা অতিক্রম করেছে"</string>
     <string name="dump_heap_notification_detail" msgid="6901391084243999274">"অনেক ডেটা সংগ্রহ করা হয়েছে; শেয়ার করার জন্য ট্যাপ করুন"</string>
     <string name="dump_heap_title" msgid="5864292264307651673">"হিপ ডাম্প শেয়ার করবেন?"</string>
-    <string name="dump_heap_text" msgid="4809417337240334941">"<xliff:g id="PROC">%1$s</xliff:g> প্রক্রিয়াটি তার <xliff:g id="SIZE">%2$s</xliff:g> এর মেমরি সীমা অতিক্রম করেছে৷ তার বিকাশকারীর সাথে শেয়ার করার জন্য একটি হিপ ডাম্প উপলব্ধ৷ সতর্কতা অবলম্বন করুন: এই হিপ ডাম্পে অ্যাপ্লিকেশানটির অ্যাক্সেস আছে এমন আপনার যেকোন ব্যক্তিগত তথ্য থাকতে পারে৷"</string>
+    <string name="dump_heap_text" msgid="4809417337240334941">"<xliff:g id="PROC">%1$s</xliff:g> প্রক্রিয়াটি তার <xliff:g id="SIZE">%2$s</xliff:g> এর মেমরি সীমা অতিক্রম করেছে৷ তার ডেভেলপারের সাথে শেয়ার করার জন্য একটি হিপ ডাম্প উপলব্ধ৷ সতর্কতা অবলম্বন করুন: এই হিপ ডাম্পে অ্যাপ্লিকেশানটির অ্যাক্সেস আছে এমন আপনার যেকোন ব্যক্তিগত তথ্য থাকতে পারে৷"</string>
     <string name="sendText" msgid="5209874571959469142">"পাঠ্যের জন্য একটি কাজ বেছে নিন"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"রিং ভলিউম"</string>
     <string name="volume_music" msgid="5421651157138628171">"মিডিয়ার ভলিউম"</string>
@@ -1116,10 +1123,12 @@
     <string name="network_available_sign_in" msgid="1848877297365446605">"নেটওয়ার্কে সাইন-ইন করুন"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
-    <string name="wifi_no_internet" msgid="8451173622563841546">"ওয়াই-ফাই -তে কোনো ইন্টারনেট অ্যাক্সেস নেই"</string>
+    <!-- no translation found for wifi_no_internet (8938267198124654938) -->
+    <skip />
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"বিকল্পগুলির জন্য আলতো চাপুন"</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> এ পাল্টানো হয়েছে"</string>
-    <string name="network_switch_metered_detail" msgid="5325661434777870353">"যখন <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> এর কোনো ইন্টারনেট অ্যাক্সেস থাকে না তখন ডিভাইস <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ব্যবহার করে৷ চার্জ লাগতে পারে৷"</string>
+    <!-- no translation found for network_switch_metered_detail (775163331794506615) -->
+    <skip />
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> থেকে <xliff:g id="NEW_NETWORK">%2$s</xliff:g> এ পাল্টানো হয়েছে"</string>
   <string-array name="network_switch_type_name">
     <item msgid="3979506840912951943">"মোবাইল ডেটা"</item>
@@ -1130,7 +1139,8 @@
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"এই নেটওয়ার্কের প্রকার অজানা"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ওয়াই-ফাই এর সাথে সংযোগ করা যায়নি"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" একটি দুর্বল ইন্টারনেট সংযোগ রয়েছে৷"</string>
+    <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
+    <skip />
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"সংযোগের অনুমতি দেবেন?"</string>
     <string name="wifi_connect_alert_message" msgid="6451273376815958922">"অ্যাপ্লিকেশান %1$s ওয়াই ফাই নেটওয়ার্ক %2$s এর সাথে সংযোগ করতে চায়"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"একটি অ্যাপ্লিকেশান"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 4e9ab0a..8b07393 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -79,7 +79,8 @@
     <string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Sense servei de veu/emergència"</string>
     <string name="RestrictedStateContent" msgid="4278821484643362350">"La xarxa mòbil de la teva ubicació temporalment no ofereix aquest servei"</string>
     <string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"No es pot accedir a la xarxa"</string>
-    <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Per millorar la recepció, prova de canviar el tipus de xarxa a Configuració &gt; Xarxa i Internet &gt; Xarxes mòbils &gt; Tipus de xarxa preferit."</string>
+    <!-- no translation found for NetworkPreferenceSwitchSummary (7056776609127756440) -->
+    <skip />
     <string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"La funció Trucades per Wi Fi està activada"</string>
     <string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"Per poder fer trucades d\'emergència, cal tenir connexió a una xarxa mòbil."</string>
     <string name="notification_channel_network_alert" msgid="4427736684338074967">"Alertes"</string>
@@ -1051,6 +1052,12 @@
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Torna a activar-ho a Configuració del sistema &gt; Aplicacions &gt; Baixades."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admet la mida de pantalla actual i és possible que funcioni de manera inesperada."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostra sempre"</string>
+    <!-- no translation found for unsupported_compile_sdk_message (5030433583092006591) -->
+    <skip />
+    <!-- no translation found for unsupported_compile_sdk_show (2681877855260970231) -->
+    <skip />
+    <!-- no translation found for unsupported_compile_sdk_check_update (3312723623323216101) -->
+    <skip />
     <string name="smv_application" msgid="3307209192155442829">"L\'aplicació <xliff:g id="APPLICATION">%1$s</xliff:g>(procés <xliff:g id="PROCESS">%2$s</xliff:g>) ha incomplert la seva política autoimposada de mode estricte."</string>
     <string name="smv_process" msgid="5120397012047462446">"El procés <xliff:g id="PROCESS">%1$s</xliff:g> ha incomplert la seva política de mode estricte."</string>
     <string name="android_upgrading_title" msgid="1584192285441405746">"Android s\'està actualitzant..."</string>
@@ -1116,10 +1123,12 @@
     <string name="network_available_sign_in" msgid="1848877297365446605">"Inicia la sessió a la xarxa"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
-    <string name="wifi_no_internet" msgid="8451173622563841546">"La Wi-Fi no té accés a Internet"</string>
+    <!-- no translation found for wifi_no_internet (8938267198124654938) -->
+    <skip />
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toca per veure les opcions"</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Actualment en ús: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
-    <string name="network_switch_metered_detail" msgid="5325661434777870353">"El dispositiu utilitza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> en cas que <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tingui accés a Internet. És possible que s\'hi apliquin càrrecs."</string>
+    <!-- no translation found for network_switch_metered_detail (775163331794506615) -->
+    <skip />
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Abans es feia servir la xarxa <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>; ara s\'utilitza <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
   <string-array name="network_switch_type_name">
     <item msgid="3979506840912951943">"dades mòbils"</item>
@@ -1130,7 +1139,7 @@
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"una tipus de xarxa desconegut"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"No s\'ha pogut connectar a la Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" té una mala connexió a Internet."</string>
+    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" té una mala connexió a Internet."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vols permetre la connexió?"</string>
     <string name="wifi_connect_alert_message" msgid="6451273376815958922">"L\'aplicació %1$s vol connectar-se a la xarxa Wi-Fi %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Una aplicació"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index a131af5..b93e830 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -79,7 +79,7 @@
     <string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‎‎‏‏‎‏‎‎‎‎‏‎‏‎‏‏‏‏‏‎‏‎‏‎‎‎‏‎‎‏‎‎‎‏‏‏‏‎‏‎‎‏‎‏‏‏‎‏‎‏‎‏‏‎‎‏‎No voice/emergency service‎‏‎‎‏‎"</string>
     <string name="RestrictedStateContent" msgid="4278821484643362350">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‏‎‎‎‎‏‎‏‏‎‏‏‎‏‎‏‏‏‏‎‎‎‎‏‎‏‏‎‎‏‎‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎‎‎‏‎‏‏‏‎‎Temporarily not offered by the mobile network at your location‎‏‎‎‏‎"</string>
     <string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎‎‏‎‎‏‏‎‏‏‎‎‏‏‏‏‎‎‏‏‏‏‎‎‎‏‏‎‎‎‎‏‎‏‏‎‎‏‏‎‎‎‏‎‎‎Can’t reach network‎‏‎‎‏‎"</string>
-    <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‎‏‏‎‏‎‎‏‎‏‎‎‏‏‏‏‏‎‎‎‎‎‎‏‎‏‏‏‏‏‎‎‏‎‏‎‎‎‏‎‎‏‏‏‏‏‎‏‎‎‏‎‏‎‏‎To improve reception, try changing the type selected at Settings &gt; Network &amp; Internet &gt; Mobile networks &gt; Preferred network type.‎‏‎‎‏‎"</string>
+    <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‎‏‏‎‏‎‎‏‏‏‏‎‎‎‎‎‎‎‎‎‏‏‎‎‏‎‏‏‎‎‎‎‏‏‏‎‎‏‎‏‎‎‏‏‎‎‎‎To improve reception, try changing the type selected at Settings &gt; Network &amp; internet &gt; Mobile networks &gt; Preferred network type.‎‏‎‎‏‎"</string>
     <string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‏‏‏‎‏‎‏‏‏‏‏‎‎‎‎‎‎‎‏‎‏‎‎‎‏‎‏‏‏‎‏‏‏‎‎‎‏‎‏‎‎‎‎‎‏‎‎‎‏‎‏‏‎‎‎Wi‑Fi calling is active‎‏‎‎‏‎"</string>
     <string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‏‏‏‎‏‎‏‎‎‏‏‏‏‎‎‎‏‎‎‏‏‏‏‏‎‎‏‎‏‏‎‎‎‎‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‎‏‎Emergency calls require a mobile network.‎‏‎‎‏‎"</string>
     <string name="notification_channel_network_alert" msgid="4427736684338074967">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‏‎‎‏‎‎‏‏‏‏‎‏‏‎‎‎‎‏‏‏‎‎‎‏‎‎‏‎‎‏‏‏‎‏‏‏‏‏‏‎‏‎‏‎‏‎‏‎‏‎‏‏‏‎Alerts‎‏‎‎‏‎"</string>
@@ -1051,6 +1051,9 @@
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‏‎‎‎‏‎‏‏‏‏‏‎‎‏‏‎‎‎‎‎‎‏‏‏‏‎‎‏‎‏‎‎‎‎‎‏‏‎‏‎‎‏‏‎‎‏‏‎‎‎‎‏‎‏‏‎Re-enable this in System settings &gt; Apps &gt; Downloaded.‎‏‎‎‏‎"</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‏‎‏‎‏‎‏‏‎‏‎‏‏‎‎‎‏‏‏‏‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‎‎‏‎‏‏‏‎‏‎‏‎‎‏‎‎‎‎‎‎‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ does not support the current Display size setting and may behave unexpectedly.‎‏‎‎‏‎"</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‎‎‎‎‎‎‎‏‎‎‎‏‏‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‏‎‎‏‎‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‎‏‎Always show‎‏‎‎‏‎"</string>
+    <string name="unsupported_compile_sdk_message" msgid="5030433583092006591">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‎‏‏‎‎‎‏‎‎‎‎‎‎‏‎‎‏‏‎‎‏‎‎‏‏‏‏‏‏‏‎‏‎‏‏‏‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ was built for preview version %2$s of the Android OS and may behave unexpectedly. An updated version of the app may be available.‎‏‎‎‏‎"</string>
+    <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‏‏‎‏‏‏‏‏‏‏‎‎‎‏‏‎‏‏‎‎‏‏‎‎‏‏‏‏‎‏‏‏‎‏‎‎‎‏‎‎‎‎‏‏‎‎‏‏‏‏‎‏‏‏‎Always show‎‏‎‎‏‎"</string>
+    <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‏‏‏‏‏‎‎‏‎‎‏‎‏‎‎‎‏‎‎‏‎‏‎‏‎‏‏‏‎‏‏‏‎‎‏‏‏‎‎‏‏‎‏‎‏‎‎‎‏‏‏‎‎‏‎‏‎Check for update‎‏‎‎‏‎"</string>
     <string name="smv_application" msgid="3307209192155442829">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‏‏‏‎‎‏‎‏‏‎‎‏‎‎‎‏‎‎‏‏‏‏‎‎‏‏‏‎‏‎‎‎‎‏‎‏‎‏‎‎‏‏‏‎‏‏‏‎‏‎‎‎‏‏‎‏‎The app ‎‏‎‎‏‏‎<xliff:g id="APPLICATION">%1$s</xliff:g>‎‏‎‎‏‏‏‎ (process ‎‏‎‎‏‏‎<xliff:g id="PROCESS">%2$s</xliff:g>‎‏‎‎‏‏‏‎) has violated its self-enforced StrictMode policy.‎‏‎‎‏‎"</string>
     <string name="smv_process" msgid="5120397012047462446">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‎‎‎‏‏‏‏‎‏‎‎‏‏‎‏‏‏‏‏‎‏‎‎‎‎‎‏‎‏‎‎‎‎‎‎‏‏‏‏‏‎‎‎‎‎‎‎‎‎‏‎‏‏‏‎‎The process ‎‏‎‎‏‏‎<xliff:g id="PROCESS">%1$s</xliff:g>‎‏‎‎‏‏‏‎ has has violated its self-enforced StrictMode policy.‎‏‎‎‏‎"</string>
     <string name="android_upgrading_title" msgid="1584192285441405746">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‏‏‏‏‏‎‎‎‎‏‎‏‏‏‎‎‏‏‏‏‏‎‏‎‏‏‏‏‏‎‏‏‎‏‎‎‏‏‎‎‎‏‏‎‎‏‏‎‎‏‏‎‎‏‎‎Android is upgrading…‎‏‎‎‏‎"</string>
@@ -1116,10 +1119,10 @@
     <string name="network_available_sign_in" msgid="1848877297365446605">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‏‎‏‎‏‎‎‎‏‎‎‎‏‎‎‎‎‎‎‏‏‎‏‏‎‎‏‎‏‏‏‎‏‏‎‎‎‎‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‏‎‏‎Sign in to network‎‏‎‎‏‎"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
-    <string name="wifi_no_internet" msgid="8451173622563841546">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‎‎‎‏‎‎‏‏‎‎‏‏‎‏‎‎‎‏‎‎‎‏‎‏‏‎‎‎‎‎‏‎‎‎‏‏‎‏‎‎‏‏‎‎‎‎‎‏‎‏‎‎Wi-Fi has no Internet access‎‏‎‎‏‎"</string>
+    <string name="wifi_no_internet" msgid="8938267198124654938">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‎‏‏‎‎‎‏‏‎‏‎‏‎‏‎‏‎‎‎‏‏‏‎‎‎‏‏‏‎‏‏‏‏‏‏‎‎‎‎‎‎‎‏‎‏‎‏‏‎‏‎‎Wi-Fi has no internet access‎‏‎‎‏‎"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‎‏‏‎‎‏‏‎‏‏‏‎‏‏‎‏‏‏‏‏‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‏‏‎‎‎‏‎‎‎‏‏‎‏‎‏‏‎‏‎Tap for options‎‏‎‎‏‎"</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‎‏‎‏‎‏‎‏‎‏‎‎‏‎‏‎‎‎‎‏‎‏‎‏‏‏‏‎‏‏‏‎‏‏‏‏‏‎‏‏‏‎‎‎‎‏‎‎‎‏‏‏‏‏‎Switched to ‎‏‎‎‏‏‎<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
-    <string name="network_switch_metered_detail" msgid="5325661434777870353">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‏‎‏‎‎‎‏‎‎‎‏‏‎‎‏‏‎‏‏‎‏‏‏‎‏‏‏‏‎‏‏‏‏‎‏‏‏‎‏‎‏‎‎‎‎‎‎‎‎‏‎‎‎‏‎Device uses ‎‏‎‎‏‏‎<xliff:g id="NEW_NETWORK">%1$s</xliff:g>‎‏‎‎‏‏‏‎ when ‎‏‎‎‏‏‎<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>‎‏‎‎‏‏‏‎ has no Internet access. Charges may apply.‎‏‎‎‏‎"</string>
+    <string name="network_switch_metered_detail" msgid="775163331794506615">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‏‏‎‎‎‎‎‏‏‏‏‎‏‏‏‎‏‏‏‏‎‎‎‏‎‏‏‏‏‎‏‎‏‎‎‎‎‏‎‏‎‎‎‏‎‎‏‏‎‏‏‏‎‏‏‏‎Device uses ‎‏‎‎‏‏‎<xliff:g id="NEW_NETWORK">%1$s</xliff:g>‎‏‎‎‏‏‏‎ when ‎‏‎‎‏‏‎<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>‎‏‎‎‏‏‏‎ has no internet access. Charges may apply.‎‏‎‎‏‎"</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‏‎‏‎‎‎‎‏‎‎‎‏‏‎‏‏‎‏‏‏‏‎‎‎‎‏‏‎‎‏‏‎‎‏‎‎‎‎‎‏‎‎‏‎‏‎‎‏‎‎‎‎‎‎Switched from ‎‏‎‎‏‏‎<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to ‎‏‎‎‏‏‎<xliff:g id="NEW_NETWORK">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
   <string-array name="network_switch_type_name">
     <item msgid="3979506840912951943">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‏‎‎‏‏‏‎‏‎‎‎‎‎‏‏‎‎‎‏‏‎‎‎‏‏‎‎‏‏‎‎‎‏‏‏‎‏‏‎‏‎‎‏‏‏‏‎‏‎‏‎‎‎‎‏‏‏‎mobile data‎‏‎‎‏‎"</item>
@@ -1130,7 +1133,7 @@
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‎‏‎‎‎‎‏‎‏‎‎‏‏‏‏‎‏‎‎‏‏‎‏‏‎‏‎‎‎‎‎‏‎‏‏‎‏‎‎‎‎‏‏‎‎‎‎‎an unknown network type‎‏‎‎‏‎"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‏‎‎‎‏‎‏‏‎‏‎‎‎‏‏‏‏‎‏‏‏‎‎‏‎‎‎‏‎‎‎‏‎‏‏‎‏‎‏‏‏‎‏‎‎‏‏‏‎‏‎‏‏‎Couldn\'t connect to Wi-Fi‎‏‎‎‏‎"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‎‎‎‎‎‎‏‎‎‏‏‏‎‏‎‏‎‏‏‎‏‏‏‏‎‏‎‏‎‏‎‏‏‏‎‏‏‏‎‎‏‎‏‎‎‎‎‎‎‎‎‎‎‏‏‎ has a poor Internet connection.‎‏‎‎‏‎"</string>
+    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‏‎‏‏‎‎‎‏‏‏‏‎‏‎‏‏‎‎‏‎‏‎‏‏‎‎‏‏‏‏‎ has a poor internet connection.‎‏‎‎‏‎"</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‎‏‎‎‏‏‎‎‏‏‎‎‏‎‎‏‏‎‏‎‎‎‏‎‏‏‎‎‏‏‎‎‎‎‏‎‎‏‏‏‏‎‏‏‏‏‏‏‎‎‎Allow connection?‎‏‎‎‏‎"</string>
     <string name="wifi_connect_alert_message" msgid="6451273376815958922">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‎‏‏‏‏‎‎‎‎‏‏‎‏‏‏‏‎‏‎‎‏‎‏‏‎‏‏‎‎‎‎‎‏‏‎‎‏‏‎‎‏‎‏‏‏‎‎‎‏‎‏‎‎Application %1$s would like to connect to Wifi Network %2$s‎‏‎‎‏‎"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‎‎‎‏‎‏‏‎‏‏‎‎‎‎‏‎‎‏‎‏‎‎‎‏‎‎‏‏‎‎‎‎‏‏‎‎‎‏‎‏‏‏‎‎‏‎‎‏‏‏‏‏‎An application‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index f24ee79..0a71c74 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -79,7 +79,8 @@
     <string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"कोई वॉइस/आपातकालीन सेवा नहीं है"</string>
     <string name="RestrictedStateContent" msgid="4278821484643362350">"मोबाइल नेटवर्क आपके जगह पर इस समय यह सेवाएं नहीं दे पा रहा"</string>
     <string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"नेटवर्क तक नहीं पहुंच पा रहे हैं"</string>
-    <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"रिसेप्शन बेहतर करने के लिए, सेटिंग &gt; नेटवर्क और इंटरनेट &gt; मोबाइल नेटवर्क &gt; पसंदीदा नेटवर्क प्रकार पर जाकर, चुना गया प्रकार बदलकर देखें."</string>
+    <!-- no translation found for NetworkPreferenceSwitchSummary (7056776609127756440) -->
+    <skip />
     <string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"वाई-फ़ाई कॉलिंग सक्रिय है"</string>
     <string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"आपातकालीन कॉल के लिए मोबाइल नेटवर्क ज़रूरी है."</string>
     <string name="notification_channel_network_alert" msgid="4427736684338074967">"सूचनाएं"</string>
@@ -1006,9 +1007,9 @@
     <string name="whichEditApplication" msgid="144727838241402655">"इसके ज़रिये बदलाव करें"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s की मदद से बदलाव करें"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"बदलाव करें"</string>
-    <string name="whichSendApplication" msgid="6902512414057341668">"इससे साझा करें"</string>
-    <string name="whichSendApplicationNamed" msgid="2799370240005424391">"%1$s से साझा करें"</string>
-    <string name="whichSendApplicationLabel" msgid="4579076294675975354">"साझा करें"</string>
+    <string name="whichSendApplication" msgid="6902512414057341668">"इससे शेयर करें"</string>
+    <string name="whichSendApplicationNamed" msgid="2799370240005424391">"%1$s से शेयर करें"</string>
+    <string name="whichSendApplicationLabel" msgid="4579076294675975354">"शेयर करें"</string>
     <string name="whichSendToApplication" msgid="8272422260066642057">"इसका उपयोग करके भेजें"</string>
     <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"%1$s का उपयोग करके भेजें"</string>
     <string name="whichSendToApplicationLabel" msgid="8878962419005813500">"भेजें"</string>
@@ -1051,6 +1052,12 @@
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"इसे सिस्‍टम सेटिंग &gt; ऐप &gt; डाउनलोड किए गए में फिर से चालू करें."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> वर्तमान स्क्रीन के आकार की सेटिंग का समर्थन नहीं करता है और अनपेक्षित रूप से व्यवहार कर सकता है."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"हमेशा दिखाएं"</string>
+    <!-- no translation found for unsupported_compile_sdk_message (5030433583092006591) -->
+    <skip />
+    <!-- no translation found for unsupported_compile_sdk_show (2681877855260970231) -->
+    <skip />
+    <!-- no translation found for unsupported_compile_sdk_check_update (3312723623323216101) -->
+    <skip />
     <string name="smv_application" msgid="3307209192155442829">"ऐप्स <xliff:g id="APPLICATION">%1$s</xliff:g> (प्रक्रिया <xliff:g id="PROCESS">%2$s</xliff:g>) ने उसकी स्‍वयं लागू होने वाली StrictMode नीति का उल्‍लंघन किया है."</string>
     <string name="smv_process" msgid="5120397012047462446">"प्रक्रिया <xliff:g id="PROCESS">%1$s</xliff:g> ने उसकी स्‍व-प्रवर्तित StrictMode नीति का उल्‍लंघन किया है."</string>
     <string name="android_upgrading_title" msgid="1584192285441405746">"Android अपग्रेड हो रहा है..."</string>
@@ -1073,7 +1080,7 @@
     <string name="new_app_description" msgid="1932143598371537340">"पुराने ऐप्स को बिना सहेजे बंद करें."</string>
     <string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> मेमोरी सीमा को पार कर गई है"</string>
     <string name="dump_heap_notification_detail" msgid="6901391084243999274">"हीप डंप का संग्रह कर लिया गया है; शेयर करने के लिए टैप करें"</string>
-    <string name="dump_heap_title" msgid="5864292264307651673">"हीप डंप साझा करें?"</string>
+    <string name="dump_heap_title" msgid="5864292264307651673">"हीप डंप शेयर करें?"</string>
     <string name="dump_heap_text" msgid="4809417337240334941">"यह प्रक्रिया <xliff:g id="PROC">%1$s</xliff:g> इसकी <xliff:g id="SIZE">%2$s</xliff:g> की मेमोरी की सीमा को पार कर गई है. एक हीप डंप मौजूद है जिसे आप इसके डेवलपर से शेयर कर सकते हैं. सावधान रहें: इस हीप डंप में आपकी ऐसी कोई भी निजी जानकारी हो सकती है जिस पर ऐप्लिकेशन की पहुंच हो."</string>
     <string name="sendText" msgid="5209874571959469142">"मैसेज करने के लिए कोई कार्रवाई चुनें"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"रिंगर वॉल्‍यूम"</string>
@@ -1116,10 +1123,12 @@
     <string name="network_available_sign_in" msgid="1848877297365446605">"नेटवर्क में साइन इन करें"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
-    <string name="wifi_no_internet" msgid="8451173622563841546">"वाई-फ़ाई में कोई इंटरनेट ऐक्‍सेस नहीं है"</string>
+    <!-- no translation found for wifi_no_internet (8938267198124654938) -->
+    <skip />
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"विकल्पों के लिए टैप करें"</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> पर ले जाया गया"</string>
-    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> में कोई इंटरनेट की सुविधा नहीं होने पर डिवाइस <xliff:g id="NEW_NETWORK">%1$s</xliff:g> का इस्तेमाल करता है. इसके लिए शुल्क लिया जा सकता है."</string>
+    <!-- no translation found for network_switch_metered_detail (775163331794506615) -->
+    <skip />
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> से <xliff:g id="NEW_NETWORK">%2$s</xliff:g> पर ले जाया गया"</string>
   <string-array name="network_switch_type_name">
     <item msgid="3979506840912951943">"मोबाइल डेटा"</item>
@@ -1130,7 +1139,7 @@
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"अज्ञात नेटवर्क प्रकार"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"वाई-फ़ाई  से कनेक्‍ट नहीं हो सका"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" के पास एक कमज़ोर इंटरनेट कनेक्‍शन है."</string>
+    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" के पास एक कमज़ोर इंटरनेट कनेक्‍शन है."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"कनेक्शन की अनुमति दें?"</string>
     <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s ऐप्‍लिकेशन %2$s वाई-फ़ाई नेटवर्क से कनेक्‍ट करना चाहता है"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"ऐप्लिकेशन"</string>
@@ -1200,7 +1209,7 @@
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"गड़बड़ी की रिपोर्ट शेयर करें?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"गड़बड़ी की रिपोर्ट शेयर की जा रही है…"</string>
     <string name="share_remote_bugreport_notification_message_finished" msgid="6029609949340992866">"आपके एडमिन ने इस डिवाइस की समस्या को हल करने में सहायता के लिए एक गड़बड़ी की रिपोर्ट का अनुरोध किया है. ऐप्लिकेशन और डेटा शेयर किए जा सकते हैं."</string>
-    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"साझा करें"</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"शेयर करें"</string>
     <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"अस्वीकार करें"</string>
     <string name="select_input_method" msgid="8547250819326693584">"कीबोर्ड बदलें"</string>
     <string name="show_ime" msgid="2506087537466597099">"भौतिक कीबोर्ड के सक्रिय होने के दौरान इसे स्‍क्रीन पर बनाए रखें"</string>
@@ -1323,7 +1332,7 @@
     <string name="action_mode_done" msgid="7217581640461922289">"हो गया"</string>
     <string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"USB मेमोरी मिटाया जा रहा है…"</string>
     <string name="progress_erasing" product="default" msgid="6596988875507043042">"SD कार्ड मिटाया जा रहा है…"</string>
-    <string name="share" msgid="1778686618230011964">"साझा करें"</string>
+    <string name="share" msgid="1778686618230011964">"शेयर करें"</string>
     <string name="find" msgid="4808270900322985960">"ढूंढें"</string>
     <string name="websearch" msgid="4337157977400211589">"वेब सर्च"</string>
     <string name="find_next" msgid="5742124618942193978">"आगे ढूंढें"</string>
@@ -1368,8 +1377,8 @@
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"कोई ऐप्स चुनें"</string>
     <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> को लॉन्च नहीं किया जा सका"</string>
-    <string name="shareactionprovider_share_with" msgid="806688056141131819">"इसके साथ साझा करें:"</string>
-    <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> के साथ साझा करें"</string>
+    <string name="shareactionprovider_share_with" msgid="806688056141131819">"इसके साथ शेयर करें:"</string>
+    <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> के साथ शेयर करें"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"स्लाइडिंग हैंडल. दबाकर रखें."</string>
     <string name="description_target_unlock_tablet" msgid="3833195335629795055">"अनलॉक करने के लिए स्‍वाइप करें."</string>
     <string name="action_bar_home_description" msgid="5293600496601490216">"होम पेज पर जाएं"</string>
@@ -1414,7 +1423,7 @@
     <string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1 फ़िंगरप्रिंट:"</string>
     <string name="activity_chooser_view_see_all" msgid="4292569383976636200">"सभी देखें"</string>
     <string name="activity_chooser_view_dialog_title_default" msgid="4710013864974040615">"गतिविधि चुनें"</string>
-    <string name="share_action_provider_share_with" msgid="5247684435979149216">"इसके साथ साझा करें:"</string>
+    <string name="share_action_provider_share_with" msgid="5247684435979149216">"इसके साथ शेयर करें:"</string>
     <string name="sending" msgid="3245653681008218030">"भेजा जा रहा है…"</string>
     <string name="launchBrowserDefault" msgid="2057951947297614725">"ब्राउज़र लॉन्च करें?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"कॉल स्वीकार करें?"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index af37300..83d0765 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -79,7 +79,8 @@
     <string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"व्हॉइस/आणीबाणी सेवा नाही"</string>
     <string name="RestrictedStateContent" msgid="4278821484643362350">"तुम्‍ही असलेल्‍या स्‍थानी मोबाइल नेटवर्क तात्‍पुरते उपलब्‍ध नाही"</string>
     <string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"नेटवर्कवर पोहोचूू शकत नाही"</string>
-    <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"रीसेप्शन सुधारण्यासाठी, सेटिंग्ज &gt; नेटवर्क आणि इंटरनेट &gt; मोबाइल नेटवर्क &gt; अग्रमानांकित नेटवर्क प्रकार बदलून पहा."</string>
+    <!-- no translation found for NetworkPreferenceSwitchSummary (7056776609127756440) -->
+    <skip />
     <string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"वाय-फाय कॉलिंग चालू आहे"</string>
     <string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"आपात्कालीन कॉलसाठी मोबाइल नेटवर्क असणे आवश्यक आहे."</string>
     <string name="notification_channel_network_alert" msgid="4427736684338074967">"अलर्ट"</string>
@@ -1051,6 +1052,12 @@
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"सिस्टम सेटिंग्ज &gt; Apps &gt; डाउनलोड केलेले मध्ये हे पुन्हा-सक्षम करा."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> वर्तमान डिस्प्ले आकार सेटिंगला समर्थन देत नाही आणि अनपेक्षित वर्तन करू शकते."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"नेहमी दर्शवा"</string>
+    <!-- no translation found for unsupported_compile_sdk_message (5030433583092006591) -->
+    <skip />
+    <!-- no translation found for unsupported_compile_sdk_show (2681877855260970231) -->
+    <skip />
+    <!-- no translation found for unsupported_compile_sdk_check_update (3312723623323216101) -->
+    <skip />
     <string name="smv_application" msgid="3307209192155442829">"अॅप <xliff:g id="APPLICATION">%1$s</xliff:g> (प्रक्रिया <xliff:g id="PROCESS">%2$s</xliff:g>) ने तिच्या स्वयं-लागू केलेल्या StrictMode धोरणाचे उल्लंघन केले आहे."</string>
     <string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> प्रक्रियेने तिच्या स्वतः-लागू केलेल्या StrictMode धोरणाचे उल्लंघन केले."</string>
     <string name="android_upgrading_title" msgid="1584192285441405746">"Android श्रेणीसुधारित होत आहे..."</string>
@@ -1116,10 +1123,12 @@
     <string name="network_available_sign_in" msgid="1848877297365446605">"नेटवर्कवर साइन इन करा"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
-    <string name="wifi_no_internet" msgid="8451173622563841546">"वाय-फायवरून इंटरनेटवर अॅक्सेस नाही"</string>
+    <!-- no translation found for wifi_no_internet (8938267198124654938) -->
+    <skip />
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"पर्यायांसाठी टॅप करा"</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> वर स्विच केले"</string>
-    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> कडे इंटरनेट अॅक्सेस नसताना डिव्हाइस <xliff:g id="NEW_NETWORK">%1$s</xliff:g> वापरते. शुल्क लागू शकेल."</string>
+    <!-- no translation found for network_switch_metered_detail (775163331794506615) -->
+    <skip />
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> वरून <xliff:g id="NEW_NETWORK">%2$s</xliff:g> वर स्विच केले"</string>
   <string-array name="network_switch_type_name">
     <item msgid="3979506840912951943">"मोबाइल डेटा"</item>
@@ -1130,7 +1139,8 @@
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"अज्ञात नेटवर्क प्रकार"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"वाय-फाय ला कनेक्ट करू शकलो नाही"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" खराब इंटरनेट कनेक्शन आहे."</string>
+    <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
+    <skip />
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"कनेक्शनला अनुमती द्यायची?"</string>
     <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s अॅप्लिकेशन %2$s वायफाय नेटवर्कशी कनेक्ट करू इच्छित आहे"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"अॅप्लिकेशन"</string>
@@ -1408,7 +1418,7 @@
     <string name="validity_period" msgid="8818886137545983110">"वैधता:"</string>
     <string name="issued_on" msgid="5895017404361397232">"रोजी जारी:"</string>
     <string name="expires_on" msgid="3676242949915959821">"रोजी मुदत संपेल:"</string>
-    <string name="serial_number" msgid="758814067660862493">"सीरीअल नंबर:"</string>
+    <string name="serial_number" msgid="758814067660862493">"सिरीअल नंबर:"</string>
     <string name="fingerprints" msgid="4516019619850763049">"फिंगरप्रिंट:"</string>
     <string name="sha256_fingerprint" msgid="4391271286477279263">"SHA-256 फिंगरप्रिंट:"</string>
     <string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1 फिंगरप्रिंट:"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index e03824b..e318851 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -79,7 +79,8 @@
     <string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"குரல்/அவசரச் சேவை இல்லை"</string>
     <string name="RestrictedStateContent" msgid="4278821484643362350">"தற்காலிகமாக உங்கள் இருப்பிடத்தில் மொபைல் நெட்வொர்க் வழங்கவில்லை"</string>
     <string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"நெட்வொர்க்குடன் இணைக்க முடியவில்லை"</string>
-    <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"பெறுதலை மேம்படுத்த, அமைப்புகள் &gt; நெட்வொர்க் &amp; இணையம் &gt; மொபைல் நெட்வொர்க்குகள் &gt; விரும்பும் நெட்வொர்க் வகை என்பதற்குச் சென்று, தேர்ந்தெடுத்த வகையை மாற்றவும்."</string>
+    <!-- no translation found for NetworkPreferenceSwitchSummary (7056776609127756440) -->
+    <skip />
     <string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"வைஃபை அழைப்பு இயக்கத்தில் உள்ளது"</string>
     <string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"அவசர அழைப்புகளுக்கு, மொபைல் நெட்வொர்க் தேவை."</string>
     <string name="notification_channel_network_alert" msgid="4427736684338074967">"விழிப்பூட்டல்கள்"</string>
@@ -321,7 +322,7 @@
     <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"குழுசேர்ந்த ஊட்டங்களைப் படித்தல்"</string>
     <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"தற்போது ஒத்திசைந்த ஊட்டங்களைப் பற்றிய விவரங்களைப் பெற பயன்பாட்டை அனுமதிக்கிறது."</string>
     <string name="permlab_sendSms" msgid="7544599214260982981">"SMS செய்திகளை அனுப்புதல் மற்றும் பார்த்தல்"</string>
-    <string name="permdesc_sendSms" msgid="7094729298204937667">"SMS செய்திகளை அனுப்ப பயன்பாட்டை அனுமதிக்கிறது. இதற்கு எதிர்பாராத கட்டணங்கள் விதிக்கப்படலாம். தீங்கு விளைவிக்கும் பயன்பாடுகள் உங்களின் உறுதிப்படுத்தல் எதுவுமின்றி செய்திகளை அனுப்பி உங்களுக்குக் கட்டணம் விதிக்கலாம்."</string>
+    <string name="permdesc_sendSms" msgid="7094729298204937667">"SMS செய்திகளை அனுப்ப பயன்பாட்டை அனுமதிக்கிறது. இதற்கு எதிர்பாராத பேமெண்ட்கள் விதிக்கப்படலாம். தீங்கு விளைவிக்கும் பயன்பாடுகள் உங்களின் உறுதிப்படுத்தல் எதுவுமின்றி செய்திகளை அனுப்பி உங்களுக்குக் கட்டணம் விதிக்கலாம்."</string>
     <string name="permlab_readSms" msgid="8745086572213270480">"உங்கள் உரைச் செய்திகளை (SMS அல்லது MMS) படித்தல்"</string>
     <string name="permdesc_readSms" product="tablet" msgid="4741697454888074891">"இந்தப் பயன்பாடு உங்கள் டேப்லெட்டில் சேமிக்கப்பட்டுள்ள எல்லா SMS (உரை) செய்திகளையும் படிக்கலாம்."</string>
     <string name="permdesc_readSms" product="tv" msgid="5796670395641116592">"இந்தப் பயன்பாடு உங்கள் டிவியில் சேமிக்கப்பட்டுள்ள எல்லா SMS (உரை) செய்திகளையும் படிக்கலாம்."</string>
@@ -1051,6 +1052,12 @@
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"சிஸ்டம் அமைப்பு &gt; பயன்பாடுகள் &gt; பதிவிறக்கம் என்பதில் இதை மீண்டும் இயக்கவும்."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"தற்போதைய திரை அளவு அமைப்பை <xliff:g id="APP_NAME">%1$s</xliff:g> ஆதரிக்காததால், அது வழக்கத்திற்கு மாறாகச் செயல்படக்கூடும்."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"எப்போதும் காட்டு"</string>
+    <!-- no translation found for unsupported_compile_sdk_message (5030433583092006591) -->
+    <skip />
+    <!-- no translation found for unsupported_compile_sdk_show (2681877855260970231) -->
+    <skip />
+    <!-- no translation found for unsupported_compile_sdk_check_update (3312723623323216101) -->
+    <skip />
     <string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> பயன்பாடு (செயல்முறை <xliff:g id="PROCESS">%2$s</xliff:g>), தனது சுய-செயலாக்க StrictMode கொள்கையை மீறியது."</string>
     <string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> செயல்முறை, தனது சுய-செயலாக்க StrictMode கொள்கையை மீறியது."</string>
     <string name="android_upgrading_title" msgid="1584192285441405746">"Android மேம்படுத்தப்படுகிறது…"</string>
@@ -1116,10 +1123,12 @@
     <string name="network_available_sign_in" msgid="1848877297365446605">"நெட்வொர்க்கில் உள்நுழையவும்"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
-    <string name="wifi_no_internet" msgid="8451173622563841546">"வைஃபை இணைய அணுகல் கொண்டிருக்கவில்லை"</string>
+    <!-- no translation found for wifi_no_internet (8938267198124654938) -->
+    <skip />
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"விருப்பங்களுக்கு, தட்டவும்"</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>க்கு மாற்றப்பட்டது"</string>
-    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> இல் இணைய அணுகல் இல்லாததால், சாதனமானது <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ஐப் பயன்படுத்துகிறது. கட்டணங்கள் விதிக்கப்படலாம்."</string>
+    <!-- no translation found for network_switch_metered_detail (775163331794506615) -->
+    <skip />
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> இலிருந்து <xliff:g id="NEW_NETWORK">%2$s</xliff:g>க்கு மாற்றப்பட்டது"</string>
   <string-array name="network_switch_type_name">
     <item msgid="3979506840912951943">"மொபைல் டேட்டா"</item>
@@ -1130,7 +1139,8 @@
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"தெரியாத நெட்வொர்க் வகை"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"வைஃபை உடன் இணைக்க முடியவில்லை"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" இணைய இணைப்பு மோசமாக உள்ளது."</string>
+    <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
+    <skip />
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"இணைப்பை அனுமதிக்கவா?"</string>
     <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%2$s வைஃபை நெட்வொர்க்குடன், %1$s பயன்பாடு இணைக்க விரும்புகிறது"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"ஒரு பயன்பாடு"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 0eefec9..9a0eafd 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3021,6 +3021,12 @@
         <!-- Whether this View should use a default focus highlight when it gets focused but
              doesn't have {@link android.R.attr#state_focused} defined in its background. -->
         <attr name="defaultFocusHighlightEnabled" format="boolean" />
+
+        <!-- Whether this view should be treated as a focusable unit by screen reader accessibility
+             tools. See {@link android.view.View#setScreenReaderFocusable(boolean)}. The default
+             value, {@code false}, leaves the screen reader to consider other signals, such as
+             focusability or the presence of text, to decide what it focus.-->
+        <attr name="screenReaderFocusable" format="boolean" />
     </declare-styleable>
 
     <!-- Attributes that can be assigned to a tag for a particular View. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index d3533fe..812595d 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2852,6 +2852,7 @@
       <public name="compileSdkVersion" />
       <!-- @hide For use by platform and tools only. Developers should not specify this value. -->
       <public name="compileSdkVersionCodename" />
+      <public name="screenReaderFocusable" />
     </public-group>
 
     <public-group type="style" first-id="0x010302e0">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 999ba73..e4310e1 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4373,7 +4373,7 @@
     <string name="package_deleted_device_owner">Deleted by your admin</string>
 
     <!-- [CHAR_LIMIT=NONE] Battery saver: Feature description -->
-    <string name="battery_saver_description">To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services, and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging.</string>
+    <string name="battery_saver_description">To help improve battery life, Battery Saver reduces your device’s performance and limits vibration, location services, and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery Saver turns off automatically when your device is charging.</string>
 
     <!-- [CHAR_LIMIT=NONE] Data saver: Feature description -->
     <string name="data_saver_description">To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them.</string>
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 51bfc20..3f2a46a 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -68,6 +68,7 @@
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
     <uses-permission android:name="android.permission.WRITE_SMS"/>
     <uses-permission android:name="android.permission.TEST_GRANTED" />
+    <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
     <uses-permission android:name="com.google.android.googleapps.permission.ACCESS_GOOGLE_PASSWORD" />
     <uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH" />
     <uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH.ALL_SERVICES" />
diff --git a/core/tests/coretests/AndroidTest.xml b/core/tests/coretests/AndroidTest.xml
index 23d70b8..970a0f0 100644
--- a/core/tests/coretests/AndroidTest.xml
+++ b/core/tests/coretests/AndroidTest.xml
@@ -16,6 +16,7 @@
 <configuration description="Runs Frameworks Core Tests.">
     <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
         <option name="test-file-name" value="FrameworksCoreTests.apk" />
+        <option name="test-file-name" value="BstatsTestApp.apk" />
     </target_preparer>
 
     <option name="test-suite-tag" value="apct" />
diff --git a/core/tests/coretests/BstatsTestApp/Android.mk b/core/tests/coretests/BstatsTestApp/Android.mk
new file mode 100644
index 0000000..6280257
--- /dev/null
+++ b/core/tests/coretests/BstatsTestApp/Android.mk
@@ -0,0 +1,32 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
+LOCAL_STATIC_JAVA_LIBRARIES := coretests-aidl
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := BstatsTestApp
+LOCAL_CERTIFICATE := platform
+LOCAL_DEX_PREOPT := false
+LOCAL_PROGUARD_ENABLED := disabled
+
+include $(BUILD_PACKAGE)
\ No newline at end of file
diff --git a/core/tests/coretests/BstatsTestApp/AndroidManifest.xml b/core/tests/coretests/BstatsTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..0cb5498
--- /dev/null
+++ b/core/tests/coretests/BstatsTestApp/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.coretests.apps.bstatstestapp">
+
+    <application>
+        <activity android:name=".TestActivity"
+                  android:exported="true" />
+        <service android:name=".IsolatedTestService"
+                 android:exported="true"
+                 android:isolatedProcess="true" />
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/IsolatedTestService.java b/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/IsolatedTestService.java
new file mode 100644
index 0000000..1f5f397
--- /dev/null
+++ b/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/IsolatedTestService.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.coretests.apps.bstatstestapp;
+
+import com.android.frameworks.coretests.aidl.ICmdReceiver;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.SystemClock;
+import android.util.Log;
+
+public class IsolatedTestService extends Service {
+    private static final String TAG = IsolatedTestService.class.getName();
+
+    @Override
+    public void onCreate() {
+        Log.d(TAG, "onCreate called. myUid=" + Process.myUid());
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mReceiver.asBinder();
+    }
+
+    private ICmdReceiver mReceiver = new ICmdReceiver.Stub() {
+        @Override
+        public void doSomeWork(int durationMs) {
+            final long endTime = SystemClock.uptimeMillis() + durationMs;
+            double x;
+            double y;
+            double z;
+            while (SystemClock.uptimeMillis() <= endTime) {
+                x = 0.02;
+                x *= 1000;
+                y = x % 5;
+                z = Math.sqrt(y / 100);
+            }
+        };
+
+        @Override
+        public void finishHost() {
+            stopSelf();
+        }
+    };
+}
diff --git a/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestActivity.java b/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestActivity.java
new file mode 100644
index 0000000..87b14d9
--- /dev/null
+++ b/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestActivity.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.coretests.apps.bstatstestapp;
+
+import com.android.frameworks.coretests.aidl.ICmdCallback;
+import com.android.frameworks.coretests.aidl.ICmdReceiver;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.Log;
+
+public class TestActivity extends Activity {
+    private static final String TAG = TestActivity.class.getName();
+
+    private static final String EXTRA_KEY_CMD_RECEIVER = "cmd_receiver";
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        Log.d(TAG, "onCreate called");
+        notifyActivityLaunched();
+    }
+
+    private void notifyActivityLaunched() {
+        if (getIntent() == null) {
+            return;
+        }
+
+        final Bundle extras = getIntent().getExtras();
+        if (extras == null) {
+            return;
+        }
+        final ICmdCallback callback = ICmdCallback.Stub.asInterface(
+                extras.getBinder(EXTRA_KEY_CMD_RECEIVER));
+        try {
+            callback.onActivityLaunched(mReceiver.asBinder());
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error occured while notifying the test: " + e);
+        }
+    }
+
+    @Override
+    public void finish() {
+        super.finish();
+        Log.d(TAG, "finish called");
+    }
+
+    private ICmdReceiver mReceiver = new ICmdReceiver.Stub() {
+        @Override
+        public void doSomeWork(int durationMs) {
+            final long endTime = SystemClock.uptimeMillis() + durationMs;
+            double x;
+            double y;
+            double z;
+            while (SystemClock.uptimeMillis() <= endTime) {
+                x = 0.02;
+                x *= 1000;
+                y = x % 5;
+                z = Math.sqrt(y / 100);
+            }
+        };
+
+        @Override
+        public void finishHost() {
+            finish();
+        }
+    };
+}
diff --git a/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/ICmdCallback.aidl b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/ICmdCallback.aidl
new file mode 100644
index 0000000..53a181a
--- /dev/null
+++ b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/ICmdCallback.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworks.coretests.aidl;
+
+interface ICmdCallback {
+    void onActivityLaunched(IBinder receiver);
+}
\ No newline at end of file
diff --git a/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/ICmdReceiver.aidl b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/ICmdReceiver.aidl
new file mode 100644
index 0000000..c406570
--- /dev/null
+++ b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/ICmdReceiver.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworks.coretests.aidl;
+
+interface ICmdReceiver {
+    void doSomeWork(int durationMs);
+    void finishHost();
+}
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 0d35f4e..454d209 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -26,6 +26,7 @@
 import static java.lang.reflect.Modifier.isPublic;
 import static java.lang.reflect.Modifier.isStatic;
 
+import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
@@ -37,6 +38,7 @@
 import java.util.Set;
 
 /** Tests that ensure appropriate settings are backed up. */
+@Presubmit
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class SettingsBackupTest {
@@ -52,6 +54,7 @@
                     Settings.System.ALARM_ALERT, // backup candidate?
                     Settings.System.ALARM_ALERT_CACHE, // internal cache
                     Settings.System.APPEND_FOR_LAST_AUDIBLE, // suffix deprecated since API 2
+                    Settings.System.DISPLAY_COLOR_MODE, // bug?
                     Settings.System.EGG_MODE, // I am the lolrus
                     Settings.System.END_BUTTON_BEHAVIOR, // bug?
                     Settings.System
@@ -108,11 +111,13 @@
                     Settings.Global.BACKUP_REFACTORED_SERVICE_DISABLED,
                     Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD,
                     Settings.Global.BATTERY_DISCHARGE_THRESHOLD,
+                    Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS,
                     Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE,
                     Settings.Global.BLUETOOTH_A2DP_SINK_PRIORITY_PREFIX,
                     Settings.Global.BLUETOOTH_A2DP_SRC_PRIORITY_PREFIX,
                     Settings.Global.BLUETOOTH_A2DP_SUPPORTS_OPTIONAL_CODECS_PREFIX,
                     Settings.Global.BLUETOOTH_A2DP_OPTIONAL_CODECS_ENABLED_PREFIX,
+                    Settings.Global.BLUETOOTH_CLASS_OF_DEVICE,
                     Settings.Global.BLUETOOTH_DISABLED_PROFILES,
                     Settings.Global.BLUETOOTH_HEADSET_PRIORITY_PREFIX,
                     Settings.Global.BLUETOOTH_INPUT_DEVICE_PRIORITY_PREFIX,
@@ -122,6 +127,7 @@
                     Settings.Global.BLUETOOTH_PAN_PRIORITY_PREFIX,
                     Settings.Global.BLUETOOTH_PBAP_CLIENT_PRIORITY_PREFIX,
                     Settings.Global.BLUETOOTH_SAP_PRIORITY_PREFIX,
+                    Settings.Global.BLUETOOTH_HEARING_AID_PRIORITY_PREFIX,
                     Settings.Global.BOOT_COUNT,
                     Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL,
                     Settings.Global.CAPTIVE_PORTAL_HTTPS_URL,
@@ -296,6 +302,7 @@
                     Settings.Global.POLICY_CONTROL,
                     Settings.Global.POWER_MANAGER_CONSTANTS,
                     Settings.Global.PREFERRED_NETWORK_MODE,
+                    Settings.Global.PRIV_APP_OOB_ENABLED,
                     Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS,
                     Settings.Global.RADIO_BLUETOOTH,
                     Settings.Global.RADIO_CELL,
@@ -411,6 +418,7 @@
     private static final Set<String> BACKUP_BLACKLISTED_SECURE_SETTINGS =
              newHashSet(
                  Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
+                 Settings.Secure.AUTOFILL_FEATURE_FIELD_DETECTION,
                  Settings.Secure.ALLOWED_GEOLOCATION_ORIGINS,
                  Settings.Secure.ALWAYS_ON_VPN_APP,
                  Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN,
diff --git a/core/tests/coretests/src/android/view/DisplayCutoutTest.java b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
new file mode 100644
index 0000000..6dd787d
--- /dev/null
+++ b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import static android.view.DisplayCutout.NO_CUTOUT;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.Parcel;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.DisplayCutout.ParcelableWrapper;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class DisplayCutoutTest {
+
+    /** This is not a consistent cutout. Useful for verifying insets in one go though. */
+    final DisplayCutout mCutoutNumbers = new DisplayCutout(
+            new Rect(1, 2, 3, 4),
+            new Rect(5, 6, 7, 8),
+            Arrays.asList(
+                    new Point(9, 10),
+                    new Point(11, 12),
+                    new Point(13, 14),
+                    new Point(15, 16)));
+
+    final DisplayCutout mCutoutTop = createCutoutTop();
+
+    @Test
+    public void hasCutout() throws Exception {
+        assertFalse(NO_CUTOUT.hasCutout());
+        assertTrue(mCutoutTop.hasCutout());
+    }
+
+    @Test
+    public void getSafeInsets() throws Exception {
+        assertEquals(1, mCutoutNumbers.getSafeInsetLeft());
+        assertEquals(2, mCutoutNumbers.getSafeInsetTop());
+        assertEquals(3, mCutoutNumbers.getSafeInsetRight());
+        assertEquals(4, mCutoutNumbers.getSafeInsetBottom());
+
+        Rect safeInsets = new Rect();
+        mCutoutNumbers.getSafeInsets(safeInsets);
+
+        assertEquals(new Rect(1, 2, 3, 4), safeInsets);
+    }
+
+    @Test
+    public void getBoundingRect() throws Exception {
+        Rect boundingRect = new Rect();
+        mCutoutTop.getBoundingRect(boundingRect);
+
+        assertEquals(new Rect(50, 0, 75, 100), boundingRect);
+    }
+
+    @Test
+    public void getBoundingPolygon() throws Exception {
+        ArrayList<Point> boundingPolygon = new ArrayList<>();
+        mCutoutTop.getBoundingPolygon(boundingPolygon);
+
+        assertEquals(Arrays.asList(
+                new Point(75, 0),
+                new Point(50, 0),
+                new Point(75, 100),
+                new Point(50, 100)), boundingPolygon);
+    }
+
+    @Test
+    public void testHashCode() throws Exception {
+        assertEquals(mCutoutTop.hashCode(), createCutoutTop().hashCode());
+        assertNotEquals(mCutoutTop.hashCode(), mCutoutNumbers.hashCode());
+    }
+
+    @Test
+    public void testEquals() throws Exception {
+        assertEquals(mCutoutTop, createCutoutTop());
+        assertNotEquals(mCutoutTop, mCutoutNumbers);
+    }
+
+    @Test
+    public void testToString() throws Exception {
+        assertFalse(mCutoutTop.toString().isEmpty());
+        assertFalse(mCutoutNumbers.toString().isEmpty());
+    }
+
+    @Test
+    public void inset_immutable() throws Exception {
+        DisplayCutout cutout = mCutoutTop.inset(1, 2, 3, 4);
+
+        assertEquals("original instance must not be mutated", createCutoutTop(), mCutoutTop);
+    }
+
+    @Test
+    public void inset_insets_withLeftCutout() throws Exception {
+        DisplayCutout cutout = createCutoutWithInsets(100, 0, 0, 0).inset(1, 2, 3, 4);
+
+        assertEquals(cutout.getSafeInsetLeft(), 99);
+        assertEquals(cutout.getSafeInsetTop(), 0);
+        assertEquals(cutout.getSafeInsetRight(), 0);
+        assertEquals(cutout.getSafeInsetBottom(), 0);
+    }
+
+    @Test
+    public void inset_insets_withTopCutout() throws Exception {
+        DisplayCutout cutout = mCutoutTop.inset(1, 2, 3, 4);
+
+        assertEquals(cutout.getSafeInsetLeft(), 0);
+        assertEquals(cutout.getSafeInsetTop(), 98);
+        assertEquals(cutout.getSafeInsetRight(), 0);
+        assertEquals(cutout.getSafeInsetBottom(), 0);
+    }
+
+    @Test
+    public void inset_insets_withRightCutout() throws Exception {
+        DisplayCutout cutout = createCutoutWithInsets(0, 0, 100, 0).inset(1, 2, 3, 4);
+
+        assertEquals(cutout.getSafeInsetLeft(), 0);
+        assertEquals(cutout.getSafeInsetTop(), 0);
+        assertEquals(cutout.getSafeInsetRight(), 97);
+        assertEquals(cutout.getSafeInsetBottom(), 0);
+    }
+
+    @Test
+    public void inset_insets_withBottomCutout() throws Exception {
+        DisplayCutout cutout = createCutoutWithInsets(0, 0, 0, 100).inset(1, 2, 3, 4);
+
+        assertEquals(cutout.getSafeInsetLeft(), 0);
+        assertEquals(cutout.getSafeInsetTop(), 0);
+        assertEquals(cutout.getSafeInsetRight(), 0);
+        assertEquals(cutout.getSafeInsetBottom(), 96);
+    }
+
+    @Test
+    public void inset_insets_consumeInset() throws Exception {
+        DisplayCutout cutout = mCutoutTop.inset(0, 1000, 0, 0);
+
+        assertEquals(cutout.getSafeInsetLeft(), 0);
+        assertEquals(cutout.getSafeInsetTop(), 0);
+        assertEquals(cutout.getSafeInsetRight(), 0);
+        assertEquals(cutout.getSafeInsetBottom(), 0);
+
+        assertFalse(cutout.hasCutout());
+    }
+
+    @Test
+    public void inset_bounds() throws Exception {
+        DisplayCutout cutout = mCutoutTop.inset(1, 2, 3, 4);
+
+        Rect boundingRect = new Rect();
+        cutout.getBoundingRect(boundingRect);
+
+        assertEquals(new Rect(49, -2, 74, 98), boundingRect);
+
+        ArrayList<Point> boundingPolygon = new ArrayList<>();
+        cutout.getBoundingPolygon(boundingPolygon);
+
+        assertEquals(Arrays.asList(
+                new Point(74, -2),
+                new Point(49, -2),
+                new Point(74, 98),
+                new Point(49, 98)), boundingPolygon);
+    }
+
+    @Test
+    public void calculateRelativeTo_top() throws Exception {
+        DisplayCutout cutout = mCutoutTop.calculateRelativeTo(new Rect(0, 0, 200, 400));
+
+        Rect insets = new Rect();
+        cutout.getSafeInsets(insets);
+
+        assertEquals(new Rect(0, 100, 0, 0), insets);
+    }
+
+    @Test
+    public void calculateRelativeTo_left() throws Exception {
+        DisplayCutout cutout = mCutoutTop.calculateRelativeTo(new Rect(0, 0, 400, 200));
+
+        Rect insets = new Rect();
+        cutout.getSafeInsets(insets);
+
+        assertEquals(new Rect(75, 0, 0, 0), insets);
+    }
+
+    @Test
+    public void calculateRelativeTo_bottom() throws Exception {
+        DisplayCutout cutout = mCutoutTop.calculateRelativeTo(new Rect(0, -300, 200, 100));
+
+        Rect insets = new Rect();
+        cutout.getSafeInsets(insets);
+
+        assertEquals(new Rect(0, 0, 0, 100), insets);
+    }
+
+    @Test
+    public void calculateRelativeTo_right() throws Exception {
+        DisplayCutout cutout = mCutoutTop.calculateRelativeTo(new Rect(-400, -200, 100, 100));
+
+        Rect insets = new Rect();
+        cutout.getSafeInsets(insets);
+
+        assertEquals(new Rect(0, 0, 50, 0), insets);
+    }
+
+    @Test
+    public void calculateRelativeTo_bounds() throws Exception {
+        DisplayCutout cutout = mCutoutTop.calculateRelativeTo(new Rect(-1000, -2000, 100, 200));
+
+
+        Rect boundingRect = new Rect();
+        cutout.getBoundingRect(boundingRect);
+        assertEquals(new Rect(1050, 2000, 1075, 2100), boundingRect);
+
+        ArrayList<Point> boundingPolygon = new ArrayList<>();
+        cutout.getBoundingPolygon(boundingPolygon);
+
+        assertEquals(Arrays.asList(
+                new Point(1075, 2000),
+                new Point(1050, 2000),
+                new Point(1075, 2100),
+                new Point(1050, 2100)), boundingPolygon);
+    }
+
+    @Test
+    public void fromBoundingPolygon() throws Exception {
+        assertEquals(
+                new DisplayCutout(
+                        new Rect(0, 0, 0, 0), // fromBoundingPolygon won't calculate safe insets.
+                        new Rect(50, 0, 75, 100),
+                        Arrays.asList(
+                                new Point(75, 0),
+                                new Point(50, 0),
+                                new Point(75, 100),
+                                new Point(50, 100))),
+                DisplayCutout.fromBoundingPolygon(
+                        Arrays.asList(
+                                new Point(75, 0),
+                                new Point(50, 0),
+                                new Point(75, 100),
+                                new Point(50, 100))));
+    }
+
+    @Test
+    public void parcel_unparcel_regular() {
+        Parcel p = Parcel.obtain();
+
+        new ParcelableWrapper(mCutoutTop).writeToParcel(p, 0);
+        int posAfterWrite = p.dataPosition();
+
+        p.setDataPosition(0);
+
+        assertEquals(mCutoutTop, ParcelableWrapper.CREATOR.createFromParcel(p).get());
+        assertEquals(posAfterWrite, p.dataPosition());
+    }
+
+    @Test
+    public void parcel_unparcel_nocutout() {
+        Parcel p = Parcel.obtain();
+
+        new ParcelableWrapper(NO_CUTOUT).writeToParcel(p, 0);
+        int posAfterWrite = p.dataPosition();
+
+        p.setDataPosition(0);
+
+        assertEquals(NO_CUTOUT, ParcelableWrapper.CREATOR.createFromParcel(p).get());
+        assertEquals(posAfterWrite, p.dataPosition());
+    }
+
+    @Test
+    public void parcel_unparcel_inplace() {
+        Parcel p = Parcel.obtain();
+
+        new ParcelableWrapper(mCutoutTop).writeToParcel(p, 0);
+        int posAfterWrite = p.dataPosition();
+
+        p.setDataPosition(0);
+
+        ParcelableWrapper wrapper = new ParcelableWrapper();
+        wrapper.readFromParcel(p);
+
+        assertEquals(mCutoutTop, wrapper.get());
+        assertEquals(posAfterWrite, p.dataPosition());
+    }
+
+    @Test
+    public void wrapper_hashcode() throws Exception {
+        assertEquals(new ParcelableWrapper(mCutoutTop).hashCode(),
+                new ParcelableWrapper(createCutoutTop()).hashCode());
+        assertNotEquals(new ParcelableWrapper(mCutoutTop).hashCode(),
+                new ParcelableWrapper(mCutoutNumbers).hashCode());
+    }
+
+    @Test
+    public void wrapper_equals() throws Exception {
+        assertEquals(new ParcelableWrapper(mCutoutTop), new ParcelableWrapper(createCutoutTop()));
+        assertNotEquals(new ParcelableWrapper(mCutoutTop), new ParcelableWrapper(mCutoutNumbers));
+    }
+
+    private static DisplayCutout createCutoutTop() {
+        return new DisplayCutout(
+                new Rect(0, 100, 0, 0),
+                new Rect(50, 0, 75, 100),
+                Arrays.asList(
+                        new Point(75, 0),
+                        new Point(50, 0),
+                        new Point(75, 100),
+                        new Point(50, 100)));
+    }
+
+    private static DisplayCutout createCutoutWithInsets(int left, int top, int right, int bottom) {
+        return new DisplayCutout(
+                new Rect(left, top, right, bottom),
+                new Rect(50, 0, 75, 100),
+                Arrays.asList(
+                        new Point(75, 0),
+                        new Point(50, 0),
+                        new Point(75, 100),
+                        new Point(50, 100)));
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
new file mode 100644
index 0000000..682a002
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
@@ -0,0 +1,399 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.os;
+
+import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+
+import static org.junit.Assume.assumeTrue;
+
+import com.android.frameworks.coretests.aidl.ICmdCallback;
+import com.android.frameworks.coretests.aidl.ICmdReceiver;
+
+import android.app.KeyguardManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.os.BatteryManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.os.Process;
+import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.uiautomator.UiDevice;
+import android.util.Log;
+
+import org.junit.Assume;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class BstatsCpuTimesValidationTest {
+    private static final String TAG = BstatsCpuTimesValidationTest.class.getName();
+
+    private static final String TEST_PKG = "com.android.coretests.apps.bstatstestapp";
+    private static final String TEST_ACTIVITY = TEST_PKG + ".TestActivity";
+    private static final String ISOLATED_TEST_SERVICE = TEST_PKG + ".IsolatedTestService";
+
+    private static final String EXTRA_KEY_CMD_RECEIVER = "cmd_receiver";
+
+    private static final int BATTERY_STATE_TIMEOUT_MS = 2000;
+    private static final int BATTERY_STATE_CHECK_INTERVAL_MS = 200;
+
+    private static final int START_ACTIVITY_TIMEOUT_MS = 2000;
+    private static final int START_ISOLATED_SERVICE_TIMEOUT_MS = 2000;
+
+    private static final int GENERAL_TIMEOUT_MS = 1000;
+    private static final int GENERAL_INTERVAL_MS = 100;
+
+    private static final int WORK_DURATION_MS = 2000;
+
+    private static Context sContext;
+    private static UiDevice sUiDevice;
+    private static int sTestPkgUid;
+    private static boolean sCpuFreqTimesAvailable;
+
+    @BeforeClass
+    public static void setupOnce() throws Exception {
+        sContext = InstrumentationRegistry.getContext();
+        sUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+        sContext.getPackageManager().setApplicationEnabledSetting(TEST_PKG,
+                PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
+        sTestPkgUid = sContext.getPackageManager().getPackageUid(TEST_PKG, 0);
+        sCpuFreqTimesAvailable = cpuFreqTimesAvailable();
+    }
+
+    // Checks cpu freq times of system uid as an indication of whether /proc/uid_time_in_state
+    // kernel node is available.
+    private static boolean cpuFreqTimesAvailable() throws Exception {
+        final long[] cpuTimes = getAllCpuFreqTimes(Process.SYSTEM_UID);
+        return cpuTimes != null;
+    }
+
+    @Test
+    public void testCpuFreqTimes() throws Exception {
+        assumeTrue(sCpuFreqTimesAvailable);
+
+        batteryOnScreenOn();
+        forceStop();
+        resetBatteryStats();
+        final long[] initialSnapshot = getAllCpuFreqTimes(sTestPkgUid);
+        assertNull("Initial snapshot should be null", initialSnapshot);
+        doSomeWork();
+        forceStop();
+
+        final long[] cpuTimesMs = getAllCpuFreqTimes(sTestPkgUid);
+        assertCpuTimesValid(cpuTimesMs);
+        long actualCpuTimeMs = 0;
+        for (int i = 0; i < cpuTimesMs.length / 2; ++i) {
+            actualCpuTimeMs += cpuTimesMs[i];
+        }
+        assertApproximateValue("Incorrect total cpu time", WORK_DURATION_MS, actualCpuTimeMs);
+        batteryOffScreenOn();
+    }
+
+    @Test
+    public void testCpuFreqTimes_screenOff() throws Exception {
+        assumeTrue(sCpuFreqTimesAvailable);
+
+        batteryOnScreenOff();
+        forceStop();
+        resetBatteryStats();
+        final long[] initialSnapshot = getAllCpuFreqTimes(sTestPkgUid);
+        assertNull("Initial snapshot should be null", initialSnapshot);
+        doSomeWork();
+        forceStop();
+
+        final long[] cpuTimesMs = getAllCpuFreqTimes(sTestPkgUid);
+        assertCpuTimesValid(cpuTimesMs);
+        long actualTotalCpuTimeMs = 0;
+        for (int i = 0; i < cpuTimesMs.length / 2; ++i) {
+            actualTotalCpuTimeMs += cpuTimesMs[i];
+        }
+        assertApproximateValue("Incorrect total cpu time", WORK_DURATION_MS, actualTotalCpuTimeMs);
+        long actualScreenOffCpuTimeMs = 0;
+        for (int i = cpuTimesMs.length / 2; i < cpuTimesMs.length; ++i) {
+            actualScreenOffCpuTimeMs += cpuTimesMs[i];
+        }
+        assertApproximateValue("Incorrect screen-off cpu time",
+                WORK_DURATION_MS, actualScreenOffCpuTimeMs);
+        batteryOffScreenOn();
+    }
+
+    @Test
+    public void testCpuFreqTimes_isolatedProcess() throws Exception {
+        assumeTrue(sCpuFreqTimesAvailable);
+
+        batteryOnScreenOn();
+        forceStop();
+        resetBatteryStats();
+        final long[] initialSnapshot = getAllCpuFreqTimes(sTestPkgUid);
+        assertNull("Initial snapshot should be null", initialSnapshot);
+        doSomeWorkInIsolatedProcess();
+        forceStop();
+
+        final long[] cpuTimesMs = getAllCpuFreqTimes(sTestPkgUid);
+        assertCpuTimesValid(cpuTimesMs);
+        long actualCpuTimeMs = 0;
+        for (int i = 0; i < cpuTimesMs.length / 2; ++i) {
+            actualCpuTimeMs += cpuTimesMs[i];
+        }
+        assertApproximateValue("Incorrect total cpu time", WORK_DURATION_MS, actualCpuTimeMs);
+        batteryOffScreenOn();
+    }
+
+    private void assertCpuTimesValid(long[] cpuTimes) {
+        assertNotNull(cpuTimes);
+        for (int i = 0; i < cpuTimes.length; ++i) {
+            if (cpuTimes[i] < 0) {
+                fail("Malformed cpu times data (-ve values): " + Arrays.toString(cpuTimes));
+            }
+        }
+        final int numFreqs = cpuTimes.length / 2;
+        for (int i = 0; i < numFreqs; ++i) {
+            if (cpuTimes[i] < cpuTimes[numFreqs + i]) {
+                fail("Malformed cpu times data (screen-off > total)" + Arrays.toString(cpuTimes));
+            }
+        }
+    }
+
+    private void assertApproximateValue(String errorPrefix, long expectedValue, long actualValue) {
+        assertValueRange(errorPrefix, actualValue, expectedValue * 0.5, expectedValue * 1.5);
+    }
+
+    private void assertValueRange(String errorPrefix,
+            long actualvalue, double minValue, double maxValue) {
+        final String errorMsg = String.format(errorPrefix + "; actual=%s; min=%s; max=%s",
+                actualvalue, minValue, maxValue);
+        assertTrue(errorMsg, actualvalue < maxValue);
+        assertTrue(errorMsg, actualvalue > minValue);
+    }
+
+    private void doSomeWork() throws Exception {
+        final ICmdReceiver receiver = ICmdReceiver.Stub.asInterface(startActivity());
+        receiver.doSomeWork(WORK_DURATION_MS);
+        receiver.finishHost();
+    }
+
+    private void doSomeWorkInIsolatedProcess() throws Exception {
+        final ICmdReceiver receiver = ICmdReceiver.Stub.asInterface(startIsolatedService());
+        receiver.doSomeWork(WORK_DURATION_MS);
+        receiver.finishHost();
+    }
+
+    private IBinder startIsolatedService() throws Exception {
+        final CountDownLatch latch = new CountDownLatch(1);
+        final IBinder[] binders = new IBinder[1];
+        final ServiceConnection connection = new ServiceConnection() {
+            @Override
+            public void onServiceConnected(ComponentName name, IBinder service) {
+                binders[0] = service;
+                latch.countDown();
+            }
+
+            @Override
+            public void onServiceDisconnected(ComponentName name) {
+            }
+        };
+        final Intent launchIntent = new Intent()
+                .setComponent(new ComponentName(TEST_PKG, ISOLATED_TEST_SERVICE));
+        sContext.bindService(launchIntent, connection, Context.BIND_AUTO_CREATE
+                | Context.BIND_ALLOW_OOM_MANAGEMENT | Context.BIND_NOT_FOREGROUND);
+        if (latch.await(START_ISOLATED_SERVICE_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+            if (binders[0] == null) {
+                fail("Receiver binder should not be null");
+            }
+            return binders[0];
+        } else {
+            fail("Timed out waiting for the isolated test service to start");
+        }
+        return null;
+    }
+
+    private IBinder startActivity() throws Exception {
+        final CountDownLatch latch = new CountDownLatch(1);
+        final Intent launchIntent = new Intent()
+                .setComponent(new ComponentName(TEST_PKG, TEST_ACTIVITY));
+        final Bundle extras = new Bundle();
+        final IBinder[] binders = new IBinder[1];
+        extras.putBinder(EXTRA_KEY_CMD_RECEIVER, new ICmdCallback.Stub() {
+            @Override
+            public void onActivityLaunched(IBinder receiver) {
+                binders[0] = receiver;
+                latch.countDown();
+            }
+        });
+        launchIntent.putExtras(extras);
+        sContext.startActivity(launchIntent);
+        if (latch.await(START_ACTIVITY_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+            if (binders[0] == null) {
+                fail("Receiver binder should not be null");
+            }
+            return binders[0];
+        } else {
+            fail("Timed out waiting for the test activity to start; testUid=" + sTestPkgUid);
+        }
+        return null;
+    }
+
+    private static long[] getAllCpuFreqTimes(int uid) throws Exception {
+        final String checkinDump = executeCmdSilent("dumpsys batterystats --checkin");
+        final Pattern pattern = Pattern.compile(uid + ",l,ctf,A,(.*?)\n");
+        final Matcher matcher = pattern.matcher(checkinDump);
+        if (!matcher.find()) {
+            return null;
+        }
+        final String[] uidTimesStr = matcher.group(1).split(",");
+        final int freqCount = Integer.parseInt(uidTimesStr[0]);
+        if (uidTimesStr.length != (2 * freqCount + 1)) {
+            fail("Malformed data: " + Arrays.toString(uidTimesStr));
+        }
+        final long[] cpuTimes = new long[freqCount * 2];
+        for (int i = 0; i < cpuTimes.length; ++i) {
+            cpuTimes[i] = Long.parseLong(uidTimesStr[i + 1]);
+        }
+        return cpuTimes;
+    }
+
+    private void resetBatteryStats() throws Exception {
+        executeCmd("dumpsys batterystats --reset");
+    }
+
+    private void batteryOnScreenOn() throws Exception {
+        batteryOn();
+        screenOn();
+    }
+
+    private void batteryOnScreenOff() throws Exception {
+        batteryOn();
+        screenoff();
+    }
+
+    private void batteryOffScreenOn() throws Exception {
+        batteryOff();
+        screenOn();
+    }
+
+    private void batteryOn() throws Exception {
+        executeCmd("dumpsys battery unplug");
+        assertBatteryState(false);
+    }
+
+    private void batteryOff() throws Exception {
+        executeCmd("dumpsys battery reset");
+        assertBatteryState(true);
+    }
+
+    private void screenOn() throws Exception {
+        executeCmd("input keyevent KEYCODE_WAKEUP");
+        executeCmd("wm dismiss-keyguard");
+        assertKeyguardUnLocked();
+        assertScreenInteractive(true);
+    }
+
+    private void screenoff() throws Exception {
+        executeCmd("input keyevent KEYCODE_SLEEP");
+        assertScreenInteractive(false);
+    }
+
+    private void forceStop() throws Exception {
+        executeCmd("cmd activity force-stop " + TEST_PKG);
+        assertUidState(PROCESS_STATE_NONEXISTENT);
+    }
+
+    private void assertUidState(int state) throws Exception {
+        final String uidStateStr = executeCmd("cmd activity get-uid-state " + sTestPkgUid);
+        final int uidState = Integer.parseInt(uidStateStr.split(" ")[0]);
+        assertEquals(state, uidState);
+    }
+
+    private void assertKeyguardUnLocked() {
+        final KeyguardManager keyguardManager =
+                (KeyguardManager) sContext.getSystemService(Context.KEYGUARD_SERVICE);
+        assertDelayedCondition("Keyguard should be unlocked",
+                () -> !keyguardManager.isKeyguardLocked());
+    }
+
+    private void assertScreenInteractive(boolean interactive) {
+        final PowerManager powerManager =
+                (PowerManager) sContext.getSystemService(Context.POWER_SERVICE);
+        assertDelayedCondition("Unexpected screen interactive state",
+                () -> interactive == powerManager.isInteractive());
+    }
+
+    private void assertDelayedCondition(String errorMsg, ExpectedCondition condition) {
+        final long endTime = SystemClock.uptimeMillis() + GENERAL_TIMEOUT_MS;
+        while (SystemClock.uptimeMillis() <= endTime) {
+            if (condition.isTrue()) {
+                return;
+            }
+            SystemClock.sleep(GENERAL_INTERVAL_MS);
+        }
+        if (!condition.isTrue()) {
+            fail(errorMsg);
+        }
+    }
+
+    private void assertBatteryState(boolean pluggedIn) throws Exception {
+        final long endTime = SystemClock.uptimeMillis() + BATTERY_STATE_TIMEOUT_MS;
+        while (isDevicePluggedIn() != pluggedIn && SystemClock.uptimeMillis() <= endTime) {
+            Thread.sleep(BATTERY_STATE_CHECK_INTERVAL_MS);
+        }
+        if (isDevicePluggedIn() != pluggedIn) {
+            fail("Timed out waiting for the plugged-in state to change,"
+                    + " expected pluggedIn: " + pluggedIn);
+        }
+    }
+
+    private boolean isDevicePluggedIn() {
+        final Intent batteryIntent = sContext.registerReceiver(null,
+                new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+        return batteryIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) > 0;
+    }
+
+    private String executeCmd(String cmd) throws Exception {
+        final String result = sUiDevice.executeShellCommand(cmd).trim();
+        Log.d(TAG, String.format("Result for '%s': %s", cmd, result));
+        return result;
+    }
+
+    private static String executeCmdSilent(String cmd) throws Exception {
+        return sUiDevice.executeShellCommand(cmd).trim();
+    }
+
+    private interface ExpectedCondition {
+        boolean isTrue();
+    }
+}
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index 158df13..da0205d 100644
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -47,12 +47,12 @@
 }
 
 std::unique_ptr<const ApkAssets> ApkAssets::Load(const std::string& path, bool system) {
-  return ApkAssets::LoadImpl(path, nullptr, nullptr, system, false /*load_as_shared_library*/);
+  return LoadImpl({} /*fd*/, path, nullptr, nullptr, system, false /*load_as_shared_library*/);
 }
 
 std::unique_ptr<const ApkAssets> ApkAssets::LoadAsSharedLibrary(const std::string& path,
                                                                 bool system) {
-  return ApkAssets::LoadImpl(path, nullptr, nullptr, system, true /*load_as_shared_library*/);
+  return LoadImpl({} /*fd*/, path, nullptr, nullptr, system, true /*load_as_shared_library*/);
 }
 
 std::unique_ptr<const ApkAssets> ApkAssets::LoadOverlay(const std::string& idmap_path,
@@ -70,8 +70,15 @@
     LOG(ERROR) << "failed to load IDMAP " << idmap_path;
     return {};
   }
-  return LoadImpl(loaded_idmap->OverlayApkPath(), std::move(idmap_asset), std::move(loaded_idmap),
-                  system, false /*load_as_shared_library*/);
+  return LoadImpl({} /*fd*/, loaded_idmap->OverlayApkPath(), std::move(idmap_asset),
+                  std::move(loaded_idmap), system, false /*load_as_shared_library*/);
+}
+
+std::unique_ptr<const ApkAssets> ApkAssets::LoadFromFd(unique_fd fd,
+                                                       const std::string& friendly_name,
+                                                       bool system, bool force_shared_lib) {
+  return LoadImpl(std::move(fd), friendly_name, nullptr /*idmap_asset*/, nullptr /*loaded_idmap*/,
+                  system, force_shared_lib);
 }
 
 std::unique_ptr<Asset> ApkAssets::CreateAssetFromFile(const std::string& path) {
@@ -96,11 +103,19 @@
 }
 
 std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(
-    const std::string& path, std::unique_ptr<Asset> idmap_asset,
+    unique_fd fd, const std::string& path, std::unique_ptr<Asset> idmap_asset,
     std::unique_ptr<const LoadedIdmap> loaded_idmap, bool system, bool load_as_shared_library) {
   ATRACE_CALL();
+
   ::ZipArchiveHandle unmanaged_handle;
-  int32_t result = ::OpenArchive(path.c_str(), &unmanaged_handle);
+  int32_t result;
+  if (fd >= 0) {
+    result =
+        ::OpenArchiveFd(fd.release(), path.c_str(), &unmanaged_handle, true /*assume_ownership*/);
+  } else {
+    result = ::OpenArchive(path.c_str(), &unmanaged_handle);
+  }
+
   if (result != 0) {
     LOG(ERROR) << "Failed to open APK '" << path << "' " << ::ErrorCodeString(result);
     return {};
diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h
index 3a307fc..69702e3 100644
--- a/libs/androidfw/include/androidfw/ApkAssets.h
+++ b/libs/androidfw/include/androidfw/ApkAssets.h
@@ -21,6 +21,7 @@
 #include <string>
 
 #include "android-base/macros.h"
+#include "android-base/unique_fd.h"
 
 #include "androidfw/Asset.h"
 #include "androidfw/LoadedArsc.h"
@@ -51,6 +52,16 @@
   static std::unique_ptr<const ApkAssets> LoadOverlay(const std::string& idmap_path,
                                                       bool system = false);
 
+  // Creates an ApkAssets from the given file descriptor, and takes ownership of the file
+  // descriptor. The `friendly_name` is some name that will be used to identify the source of
+  // this ApkAssets in log messages and other debug scenarios.
+  // If `system` is true, the package is marked as a system package, and allows some functions to
+  // filter out this package when computing what configurations/resources are available.
+  // If `force_shared_lib` is true, any package with ID 0x7f is loaded as a shared library.
+  static std::unique_ptr<const ApkAssets> LoadFromFd(base::unique_fd fd,
+                                                     const std::string& friendly_name, bool system,
+                                                     bool force_shared_lib);
+
   std::unique_ptr<Asset> Open(const std::string& path,
                               Asset::AccessMode mode = Asset::AccessMode::ACCESS_RANDOM) const;
 
@@ -69,7 +80,7 @@
  private:
   DISALLOW_COPY_AND_ASSIGN(ApkAssets);
 
-  static std::unique_ptr<const ApkAssets> LoadImpl(const std::string& path,
+  static std::unique_ptr<const ApkAssets> LoadImpl(base::unique_fd fd, const std::string& path,
                                                    std::unique_ptr<Asset> idmap_asset,
                                                    std::unique_ptr<const LoadedIdmap> loaded_idmap,
                                                    bool system, bool load_as_shared_library);
diff --git a/libs/androidfw/tests/ApkAssets_test.cpp b/libs/androidfw/tests/ApkAssets_test.cpp
index d65d93f..ba5844b 100644
--- a/libs/androidfw/tests/ApkAssets_test.cpp
+++ b/libs/androidfw/tests/ApkAssets_test.cpp
@@ -24,6 +24,7 @@
 #include "TestHelpers.h"
 #include "data/basic/R.h"
 
+using ::android::base::unique_fd;
 using ::com::android::basic::R;
 
 namespace android {
@@ -44,6 +45,26 @@
   ASSERT_NE(nullptr, asset);
 }
 
+TEST(ApkAssetsTest, LoadApkFromFd) {
+  const std::string path = GetTestDataPath() + "/basic/basic.apk";
+  unique_fd fd(::open(path.c_str(), O_RDONLY | O_BINARY));
+  ASSERT_GE(fd.get(), 0);
+
+  std::unique_ptr<const ApkAssets> loaded_apk =
+      ApkAssets::LoadFromFd(std::move(fd), path, false /*system*/, false /*force_shared_lib*/);
+  ASSERT_NE(nullptr, loaded_apk);
+
+  const LoadedArsc* loaded_arsc = loaded_apk->GetLoadedArsc();
+  ASSERT_NE(nullptr, loaded_arsc);
+
+  const LoadedPackage* loaded_package = loaded_arsc->GetPackageForId(0x7f010000);
+  ASSERT_NE(nullptr, loaded_package);
+  EXPECT_TRUE(loaded_package->IsVerified());
+
+  std::unique_ptr<Asset> asset = loaded_apk->Open("res/layout/main.xml");
+  ASSERT_NE(nullptr, asset);
+}
+
 TEST(ApkAssetsTest, LoadApkAsSharedLibrary) {
   std::unique_ptr<const ApkAssets> loaded_apk =
       ApkAssets::Load(GetTestDataPath() + "/appaslib/appaslib.apk");
@@ -132,7 +153,7 @@
   ASSERT_NE(nullptr, asset);
 
   off64_t start, length;
-  base::unique_fd fd(asset->openFileDescriptor(&start, &length));
+  unique_fd fd(asset->openFileDescriptor(&start, &length));
   EXPECT_GE(fd.get(), 0);
 
   lseek64(fd.get(), start, SEEK_SET);
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 6c87a9d..143182f 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -1586,8 +1586,10 @@
      * @param info The TV input which will use the acquired Hardware.
      * @return Hardware on success, {@code null} otherwise.
      *
+     * @hide
      * @removed
      */
+    @SystemApi
     @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
     public Hardware acquireTvInputHardware(int deviceId, final HardwareCallback callback,
             TvInputInfo info) {
diff --git a/packages/MtpDocumentsProvider/res/values-hi/strings.xml b/packages/MtpDocumentsProvider/res/values-hi/strings.xml
index 6aceb95..bbd0ae7 100644
--- a/packages/MtpDocumentsProvider/res/values-hi/strings.xml
+++ b/packages/MtpDocumentsProvider/res/values-hi/strings.xml
@@ -20,6 +20,6 @@
     <string name="downloads_app_label" msgid="7120690641874849726">"डाउनलोड"</string>
     <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
     <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> से फ़ाइलें एक्सेस कर रहा है"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"दूसरा डिवाइस व्यस्त है. आप उसके उपलब्ध हो जाने तक फ़ाइलें स्थानांतरित नहीं कर सकते हैं."</string>
+    <string name="error_busy_device" msgid="3997316850357386589">"दूसरा डिवाइस व्यस्त है. आप उसके उपलब्ध हो जाने तक फ़ाइलें ट्रांसफ़र नहीं कर सकते."</string>
     <string name="error_locked_device" msgid="7557872102188356147">"कोई फ़ाइल नहीं मिली. हो सकता है कि दूसरा डिवाइस लॉक हो. अगर ऐसा है, तो उसे अनलॉक करें और दोबारा कोशिश करें."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-bn/strings.xml b/packages/PrintSpooler/res/values-bn/strings.xml
index d2751f1..cd74d22 100644
--- a/packages/PrintSpooler/res/values-bn/strings.xml
+++ b/packages/PrintSpooler/res/values-bn/strings.xml
@@ -27,7 +27,7 @@
     <string name="label_duplex" msgid="5370037254347072243">"দ্বিভুজ"</string>
     <string name="label_orientation" msgid="2853142581990496477">"সজ্জা"</string>
     <string name="label_pages" msgid="7768589729282182230">"পৃষ্ঠাগুলি"</string>
-    <string name="destination_default_text" msgid="5422708056807065710">"একটি মুদ্রক বেছে নিন"</string>
+    <string name="destination_default_text" msgid="5422708056807065710">"একটি প্রিন্টার বেছে নিন"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"সমস্ত <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
     <string name="template_page_range" msgid="428638530038286328">"<xliff:g id="PAGE_COUNT">%1$s</xliff:g> এর পরিসর"</string>
     <string name="pages_range_example" msgid="8558694453556945172">"যেমন, ১—৫,৮,১১—১৩"</string>
@@ -36,7 +36,7 @@
     <string name="printing_app_crashed" msgid="854477616686566398">"প্রিন্ট অ্যাপ্লিকেশান ক্র্যাশ করছে"</string>
     <string name="generating_print_job" msgid="3119608742651698916">"প্রিন্ট কার্য তৈরি করা হচ্ছে"</string>
     <string name="save_as_pdf" msgid="5718454119847596853">"পিডিএফ হিসাবে সেভ করুন"</string>
-    <string name="all_printers" msgid="5018829726861876202">"সমস্ত মুদ্রক…"</string>
+    <string name="all_printers" msgid="5018829726861876202">"সমস্ত প্রিন্টার…"</string>
     <string name="print_dialog" msgid="32628687461331979">"প্রিন্ট ডায়লগ"</string>
     <string name="current_page_template" msgid="5145005201131935302">"<xliff:g id="CURRENT_PAGE">%1$d</xliff:g>/<xliff:g id="PAGE_COUNT">%2$d</xliff:g>"</string>
     <string name="page_description_template" msgid="6831239682256197161">"<xliff:g id="PAGE_COUNT">%2$d</xliff:g>টির মধ্যে <xliff:g id="CURRENT_PAGE">%1$d</xliff:g> নম্বর পৃষ্ঠা"</string>
@@ -48,16 +48,16 @@
     <string name="print_options_expanded" msgid="6944679157471691859">"প্রিন্ট বিকল্প প্রসারিত হয়েছে"</string>
     <string name="print_options_collapsed" msgid="7455930445670414332">"প্রিন্ট বিকল্প সংকুচিত হয়েছে"</string>
     <string name="search" msgid="5421724265322228497">"খুঁজুন"</string>
-    <string name="all_printers_label" msgid="3178848870161526399">"সমস্ত মুদ্রক"</string>
+    <string name="all_printers_label" msgid="3178848870161526399">"সমস্ত প্রিন্টার"</string>
     <string name="add_print_service_label" msgid="5356702546188981940">"পরিষেবা যোগ করুন"</string>
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"অনুসন্ধান বাক্স দেখানো হচ্ছে"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"অনুসন্ধান বাক্স লুকানো রয়েছে"</string>
-    <string name="print_add_printer" msgid="1088656468360653455">"মুদ্রক যোগ করুন"</string>
-    <string name="print_select_printer" msgid="7388760939873368698">"মুদ্রক বেছে নিন"</string>
+    <string name="print_add_printer" msgid="1088656468360653455">"প্রিন্টার যোগ করুন"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"প্রিন্টার বেছে নিন"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"মুদ্রকটিকে সরিয়ে দিন"</string>
     <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
-      <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g>টি মুদ্রক খুঁজে পাওয়া গেছে</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g>টি মুদ্রক খুঁজে পাওয়া গেছে</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g>টি প্রিন্টার খুঁজে পাওয়া গেছে</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g>টি প্রিন্টার খুঁজে পাওয়া গেছে</item>
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"এই মুদ্রকটির বিষয়ে আরও তথ্য"</string>
@@ -67,22 +67,22 @@
     <string name="print_services_disabled_toast" msgid="9089060734685174685">"কিছু প্রিন্ট পরিষেবা অক্ষম করা আছে"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"মুদ্রকগুলি অনুসন্ধান করা হচ্ছে"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"প্রিন্ট পরিষেবা সক্ষম নেই"</string>
-    <string name="print_no_printers" msgid="4869403323900054866">"কোনো মুদ্রক পাওয়া যায়নি"</string>
+    <string name="print_no_printers" msgid="4869403323900054866">"কোনো প্রিন্টার পাওয়া যায়নি"</string>
     <string name="cannot_add_printer" msgid="7840348733668023106">"মুদ্রকগুলি যোগ করা যাবে না"</string>
-    <string name="select_to_add_printers" msgid="3800709038689830974">"মুদ্রক যোগ করতে বেছে নিন"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"প্রিন্টার যোগ করতে বেছে নিন"</string>
     <string name="enable_print_service" msgid="3482815747043533842">"সক্ষম করতে বেছে নিন"</string>
     <string name="enabled_services_title" msgid="7036986099096582296">"সক্ষম করা পরিষেবাগুলি"</string>
     <string name="recommended_services_title" msgid="3799434882937956924">"প্রস্তাবিত পরিষেবাগুলি"</string>
     <string name="disabled_services_title" msgid="7313253167968363211">"অক্ষম করা পরিষেবাগুলি"</string>
     <string name="all_services_title" msgid="5578662754874906455">"সমস্ত পরিষেবা"</string>
     <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
-      <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g>টি মুদ্রক খুঁজে পেতে ইনস্টল করুন</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g>টি মুদ্রক খুঁজে পেতে ইনস্টল করুন</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g>টি প্রিন্টার খুঁজে পেতে ইনস্টল করুন</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g>টি প্রিন্টার খুঁজে পেতে ইনস্টল করুন</item>
     </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> প্রিন্ট করা হচ্ছে"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> বাতিল করা হচ্ছে"</string>
-    <string name="failed_notification_title_template" msgid="2256217208186530973">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> মুদ্রক ত্রুটি"</string>
-    <string name="blocked_notification_title_template" msgid="1175435827331588646">"মুদ্রক <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> অবরুদ্ধ করেছে"</string>
+    <string name="failed_notification_title_template" msgid="2256217208186530973">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> প্রিন্টার ত্রুটি"</string>
+    <string name="blocked_notification_title_template" msgid="1175435827331588646">"প্রিন্টার <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> অবরুদ্ধ করেছে"</string>
     <string name="cancel" msgid="4373674107267141885">"বাতিল করুন"</string>
     <string name="restart" msgid="2472034227037808749">"রিস্টার্ট করুন"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"মুদ্রকে কোনো সংযোগ নেই"</string>
diff --git a/packages/SettingsLib/res/layout/preference_dropdown_material_settings.xml b/packages/SettingsLib/res/layout/preference_dropdown_material_settings.xml
deleted file mode 100644
index a0b8155..0000000
--- a/packages/SettingsLib/res/layout/preference_dropdown_material_settings.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2017 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-
-<!-- Based off frameworks/base/core/res/res/layout/preference_dropdown_material.xml
-     except that icon space in this layout is always reserved -->
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content">
-
-    <Spinner
-        android:id="@+id/spinner"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="@dimen/preference_no_icon_padding_start"
-        android:visibility="invisible" />
-
-    <include layout="@layout/preference_material"/>
-
-</FrameLayout>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index b2afcb5..75a0a42 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -33,13 +33,15 @@
     <string name="wifi_check_password_try_again" msgid="516958988102584767">"পাসওয়ার্ড দেখে আবার চেষ্টা করুন"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"পরিসরের মধ্যে নয়"</string>
     <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"স্বয়ংক্রিয়ভাবে সংযোগ করবে না"</string>
-    <string name="wifi_no_internet" msgid="3880396223819116454">"কোনো ইন্টারনেট অ্যাক্সেস নেই"</string>
+    <!-- no translation found for wifi_no_internet (4663834955626848401) -->
+    <skip />
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> দ্বারা সেভ করা"</string>
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"স্বয়ংক্রিয়ভাবে %1$s এর মাধ্যমে সংযুক্ত হয়েছে"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"নেটওয়ার্কের রেটিং প্রদানকারীর মাধ্যমে স্বয়ংক্রিয়ভাবে সংযুক্ত"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s মাধ্যমে সংযুক্ত হয়েছে"</string>
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s এর মাধ্যমে উপলব্ধ"</string>
-    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"সংযুক্ত, ইন্টারনেট নেই"</string>
+    <!-- no translation found for wifi_connected_no_internet (8202906332837777829) -->
+    <skip />
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"এই মুহূর্তে অ্যাক্সেস পয়েন্টের কোনও কানেকশন ফাঁকা নেই"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s এর মাধ্যমে সংযুক্ত হয়েছে"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s এর মাধ্যমে পাওয়া যাচ্ছে"</string>
@@ -82,9 +84,10 @@
     <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP -তে সংযুক্ত হয়েছে"</string>
     <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"ফাইল স্থানান্তর সার্ভারের সঙ্গে সংযুক্ত নয়"</string>
     <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"ইনপুট ডিভাইসে সংযুক্ত"</string>
-    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"ইন্টারনেট অ্যাক্সেসের জন্য ডিভাইসে সংযুক্ত"</string>
-    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"ডিভাইসের সাথে স্থানীয় ইন্টারনেট সংযোগ ভাগ করছে"</string>
-    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"ইন্টারনেট অ্যাক্সেসের জন্য ব্যবহার করুন"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"ইন্টারনেটের জন্য সংযুক্ত"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"স্থানীয় ইন্টারনেটে চলছে"</string>
+    <!-- no translation found for bluetooth_pan_profile_summary_use_for (5736111170225304239) -->
+    <skip />
     <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"মানচিত্রের জন্য ব্যবহার করুন"</string>
     <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"সিম -এর অ্যাক্সেসের জন্য ব্যবহার করুন"</string>
     <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"মিডিয়া অডিওয়ের জন্য ব্যবহার করুন"</string>
@@ -296,6 +299,8 @@
     <string name="force_msaa_summary" msgid="9123553203895817537">"OpenGL ES 2.0 অ্যাপ্লিকেশানগুলির মধ্যে 4x MSAA সক্রিয় করুন"</string>
     <string name="show_non_rect_clip" msgid="505954950474595172">"অ-আয়তক্ষেত্রাকার ক্লিপ কার্যকলাপ ডিবাগ করুন"</string>
     <string name="track_frame_time" msgid="6146354853663863443">"প্রোফাইল GPU রেন্ডারিং"</string>
+    <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU ডিবাগ স্তর সক্ষম করুন"</string>
+    <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"ডিবাগ অ্যাপের জন্য GPU ডিবাগ স্তর লোড হতে দিন"</string>
     <string name="window_animation_scale_title" msgid="6162587588166114700">"উইন্ডো অ্যানিমেশন স্কেল"</string>
     <string name="transition_animation_scale_title" msgid="387527540523595875">"ট্র্যানজিশন অ্যানিমেশন স্কেল"</string>
     <string name="animator_duration_scale_title" msgid="3406722410819934083">"অ্যানিমেটর সময়কাল স্কেল"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index fc81c76..9d86055 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -33,13 +33,15 @@
     <string name="wifi_check_password_try_again" msgid="516958988102584767">"Comprova la contrasenya i torna-ho a provar"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Fora de l\'abast"</string>
     <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"No es connectarà automàticament"</string>
-    <string name="wifi_no_internet" msgid="3880396223819116454">"No hi ha accés a Internet"</string>
+    <!-- no translation found for wifi_no_internet (4663834955626848401) -->
+    <skip />
     <string name="saved_network" msgid="4352716707126620811">"Desat per <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Connectada automàticament a través de: %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Connectada automàticament a través d\'un proveïdor de valoració de xarxes"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connectada mitjançant %1$s"</string>
     <string name="available_via_passpoint" msgid="1617440946846329613">"Disponible mitjançant %1$s"</string>
-    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Connectada, sense Internet"</string>
+    <!-- no translation found for wifi_connected_no_internet (8202906332837777829) -->
+    <skip />
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"El punt d\'accés està temporalment ple"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Connectat mitjançant %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Disponible mitjançant %1$s"</string>
@@ -82,9 +84,10 @@
     <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Connectat a SAP"</string>
     <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"No està connectat al servidor de transferència de fitxers"</string>
     <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Connectat a dispositiu d\'entrada"</string>
-    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Connectat al dispositiu per a accés a Internet"</string>
-    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"S\'està compartint la connexió a Internet amb el dispositiu"</string>
-    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Utilitza\'l per a l\'accés a Internet"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Connectat per accedir a Internet"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Compartint la connexió local amb el dispositiu"</string>
+    <!-- no translation found for bluetooth_pan_profile_summary_use_for (5736111170225304239) -->
+    <skip />
     <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Utilitza per al mapa"</string>
     <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Utilitza per a l\'accés a la SIM"</string>
     <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Utilitza per a l\'àudio del mitjà"</string>
@@ -296,6 +299,8 @@
     <string name="force_msaa_summary" msgid="9123553203895817537">"Activa MSAA 4x en aplicacions d\'OpenGL ES 2.0"</string>
     <string name="show_non_rect_clip" msgid="505954950474595172">"Depura operacions de retall no rectangulars"</string>
     <string name="track_frame_time" msgid="6146354853663863443">"Perfil de renderització de GPU"</string>
+    <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Activa les capes de depuració de GPU"</string>
+    <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Permet carregar capes de depuració de GPU per a apps de depuració"</string>
     <string name="window_animation_scale_title" msgid="6162587588166114700">"Escala d\'animació finestra"</string>
     <string name="transition_animation_scale_title" msgid="387527540523595875">"Escala d\'animació transició"</string>
     <string name="animator_duration_scale_title" msgid="3406722410819934083">"Escala de durada d\'animació"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index e9fa086..53b5d9e 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -33,13 +33,13 @@
     <string name="wifi_check_password_try_again" msgid="516958988102584767">"Check password and try again"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Not in range"</string>
     <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Won\'t automatically connect"</string>
-    <string name="wifi_no_internet" msgid="3880396223819116454">"No Internet access"</string>
+    <string name="wifi_no_internet" msgid="4663834955626848401">"No Internet access"</string>
     <string name="saved_network" msgid="4352716707126620811">"Saved by <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatically connected via %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatically connected via network rating provider"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connected via %1$s"</string>
     <string name="available_via_passpoint" msgid="1617440946846329613">"Available via %1$s"</string>
-    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Connected, no Internet"</string>
+    <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Connected, no Internet"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Access point temporarily full"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Connected via %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Available via %1$s"</string>
@@ -82,9 +82,9 @@
     <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Connected to SAP"</string>
     <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Not connected to file-transfer server"</string>
     <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Connected to input device"</string>
-    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Connected to device for Internet access"</string>
-    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Sharing local Internet connection with device"</string>
-    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Use for Internet access"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Connected to device for Internet access"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Sharing local Internet connection with device"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Use for Internet access"</string>
     <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Use for map"</string>
     <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Use for SIM access"</string>
     <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Use for media audio"</string>
@@ -296,6 +296,8 @@
     <string name="force_msaa_summary" msgid="9123553203895817537">"Enable 4x MSAA in OpenGL ES 2.0 apps"</string>
     <string name="show_non_rect_clip" msgid="505954950474595172">"Debug non-rectangular clip operations"</string>
     <string name="track_frame_time" msgid="6146354853663863443">"Profile GPU rendering"</string>
+    <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Enable GPU debug layers"</string>
+    <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Allow loading GPU debug layers for debug apps"</string>
     <string name="window_animation_scale_title" msgid="6162587588166114700">"Window animation scale"</string>
     <string name="transition_animation_scale_title" msgid="387527540523595875">"Transition animation scale"</string>
     <string name="animator_duration_scale_title" msgid="3406722410819934083">"Animator duration scale"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index e9fa086..53b5d9e 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -33,13 +33,13 @@
     <string name="wifi_check_password_try_again" msgid="516958988102584767">"Check password and try again"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Not in range"</string>
     <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Won\'t automatically connect"</string>
-    <string name="wifi_no_internet" msgid="3880396223819116454">"No Internet access"</string>
+    <string name="wifi_no_internet" msgid="4663834955626848401">"No Internet access"</string>
     <string name="saved_network" msgid="4352716707126620811">"Saved by <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatically connected via %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatically connected via network rating provider"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connected via %1$s"</string>
     <string name="available_via_passpoint" msgid="1617440946846329613">"Available via %1$s"</string>
-    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Connected, no Internet"</string>
+    <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Connected, no Internet"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Access point temporarily full"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Connected via %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Available via %1$s"</string>
@@ -82,9 +82,9 @@
     <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Connected to SAP"</string>
     <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Not connected to file-transfer server"</string>
     <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Connected to input device"</string>
-    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Connected to device for Internet access"</string>
-    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Sharing local Internet connection with device"</string>
-    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Use for Internet access"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Connected to device for Internet access"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Sharing local Internet connection with device"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Use for Internet access"</string>
     <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Use for map"</string>
     <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Use for SIM access"</string>
     <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Use for media audio"</string>
@@ -296,6 +296,8 @@
     <string name="force_msaa_summary" msgid="9123553203895817537">"Enable 4x MSAA in OpenGL ES 2.0 apps"</string>
     <string name="show_non_rect_clip" msgid="505954950474595172">"Debug non-rectangular clip operations"</string>
     <string name="track_frame_time" msgid="6146354853663863443">"Profile GPU rendering"</string>
+    <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Enable GPU debug layers"</string>
+    <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Allow loading GPU debug layers for debug apps"</string>
     <string name="window_animation_scale_title" msgid="6162587588166114700">"Window animation scale"</string>
     <string name="transition_animation_scale_title" msgid="387527540523595875">"Transition animation scale"</string>
     <string name="animator_duration_scale_title" msgid="3406722410819934083">"Animator duration scale"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index e9fa086..53b5d9e 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -33,13 +33,13 @@
     <string name="wifi_check_password_try_again" msgid="516958988102584767">"Check password and try again"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Not in range"</string>
     <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Won\'t automatically connect"</string>
-    <string name="wifi_no_internet" msgid="3880396223819116454">"No Internet access"</string>
+    <string name="wifi_no_internet" msgid="4663834955626848401">"No Internet access"</string>
     <string name="saved_network" msgid="4352716707126620811">"Saved by <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatically connected via %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatically connected via network rating provider"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connected via %1$s"</string>
     <string name="available_via_passpoint" msgid="1617440946846329613">"Available via %1$s"</string>
-    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Connected, no Internet"</string>
+    <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Connected, no Internet"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Access point temporarily full"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Connected via %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Available via %1$s"</string>
@@ -82,9 +82,9 @@
     <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Connected to SAP"</string>
     <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Not connected to file-transfer server"</string>
     <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Connected to input device"</string>
-    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Connected to device for Internet access"</string>
-    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Sharing local Internet connection with device"</string>
-    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Use for Internet access"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Connected to device for Internet access"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Sharing local Internet connection with device"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Use for Internet access"</string>
     <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Use for map"</string>
     <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Use for SIM access"</string>
     <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Use for media audio"</string>
@@ -296,6 +296,8 @@
     <string name="force_msaa_summary" msgid="9123553203895817537">"Enable 4x MSAA in OpenGL ES 2.0 apps"</string>
     <string name="show_non_rect_clip" msgid="505954950474595172">"Debug non-rectangular clip operations"</string>
     <string name="track_frame_time" msgid="6146354853663863443">"Profile GPU rendering"</string>
+    <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Enable GPU debug layers"</string>
+    <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Allow loading GPU debug layers for debug apps"</string>
     <string name="window_animation_scale_title" msgid="6162587588166114700">"Window animation scale"</string>
     <string name="transition_animation_scale_title" msgid="387527540523595875">"Transition animation scale"</string>
     <string name="animator_duration_scale_title" msgid="3406722410819934083">"Animator duration scale"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index e9fa086..53b5d9e 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -33,13 +33,13 @@
     <string name="wifi_check_password_try_again" msgid="516958988102584767">"Check password and try again"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Not in range"</string>
     <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Won\'t automatically connect"</string>
-    <string name="wifi_no_internet" msgid="3880396223819116454">"No Internet access"</string>
+    <string name="wifi_no_internet" msgid="4663834955626848401">"No Internet access"</string>
     <string name="saved_network" msgid="4352716707126620811">"Saved by <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatically connected via %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatically connected via network rating provider"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connected via %1$s"</string>
     <string name="available_via_passpoint" msgid="1617440946846329613">"Available via %1$s"</string>
-    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Connected, no Internet"</string>
+    <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Connected, no Internet"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Access point temporarily full"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Connected via %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Available via %1$s"</string>
@@ -82,9 +82,9 @@
     <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Connected to SAP"</string>
     <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Not connected to file-transfer server"</string>
     <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Connected to input device"</string>
-    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Connected to device for Internet access"</string>
-    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Sharing local Internet connection with device"</string>
-    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Use for Internet access"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Connected to device for Internet access"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Sharing local Internet connection with device"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Use for Internet access"</string>
     <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Use for map"</string>
     <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Use for SIM access"</string>
     <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Use for media audio"</string>
@@ -296,6 +296,8 @@
     <string name="force_msaa_summary" msgid="9123553203895817537">"Enable 4x MSAA in OpenGL ES 2.0 apps"</string>
     <string name="show_non_rect_clip" msgid="505954950474595172">"Debug non-rectangular clip operations"</string>
     <string name="track_frame_time" msgid="6146354853663863443">"Profile GPU rendering"</string>
+    <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Enable GPU debug layers"</string>
+    <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Allow loading GPU debug layers for debug apps"</string>
     <string name="window_animation_scale_title" msgid="6162587588166114700">"Window animation scale"</string>
     <string name="transition_animation_scale_title" msgid="387527540523595875">"Transition animation scale"</string>
     <string name="animator_duration_scale_title" msgid="3406722410819934083">"Animator duration scale"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 88fba49..2b0b6e5 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -33,13 +33,13 @@
     <string name="wifi_check_password_try_again" msgid="516958988102584767">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‏‏‏‏‎‎‏‎‏‏‎‎‏‎‎‏‏‎‏‏‎‏‏‏‎‏‎‏‏‏‏‏‎‎‎‏‎‏‎‎‏‏‎‎‏‏‎‎‏‎‎‏‏‎‏‏‏‏‏‏‎Check password and try again‎‏‎‎‏‎"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‏‏‏‏‎‎‎‏‎‎‏‎‎‏‎‎‎‎‎‎‏‎‏‎‎‎‏‏‏‎‎‎‎‎‎‎‏‎‏‏‏‏‏‎‎‎‎‎‎‏‏‎‏‎‎‏‏‏‎Not in range‎‏‎‎‏‎"</string>
     <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‏‏‎‎‏‎‏‏‏‏‎‎‎‏‎‏‎‎‎‎‏‏‎‎‏‏‎‏‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‎‏‏‏‎‎‎‏‎‏‎‎Won\'t automatically connect‎‏‎‎‏‎"</string>
-    <string name="wifi_no_internet" msgid="3880396223819116454">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‎‏‏‏‎‏‏‎‎‏‏‏‏‎‏‏‏‏‏‏‎‎‏‏‏‎‎‏‏‎‏‏‎‎‏‎‎‎‎‎‎‏‎‏‏‎‏‏‏‏‏‎‏‎‎‏‏‎‎No Internet access‎‏‎‎‏‎"</string>
+    <string name="wifi_no_internet" msgid="4663834955626848401">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‎‎‏‎‏‏‏‎‎‏‎‏‎‎‎‏‎‏‎‎‏‎‏‏‏‎‏‎‎‏‏‏‎‏‎‎‏‏‎‎‎‎‎‎‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎No internet access‎‏‎‎‏‎"</string>
     <string name="saved_network" msgid="4352716707126620811">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‎‎‎‏‎‎‏‎‎‎‎‎‎‏‏‎‎‎‎‏‎‏‏‎‎‏‎‏‎‎‎‏‎‏‏‎Saved by ‎‏‎‎‏‏‎<xliff:g id="NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‎‎‏‎‏‏‎‏‏‏‏‎‎‎‏‎‏‏‏‏‎‏‎‏‎‏‏‎‎‎‎‎‎‎‏‎‏‎‎‎‎‏‏‎‏‎‎‏‏‎‏‏‎‏‎Automatically connected via %1$s‎‏‎‎‏‎"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‏‎‏‎‎‏‎‎‏‎‎‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‎‎‎‎‎‎Automatically connected via network rating provider‎‏‎‎‏‎"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‏‏‏‎‎‏‏‏‎‎‎‏‎‏‏‎‎‏‏‎‎‎‏‏‎‏‎‏‏‎‎‏‎‎‏‎‏‎‏‎‎‎‏‏‏‎‎‏‎‏‏‎‏‏‎‏‎‏‏‎Connected via %1$s‎‏‎‎‏‎"</string>
     <string name="available_via_passpoint" msgid="1617440946846329613">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‏‎‎‏‏‏‎‎‏‎‎‏‎‎‏‏‎‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‎‏‏‏‏‏‎‎‏‎‎‏‏‎‏‎‏‏‎‎‎‎‏‏‎‏‎Available via %1$s‎‏‎‎‏‎"</string>
-    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‏‎‏‏‎‏‎‎‎‎‏‏‏‎‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‎‎‎‏‏‏‏‏‏‏‎‎‎‎‎Connected, no Internet‎‏‎‎‏‎"</string>
+    <string name="wifi_connected_no_internet" msgid="8202906332837777829">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‎‏‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‎‎‏‎‏‎‎‏‏‏‎‏‎‎‏‏‎‎‏‎‎‎‏‎‎‎‏‏‎‏‎‎‏‎‏‎Connected, no internet‎‏‎‎‏‎"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‏‏‏‎‏‎‏‏‎‏‎‏‏‏‎‏‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‎‏‏‏‏‎‏‎Access point temporarily full‎‏‎‎‏‎"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‎‎‏‎‏‎‎‏‏‎‎‏‏‏‏‎‏‏‎‎‏‏‏‎‎‏‏‏‎‎‎‎Connected via %1$s‎‏‎‎‏‎"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‎‎‎‏‏‎‎‎‏‏‎‎‎‏‎‎‎‎‏‎‎‏‎‎‏‏‏‎‏‎‎‎‏‏‎‏‏‎‏‎‏‎‎‎‏‏‏‏‎‎‎‏‎‎‏‏‎‏‎Available via %1$s‎‏‎‎‏‎"</string>
@@ -82,9 +82,9 @@
     <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‎‏‏‏‏‎‏‎‏‏‏‏‏‎‎‏‏‎‎‏‎‏‏‏‏‏‎‎Connected to SAP‎‏‎‎‏‎"</string>
     <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‎‏‏‎‎‏‎‏‎‏‏‎‎‏‏‏‎‎‏‏‏‎‎‎‎‎‎‎‎‎‎‎‎‏‏‎‏‎‏‎‎‎‎‏‏‏‎‎‎‏‎‏‎‎‏‏‎‏‎Not connected to file transfer server‎‏‎‎‏‎"</string>
     <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‏‎‏‏‏‎‏‏‏‎‎‏‏‎‏‏‎‎‏‏‎‏‏‎‏‎‎‎‎‏‏‎‏‏‎‎‎‏‏‎‎‏‏‏‎‏‎‎‏‎‏‎‏‏‎‎‎‏‎Connected to input device‎‏‎‎‏‎"</string>
-    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‎‎‏‎‏‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‏‏‎‎‎‏‎‏‎‏‎‎‎Connected to device for Internet access‎‏‎‎‏‎"</string>
-    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‎‏‏‎‏‎‏‎‏‏‎‎‏‎‎‏‏‎‎‎‏‏‎‏‎‏‎‏‎‏‏‎‏‎‏‏‎‎‎‏‎‎‏‏‎‎‎‎‏‎‎‎‎‏‏‏‏‏‎Sharing local Internet connection with device‎‏‎‎‏‎"</string>
-    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‎‏‏‏‎‏‏‎‏‏‎‏‏‎‎‏‏‏‎‏‎‏‏‏‏‎‏‎‎‎‎‎‎‎‎‏‎‏‏‎‏‏‎‎‏‏‏‎‏‎‏‏‎‏‎Use for Internet access‎‏‎‎‏‎"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‎‏‏‎‎‎‎‎‎‏‏‎‏‎‏‏‎‎‏‏‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎Connected to device for internet access‎‏‎‎‏‎"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‏‎‎‏‎‏‏‎‏‏‎‎‏‎‎‏‏‏‎‏‏‎‎‎‏‏‏‎‏‏‎‏‏‏‏‎‏‏‎‏‎‏‏‏‏‎‎‏‎‏‎‎‎‏‏‏‎‎‎Sharing local internet connection with device‎‏‎‎‏‎"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‏‏‏‏‎‎‏‏‎‏‎‏‏‎‎‎‎‏‎‏‎‏‏‎‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‏‏‎‏‏‏‏‏‎‎‏‎‏‎‏‎‏‏‏‏‎Use for internet access‎‏‎‎‏‎"</string>
     <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‏‏‏‏‎‎‎‎‏‏‏‎‏‏‎‎‏‎‏‏‎‏‏‎‎‏‏‎‏‏‏‎‎‎‏‎‎‎‏‏‎‏‎‎‏‏‎‎‎‎‎‏‎‎‎‏‎‏‎‎Use for map‎‏‎‎‏‎"</string>
     <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‎‏‎‏‎‎‎‏‎‎‎‎‏‏‏‏‎‏‏‎‎‎‏‏‏‏‎‎‎‎‎‏‏‏‎‏‏‎‎‎‏‏‎‎‏‏‎‏‎‏‏‎‎‏‎Use for SIM access‎‏‎‎‏‎"</string>
     <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‎‎‎‏‎‎‎‏‎‎‎‎‎‏‎‏‎‎‏‎‏‎‎‏‏‎‏‎‎‎‎‎‏‏‏‎‏‎‏‏‏‏‏‎‏‏‎‎‎‎‎‏‏‎‏‎‏‏‎Use for media audio‎‏‎‎‏‎"</string>
@@ -296,6 +296,8 @@
     <string name="force_msaa_summary" msgid="9123553203895817537">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‎‏‎‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‏‏‎‎‏‎‏‎‏‎‏‎‏‎‎‎‎‎‏‎Enable 4x MSAA in OpenGL ES 2.0 apps‎‏‎‎‏‎"</string>
     <string name="show_non_rect_clip" msgid="505954950474595172">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‏‏‏‏‎‎‎‎‎‏‎‏‏‎‎‎‎‎‏‏‎‏‎‏‏‎‎‎‏‏‎‎‎‏‏‏‎‏‏‎‎‎‏‏‎‏‏‏‏‎‏‏‎‏‏‎‎‏‎‎‎Debug non-rectangular clip operations‎‏‎‎‏‎"</string>
     <string name="track_frame_time" msgid="6146354853663863443">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‎‎‏‏‎‎‎‎‏‏‏‏‎‏‎‎‏‎‏‏‎‎‏‎‏‏‎‏‎‎‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‎‏‎‎‏‏‎Profile GPU rendering‎‏‎‎‏‎"</string>
+    <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‎‏‎‏‏‎‏‎‎‏‏‏‎‏‎‎‏‎‎‎‎‎‏‎‎‏‎‏‎‎‎‎‏‏‎‏‏‏‎‏‏‏‏‎‏‎‏‏‏‎‏‎‏‏‏‎‎‏‎Enable GPU debug layers‎‏‎‎‏‎"</string>
+    <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‎‎‏‏‎‎‎‏‎‏‎‏‏‏‎‎‏‏‏‎‏‎‎‎‎‎‎‏‎‎‎‏‎‏‎‏‎‎‏‎‏‎‏‏‏‎‎‏‏‏‏‎‎‎Allow loading GPU debug layers for debug apps‎‏‎‎‏‎"</string>
     <string name="window_animation_scale_title" msgid="6162587588166114700">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‎‎‎‏‎‏‏‏‏‎‏‎‎‎‏‏‎‎‎‎‏‎‏‎‏‏‏‎‎‏‏‏‎‏‏‏‏‏‎‏‎‏‏‏‎‏‏‎‎‎‏‏‎‎‎Window animation scale‎‏‎‎‏‎"</string>
     <string name="transition_animation_scale_title" msgid="387527540523595875">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‏‏‎‏‎‏‏‎‎‎‎‎‏‏‎‎‎‏‏‎‎‎‏‏‏‏‏‎‏‎‏‏‎‎‎‏‏‎‎‏‎‏‏‎‏‏‏‏‏‎‎‎‎‏‏‎‎‎‏‏‎Transition animation scale‎‏‎‎‏‎"</string>
     <string name="animator_duration_scale_title" msgid="3406722410819934083">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‎‏‎‏‎‎‏‎‎‎‏‏‎‏‎‏‏‏‏‎‎‎‎‎‏‏‎Animator duration scale‎‏‎‎‏‎"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index a5929e2..d36db19 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -33,19 +33,21 @@
     <string name="wifi_check_password_try_again" msgid="516958988102584767">"Comprueba la contraseña y vuelve a intentarlo"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Fuera de rango"</string>
     <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"No se establecerá conexión automáticamente"</string>
-    <string name="wifi_no_internet" msgid="3880396223819116454">"No se ha detectado acceso a Internet"</string>
+    <!-- no translation found for wifi_no_internet (4663834955626848401) -->
+    <skip />
     <string name="saved_network" msgid="4352716707126620811">"Guardada por <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Conectada automáticamente a través de %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Conectado automáticamente a través de un proveedor de valoración de redes"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado a través de %1$s"</string>
     <string name="available_via_passpoint" msgid="1617440946846329613">"Disponible a través de %1$s"</string>
-    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Conexión sin Internet"</string>
+    <!-- no translation found for wifi_connected_no_internet (8202906332837777829) -->
+    <skip />
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Punto de acceso temporalmente lleno"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Conectado a través de %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Disponible a través de %1$s"</string>
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Muy lenta"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Lenta"</string>
-    <string name="speed_label_okay" msgid="2331665440671174858">"Aceptar"</string>
+    <string name="speed_label_okay" msgid="2331665440671174858">"Aceptable"</string>
     <string name="speed_label_medium" msgid="3175763313268941953">"Media"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Rápida"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Muy rápida"</string>
@@ -82,9 +84,10 @@
     <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Conectado a SAP"</string>
     <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Sin conexión con el servidor de transferencia de archivos"</string>
     <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Conectado a dispositivo de entrada"</string>
-    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Conectado para acceso a Internet"</string>
-    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Compartiendo conexión a Internet con el dispositivo"</string>
-    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Usar para acceder a Internet"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Conectado para acceder a Internet"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Compartiendo conexión local con dispositivo"</string>
+    <!-- no translation found for bluetooth_pan_profile_summary_use_for (5736111170225304239) -->
+    <skip />
     <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Usar para mapa"</string>
     <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Utilizar para acceso a tarjeta SIM"</string>
     <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Utilizar para audio de medio"</string>
@@ -296,6 +299,8 @@
     <string name="force_msaa_summary" msgid="9123553203895817537">"Habilitar MSAA 4x en aplicaciones de OpenGL ES 2.0"</string>
     <string name="show_non_rect_clip" msgid="505954950474595172">"Depurar operaciones de recorte no rectangulares"</string>
     <string name="track_frame_time" msgid="6146354853663863443">"Perfil renderización GPU"</string>
+    <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Activar capas depuración GPU"</string>
+    <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Permitir cargar capas de depuración de GPU en apps"</string>
     <string name="window_animation_scale_title" msgid="6162587588166114700">"Escala de animación de ventana"</string>
     <string name="transition_animation_scale_title" msgid="387527540523595875">"Escala de transición-animación"</string>
     <string name="animator_duration_scale_title" msgid="3406722410819934083">"Escala de duración de animación"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index bd2f94e..57d1657 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -33,13 +33,13 @@
     <string name="wifi_check_password_try_again" msgid="516958988102584767">"Egiaztatu pasahitza zuzena dela eta saiatu berriro"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Urrunegi"</string>
     <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Ez da konektatuko automatikoki"</string>
-    <string name="wifi_no_internet" msgid="3880396223819116454">"Ezin da konektatu Internetera"</string>
+    <string name="wifi_no_internet" msgid="4663834955626848401">"Ezin da atzitu Internet"</string>
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> aplikazioak gorde du"</string>
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s bidez automatikoki konektatuta"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatikoki konektatuta sareen balorazioen hornitzailearen bidez"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s bidez konektatuta"</string>
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s bidez erabilgarri"</string>
-    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Konektatuta, ez dago Interneteko konexiorik"</string>
+    <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Konektatuta; ezin da atzitu Internet"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Sarbide-puntua beteta dago aldi baterako"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s bidez konektatuta"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s bidez erabilgarri"</string>
@@ -82,9 +82,9 @@
     <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP sarbide-puntura konektatuta"</string>
     <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Fitxategi-transferentziako zerbitzarira konektatu gabe"</string>
     <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Sarrerako gailura konektatuta"</string>
-    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Gailura konektatuta Interneteko sarbiderako"</string>
-    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Tokiko Interneteko konexioa gailu batekin partekatzea"</string>
-    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Erabili Interneteko sarbiderako"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Gailura konektatuta Interneteko sarbiderako"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Tokiko Interneteko konexioa gailu batekin partekatzea"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Erabili Internet atzitzeko"</string>
     <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Erabili maparako"</string>
     <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Erabili SIM txartelerako sarbiderako"</string>
     <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Erabili euskarriaren audiorako"</string>
@@ -99,6 +99,13 @@
     <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Ezin izan da <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gailuarekin parekatu PIN edo pasakode okerra idatzi delako."</string>
     <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Ezin da <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gailuarekin komunikatu."</string>
     <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> gailuak bikotetzea ukatu du."</string>
+    <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Ordenagailua"</string>
+    <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Mikrofonodun entzungailua"</string>
+    <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Telefonoa"</string>
+    <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Irudietarako gailua"</string>
+    <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Aurikularra"</string>
+    <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Idazteko gailua"</string>
+    <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth gailua"</string>
     <string name="accessibility_wifi_off" msgid="1166761729660614716">"Desaktibatuta dago Wi-Fi konexioa."</string>
     <string name="accessibility_no_wifi" msgid="8834610636137374508">"Deskonektatu egin da Wi-Fi konexioa."</string>
     <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi sarearen barra bat."</string>
@@ -209,8 +216,12 @@
     <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth audioaren LDAC kodeka: erreprodukzioaren kalitatea"</string>
     <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Hautatu Bluetooth audioaren LDAC kodeka:\nerreprodukzioaren kalitatea"</string>
     <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Igortzean: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
-    <string name="dns_tls" msgid="6773814174391131955">"TLS bidezko DNSa"</string>
-    <string name="dns_tls_summary" msgid="3692494150251071380">"Gaituz gero, erabili TLS bidezko DNSa 853 atakan."</string>
+    <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS pribatua"</string>
+    <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Hautatu DNS pribatuaren modua"</string>
+    <string name="private_dns_mode_off" msgid="8236575187318721684">"Desaktibatuta"</string>
+    <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Aldakorra"</string>
+    <string name="private_dns_mode_provider" msgid="8354935160639360804">"DNS hornitzaile pribatuaren ostalari-izena"</string>
+    <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Idatzi DNS hornitzailearen ostalari-izena"</string>
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Erakutsi hari gabeko bistaratze-egiaztapenaren aukerak"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Erakutsi datu gehiago Wi-Fi sareetan saioa hasterakoan. Erakutsi sarearen identifikatzailea eta seinalearen indarra Wi‑Fi sareen hautagailuan."</string>
     <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Aukera hori gaituz gero, gailua nahitaez aldatuko da datu mugikorren konexiora Wi-Fi seinalea ahultzen dela nabaritutakoan"</string>
@@ -285,6 +296,8 @@
     <string name="force_msaa_summary" msgid="9123553203895817537">"Gaitu 4x MSAA, OpenGL ES 2.0 aplikazioetan."</string>
     <string name="show_non_rect_clip" msgid="505954950474595172">"Araztu angeluzuzenak ez diren klip-eragiketak."</string>
     <string name="track_frame_time" msgid="6146354853663863443">"GPU errendatze-profila"</string>
+    <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Gaitu GPUaren arazte-geruzak"</string>
+    <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Onartu GPUaren arazte-geruzak kargatzea arazte-aplikazioetarako"</string>
     <string name="window_animation_scale_title" msgid="6162587588166114700">"Leihoen animazio-eskala"</string>
     <string name="transition_animation_scale_title" msgid="387527540523595875">"Trantsizio-animazio eskala"</string>
     <string name="animator_duration_scale_title" msgid="3406722410819934083">"Animatzailearen iraupena"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 3b5ea2d..14095f4 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -33,13 +33,15 @@
     <string name="wifi_check_password_try_again" msgid="516958988102584767">"पासवर्ड जाँचें और दोबारा कोशिश करें"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"रेंज में नहीं"</string>
     <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"अपने आप कनेक्ट नहीं होगा"</string>
-    <string name="wifi_no_internet" msgid="3880396223819116454">"इंटरनेट नहीं है"</string>
+    <!-- no translation found for wifi_no_internet (4663834955626848401) -->
+    <skip />
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> के द्वारा सहेजा गया"</string>
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s के ज़रिए ऑटोमैटिक रूप से कनेक्ट है"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"नेटवर्क रेटिंग प्रदाता के ज़रिए अपने आप कनेक्ट है"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s के द्वारा उपलब्ध"</string>
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s के द्वारा उपलब्ध"</string>
-    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"कनेक्ट किया गया, इंटरनेट नहीं"</string>
+    <!-- no translation found for wifi_connected_no_internet (8202906332837777829) -->
+    <skip />
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"एक्सेस पॉइंट फ़िलहाल भरा हुआ है"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s के ज़रिए कनेक्ट"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s के ज़रिए उपलब्ध"</string>
@@ -82,9 +84,10 @@
     <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP से कनेक्ट किया गया"</string>
     <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"फ़ाइल स्‍थानांतरण सर्वर से कनेक्‍ट नहीं किया गया"</string>
     <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"इनपुट डिवाइस से कनेक्‍ट किया गया"</string>
-    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"इंटरनेट पहुंच के लिए डिवाइस से कनेक्‍ट"</string>
-    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"डिवाइस से स्‍थानीय इंटरनेट कनेक्‍शन शेयर किया जा रहा है"</string>
-    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"इंटरनेट पहुंच के लिए उपयोग करें"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"इंटरनेट के लिए डिवाइस से कनेक्ट है"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"डिवाइस से इंटरनेट शेयर हो रहा है"</string>
+    <!-- no translation found for bluetooth_pan_profile_summary_use_for (5736111170225304239) -->
+    <skip />
     <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"मानचित्र के लिए उपयोग करें"</string>
     <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"सिम ऐक्सेस के लिए उपयोग करें"</string>
     <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"मीडिया ऑडियो के लिए उपयोग करें"</string>
@@ -296,6 +299,8 @@
     <string name="force_msaa_summary" msgid="9123553203895817537">"OpenGL ES 2.0 ऐप में 4x MSAA को चालू करें"</string>
     <string name="show_non_rect_clip" msgid="505954950474595172">"गैर-आयताकार क्लिप परिचालनों को डीबग करें"</string>
     <string name="track_frame_time" msgid="6146354853663863443">"प्रोफ़ाइल GPU रेंडरिंग"</string>
+    <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU डीबग लेयर चालू करें"</string>
+    <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"डीबग ऐप के लिए GPU डीबग लेयर लोड करने की अनुमति दें"</string>
     <string name="window_animation_scale_title" msgid="6162587588166114700">"विंडो एनिमेशन स्‍केल"</string>
     <string name="transition_animation_scale_title" msgid="387527540523595875">"संक्रमण एनिमेशन स्‍केल"</string>
     <string name="animator_duration_scale_title" msgid="3406722410819934083">"एनिमेटर अवधि स्केल"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 873d15a..02575ff 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -33,13 +33,15 @@
     <string name="wifi_check_password_try_again" msgid="516958988102584767">"សូមពិនិត្យមើលពាក្យសម្ងាត់ រួចព្យាយាមម្ដងទៀត"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"នៅ​ក្រៅ​តំបន់"</string>
     <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"នឹងមិនភ្ជាប់ដោយស្វ័យប្រវត្តិទេ"</string>
-    <string name="wifi_no_internet" msgid="3880396223819116454">"មិនមានអ៊ីនធឺណិតទេ"</string>
+    <!-- no translation found for wifi_no_internet (4663834955626848401) -->
+    <skip />
     <string name="saved_network" msgid="4352716707126620811">"បានរក្សាទុកដោយ <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"បានភ្ជាប់ដោយស្វ័យប្រវត្តិតាមរយៈ %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"បានភ្ជាប់​ដោយស្វ័យប្រវត្តិ​តាម​រយៈក្រុមហ៊ុនផ្តល់​ការ​វាយ​តម្លៃលើ​បណ្តាញ"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"បានភ្ជាប់តាមរយៈ %1$s"</string>
     <string name="available_via_passpoint" msgid="1617440946846329613">"មានតាមរយៈ %1$s"</string>
-    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"បានភ្ជាប់ ប៉ុន្តែគ្មានអ៊ីនធឺណិតទេ"</string>
+    <!-- no translation found for wifi_connected_no_internet (8202906332837777829) -->
+    <skip />
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"ចំណុចចូលប្រើពេញជាបណ្តោះអាសន្ន"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"បានភ្ជាប់តាមរយៈ %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"មានតាមរយៈ %1$s"</string>
@@ -82,9 +84,10 @@
     <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"បានភ្ជាប់ទៅ SAP"</string>
     <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"មិន​បាន​តភ្ជាប់​ទៅ​ម៉ាស៊ីន​មេ​ផ្ទេរ​ឯកសារ"</string>
     <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"បាន​តភ្ជាប់​ទៅ​ឧបករណ៍​បញ្ចូល"</string>
-    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"បាន​តភ្ជាប់​​ឧបករណ៍​សម្រាប់​ចូល​អ៊ីនធឺណិត"</string>
-    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"ចែករំលែក​ការ​តភ្ជាប់​អ៊ីនធឺណិត​មូលដ្ឋាន​ជា​មួយ​ឧបករណ៍"</string>
-    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"ប្រើ​សម្រាប់​ចូល​អ៊ីនធឺណិត"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"បានភ្ជាប់​​ទៅឧបករណ៍​ដើម្បីចូល​ប្រើអ៊ីនធឺណិត"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"កំពុងចែករំលែក​ការ​ភ្ជាប់​អ៊ីនធឺណិត​មូលដ្ឋាន​ជាមួយ​ឧបករណ៍"</string>
+    <!-- no translation found for bluetooth_pan_profile_summary_use_for (5736111170225304239) -->
+    <skip />
     <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"ប្រើ​សម្រាប់​ផែនទី"</string>
     <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"ប្រើសម្រាប់ចូលដំណើរការស៊ីម"</string>
     <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"ប្រើ​សម្រាប់​សំឡេង​មេឌៀ"</string>
@@ -99,6 +102,13 @@
     <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"មិន​អាច​ផ្គូផ្គង​ជា​មួយ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ព្រោះ​​​កូដ PIN ឬ​លេខ​កូដ​មិន​ត្រឹមត្រូវ។"</string>
     <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"មិន​អាច​ទាក់ទង​ជា​មួយ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ។"</string>
     <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"ការ​ផ្គូផ្គង​បាន​បដិសេធ​ដោយ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ។"</string>
+    <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"កុំព្យូទ័រ"</string>
+    <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"កាស"</string>
+    <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"ទូរស័ព្ទ"</string>
+    <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"កំពុងបង្ហាញ"</string>
+    <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"កាស"</string>
+    <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"ធាតុបញ្ចូលបន្ថែម"</string>
+    <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"ប៊្លូធូស"</string>
     <string name="accessibility_wifi_off" msgid="1166761729660614716">"បានបិទ Wifi"</string>
     <string name="accessibility_no_wifi" msgid="8834610636137374508">"បានផ្តាច់ Wifi"</string>
     <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wifi មួយកាំ"</string>
@@ -209,8 +219,12 @@
     <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"កូឌិកប្រភេទ LDAC នៃសំឡេង​ប៊្លូធូស៖ គុណភាព​ចាក់​សំឡេង"</string>
     <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"ជ្រើសរើស​កូឌិក​ប្រភេទ​ LDAC នៃសំឡេង​ប៊្លូធូស៖\nគុណភាព​ចាក់​សំឡេង"</string>
     <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"កំពុង​ចាក់៖ <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
-    <string name="dns_tls" msgid="6773814174391131955">"DNS តាមរយៈ TLS"</string>
-    <string name="dns_tls_summary" msgid="3692494150251071380">"ប្រសិនបើបើក វានឹងព្យាយាមប្រើ DNS តាមរៈ TLS នៅលើរន្ធ 853។"</string>
+    <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS ឯកជន"</string>
+    <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"ជ្រើសរើសមុខងារ DNS ឯកជន"</string>
+    <string name="private_dns_mode_off" msgid="8236575187318721684">"បិទ"</string>
+    <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunistic"</string>
+    <string name="private_dns_mode_provider" msgid="8354935160639360804">"ឈ្មោះម៉ាស៊ីនក្រុមហ៊ុនផ្ដល់សេវា DNS ឯកជន"</string>
+    <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"បញ្ចូលឈ្មោះម៉ាស៊ីនរបស់ក្រុមហ៊ុនផ្ដល់សេវា DNS"</string>
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"បង្ហាញ​ជម្រើស​សម្រាប់​វិញ្ញាបនបត្រ​បង្ហាញ​ឥត​ខ្សែ"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"បង្កើនកម្រិតកំណត់ហេតុវ៉ាយហ្វាយបង្ហាញក្នុង SSID RSSI ក្នុងកម្មវិធីជ្រើស​វ៉ាយហ្វាយ"</string>
     <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"នៅពេលដែលបើក នោះ Wi‑Fi នឹងផ្តល់ការតភ្ជាប់ទិន្នន័យយ៉ាងគំហុកទៅបណ្តាញទូរសព្ទចល័ត នៅពេលរលកសញ្ញា Wi‑Fi ចុះខ្សោយ។"</string>
@@ -285,6 +299,8 @@
     <string name="force_msaa_summary" msgid="9123553203895817537">"បើក 4x MSAA ក្នុង​កម្មវិធី OpenGL ES 2.0"</string>
     <string name="show_non_rect_clip" msgid="505954950474595172">"កែ​ប្រតិបត្តិការ​​ស្រង់ non-rectangular"</string>
     <string name="track_frame_time" msgid="6146354853663863443">"ការ​បង្ហាញ​ទម្រង់ GPU"</string>
+    <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"បើក​ស្រទាប់​ជួសជុល GPU"</string>
+    <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"អនុញ្ញាតឱ្យ​ផ្ទុក​ស្រទាប់​ជួស​ជុល GPU សម្រាប់​កម្មវិធី​ជួសជុល"</string>
     <string name="window_animation_scale_title" msgid="6162587588166114700">"មាត្រដ្ឋាន​ចលនា​បង្អួច"</string>
     <string name="transition_animation_scale_title" msgid="387527540523595875">"មាត្រដ្ឋាន​ដំណើរ​ផ្លាស់ប្ដូរ​ចលនា"</string>
     <string name="animator_duration_scale_title" msgid="3406722410819934083">"មាត្រដ្ឋាន​រយៈពេល​នៃ​កម្មវិធី​ចលនា"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 3ac6923..74734a0 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -33,13 +33,15 @@
     <string name="wifi_check_password_try_again" msgid="516958988102584767">"पासवर्ड तपासा आणि पुन्‍हा प्रयत्‍न करा"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"परिक्षेत्रामध्ये नाही"</string>
     <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"स्वयंचलितपणे कनेक्ट करणार नाही"</string>
-    <string name="wifi_no_internet" msgid="3880396223819116454">"इंटरनेट अॅक्सेस नाही"</string>
+    <!-- no translation found for wifi_no_internet (4663834955626848401) -->
+    <skip />
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> द्वारे सेव्ह केले"</string>
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s द्वारे स्वयंचलितपणे कनेक्ट केले"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"नेटवर्क रेटिंग प्रदात्याद्वारे स्वयंचलितपणे कनेक्ट केले"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s द्वारे कनेक्‍ट केले"</string>
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s द्वारे उपलब्‍ध"</string>
-    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"कनेक्‍ट केले, इंटरनेट नाही"</string>
+    <!-- no translation found for wifi_connected_no_internet (8202906332837777829) -->
+    <skip />
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"अॅक्सेस पॉइंट तात्पुरते भरलेले"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s ने कनेक्‍ट केले"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s ने उपलब्‍ध"</string>
@@ -82,9 +84,10 @@
     <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP शी कनेक्‍ट केले"</string>
     <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"फाइल स्थानांतर सर्व्हरशी कनेक्ट केले नाही"</string>
     <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"इनपुट डिव्हाइसवर कनेक्ट केले"</string>
-    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"इंटरनेट अॅक्सेससाठी डीव्हाइसवर कनेक्ट केले"</string>
-    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"डीव्हाइससह स्थानिक इंटरनेट कनेक्शन शेअर करत आहे"</string>
-    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"इंटरनेट अॅक्सेससाठी वापरा"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"इंटरनेट अॅक्सेससाठी डिव्हाइसशी कनेक्ट केले"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"डिव्हाइससह स्थानिक इंटरनेट कनेक्शन शेअर करत आहे"</string>
+    <!-- no translation found for bluetooth_pan_profile_summary_use_for (5736111170225304239) -->
+    <skip />
     <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"नकाशासाठी वापरा"</string>
     <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM प्रवेशासाठी वापरा"</string>
     <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"मीडिया ऑडिओसाठी वापरा"</string>
@@ -296,6 +299,8 @@
     <string name="force_msaa_summary" msgid="9123553203895817537">"OpenGL ES 2.0 अॅप्समध्ये 4x MSAA सक्षम करा"</string>
     <string name="show_non_rect_clip" msgid="505954950474595172">"आयताकृती नसलेले क्लिप ऑपरेशन डीबग करा"</string>
     <string name="track_frame_time" msgid="6146354853663863443">"प्रोफाईल GPU प्रस्तुती"</string>
+    <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU डीबग स्तर सुरू करा"</string>
+    <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"डीबग अॅप्ससाठी GPU डीबग स्तर लोड करण्याची अनुमती द्या"</string>
     <string name="window_animation_scale_title" msgid="6162587588166114700">"विंडो अॅनिमेशन स्केल"</string>
     <string name="transition_animation_scale_title" msgid="387527540523595875">"संक्रमण अॅनिमेशन स्केल"</string>
     <string name="animator_duration_scale_title" msgid="3406722410819934083">"अॅनिमेटर कालावधी स्केल"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index c1892c3..d0fce81 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -33,13 +33,15 @@
     <string name="wifi_check_password_try_again" msgid="516958988102584767">"စကားဝှက်ကို စစ်ဆေးပြီး ထပ်လုပ်ကြည့်ပါ"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"စက်ကွင်းထဲတွင် မဟုတ်ပါ"</string>
     <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"အလိုအလျောက်ချိတ်ဆက်မည်မဟုတ်ပါ"</string>
-    <string name="wifi_no_internet" msgid="3880396223819116454">"အင်တာနက် ချိတ်ဆက်မှု မရှိပါ"</string>
+    <!-- no translation found for wifi_no_internet (4663834955626848401) -->
+    <skip />
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> မှသိမ်းဆည်းခဲ့သည်"</string>
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s မှတစ်ဆင့် အလိုအလျောက် ချိတ်ဆက်ထားပါသည်"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"ကွန်ရက်အဆင့်သတ်မှတ်ပေးသူ မှတစ်ဆင့် အလိုအလျောက် ချိတ်ဆက်ထားပါသည်"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s မှတစ်ဆင့် ချိတ်ဆက်ထားသည်"</string>
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s မှတစ်ဆင့်ရနိုင်သည်"</string>
-    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"ချိတ်ဆက်ထားသည်၊ အင်တာနက်မရှိ"</string>
+    <!-- no translation found for wifi_connected_no_internet (8202906332837777829) -->
+    <skip />
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"ကွန်ရက်ချိတ်ဆက်မှု ယာယီပြည့်နေသည်"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s မှတစ်ဆင့် ချိတ်ဆက်ထားသည်"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s မှတစ်ဆင့် ရနိုင်သည်"</string>
@@ -82,9 +84,10 @@
     <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP သို့ချိတ်ဆက်ထားသည်"</string>
     <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"ဖိုင်လွှဲပြောင်းမည့်ဆာဗာနှင့် ချိတ်ဆက်မထားပါ"</string>
     <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"ထည့်သွင်းထားသောစက်ကို ချိတ်ဆက်မည်"</string>
-    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"အင်တာနက်ဆက်သွယ်မှုရရန် စက်နှင်ချိတ်ဆက်မည်"</string>
-    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"စက်နှင့် ပုံမှန်အင်တာနက်ဆက်သွယ်မှုအား မျှဝေစေရန်"</string>
-    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"အင်တာနက်ချိတ်ဆက်ရန်အသုံးပြုသည်"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"အင်တာနက် ချိတ်ထားသည်"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"စက်နှင့် အင်တာနက်မျှဝေရန်"</string>
+    <!-- no translation found for bluetooth_pan_profile_summary_use_for (5736111170225304239) -->
+    <skip />
     <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"မြေပုံအတွက်သုံးရန်"</string>
     <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM အသုံးပြုမှုအတွက် အသုံးပြုမည်"</string>
     <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"မီဒီယာအသံအတွက်အသုံးပြုရန်"</string>
@@ -296,6 +299,8 @@
     <string name="force_msaa_summary" msgid="9123553203895817537">"OpenGL ES 2.0 apps တွင် ၄×MSAA အသုံးပြုခွင့်ပေးရန်"</string>
     <string name="show_non_rect_clip" msgid="505954950474595172">"စတုဂံပုံမကျသောဖြတ်ပိုင်း လုပ်ဆောင်ချက်များကို အမှားဖယ်ရှားသည်"</string>
     <string name="track_frame_time" msgid="6146354853663863443">"GPU တင်ဆက်မှု ကိုယ်ရေးအချက်အလက်"</string>
+    <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU အမှားရှာ အလွှာများဖွင့်ထားပါ"</string>
+    <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"အမှားရှာအက်ပ်များအတွက် GPU အမှားရှာအလွှာများ ထည့်သွင်းခွင့်ပြုပါ"</string>
     <string name="window_animation_scale_title" msgid="6162587588166114700">"လှုပ်ရှားသက်ဝင်ပုံစကေး"</string>
     <string name="transition_animation_scale_title" msgid="387527540523595875">"သက်ဝင်အသွင်ပြောင်းခြင်း"</string>
     <string name="animator_duration_scale_title" msgid="3406722410819934083">"လှုပ်ရှားမှုကြာချိန်စကေး"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 2b31bf1..b84194d 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -33,13 +33,15 @@
     <string name="wifi_check_password_try_again" msgid="516958988102584767">"Angalia nenosiri na ujaribu tena"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Haiko karibu"</string>
     <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Haiwezi kuunganisha kiotomatiki"</string>
-    <string name="wifi_no_internet" msgid="3880396223819116454">"Hakuna muunganisho wa Intaneti"</string>
+    <!-- no translation found for wifi_no_internet (4663834955626848401) -->
+    <skip />
     <string name="saved_network" msgid="4352716707126620811">"Ilihifadhiwa na <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Imeunganishwa kiotomatiki kupitia %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Imeunganishwa kiotomatiki kupitia mtoa huduma wa ukadiriaji wa mtandao"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Imeunganishwa kupitia %1$s"</string>
     <string name="available_via_passpoint" msgid="1617440946846329613">"Inapatikana kupitia %1$s"</string>
-    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Imeunganishwa, hakuna Intaneti"</string>
+    <!-- no translation found for wifi_connected_no_internet (8202906332837777829) -->
+    <skip />
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Lango la mtandao lina shughuli nyingi kwa sasa"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Imeunganishwa kupitia %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Inapatikana kupitia %1$s"</string>
@@ -82,9 +84,10 @@
     <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Imeunganishwa kwenye SAP"</string>
     <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Haijaunganishwa kwenye seva ya kuhamisha faili"</string>
     <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Umeunganishwa kwa kifaa cha kuingiza"</string>
-    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Umeunganishwa kwa kifaa cha ufikia Mtandao"</string>
-    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Kushiriki muunganisho wa mtandao wa nyumbani na kifaa"</string>
-    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Tumia kwa ufikiaji mtandao"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Imeunganishwa kwenye kifaa ili kufikia intaneti"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Inashiriki muunganisho wa intaneti wa kifaa na kifaa kingine"</string>
+    <!-- no translation found for bluetooth_pan_profile_summary_use_for (5736111170225304239) -->
+    <skip />
     <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Tumia kwa ramani"</string>
     <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Tumia kwa ufikiaji wa SIM"</string>
     <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Tumia kwa sauti ya media"</string>
@@ -296,6 +299,8 @@
     <string name="force_msaa_summary" msgid="9123553203895817537">"Wezesha 4x MSAA katika programu za OpenGL ES 2.0"</string>
     <string name="show_non_rect_clip" msgid="505954950474595172">"Tatua uendeshaji wa klipu usio mstatili"</string>
     <string name="track_frame_time" msgid="6146354853663863443">"Utungilizaji wa GPU ya wasifu"</string>
+    <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Ruhusu safu za utatuzi wa GPU"</string>
+    <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Ruhusu upakiaji wa safu za utatuzi wa GPU za programu za utatuzi"</string>
     <string name="window_animation_scale_title" msgid="6162587588166114700">"Uhuishaji kwenye dirisha"</string>
     <string name="transition_animation_scale_title" msgid="387527540523595875">"Mageuzi ya kipimo cha huiani"</string>
     <string name="animator_duration_scale_title" msgid="3406722410819934083">"Mizani ya muda wa uhuishaji"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 3a8b175..cb57c71 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -33,13 +33,15 @@
     <string name="wifi_check_password_try_again" msgid="516958988102584767">"கடவுச்சொல்லைச் சரிபார்த்து, மீண்டும் முயலவும்"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"தொடர்பு எல்லையில் இல்லை"</string>
     <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"தானாக இணைக்கப்படாது"</string>
-    <string name="wifi_no_internet" msgid="3880396223819116454">"இணைய அணுகல் இல்லை"</string>
+    <!-- no translation found for wifi_no_internet (4663834955626848401) -->
+    <skip />
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> சேமித்தது"</string>
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s மூலம் தானாக இணைக்கப்பட்டது"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"நெட்வொர்க் மதிப்பீடு வழங்குநரால் தானாக இணைக்கப்பட்டது"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s வழியாக இணைக்கப்பட்டது"</string>
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s வழியாகக் கிடைக்கிறது"</string>
-    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"இணைக்கப்பட்டது, இணையம் இல்லை"</string>
+    <!-- no translation found for wifi_connected_no_internet (8202906332837777829) -->
+    <skip />
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"தற்காலிகமாக அணுகல் புள்ளி நிரம்பியுள்ளது"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s வழியாக இணைக்கப்பட்டது"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s வழியாகக் கிடைக்கிறது"</string>
@@ -82,9 +84,10 @@
     <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP உடன் இணைக்கப்பட்டது"</string>
     <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"கோப்பு இடமாற்றும் சேவையகத்துடன் இணைக்கப்படவில்லை"</string>
     <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"உள்ளீட்டுச் சாதனத்துடன் இணைக்கப்பட்டது"</string>
-    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"இணைய அணுகலுக்காகச் சாதனம் இணைக்கப்பட்டது"</string>
-    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"சாதனத்துடன் அக இணைய இணைப்பைப் பகிர்கிறது"</string>
-    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"இணைய அணுகலுக்காகப் பயன்படுத்து"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"சாதனத்துடன் இணைந்தது"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"சாதனத்துடன் உள்ளூர் இண்டர்நெட்டைப் பகிர்தல்"</string>
+    <!-- no translation found for bluetooth_pan_profile_summary_use_for (5736111170225304239) -->
+    <skip />
     <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"வரைபடத்திற்குப் பயன்படுத்து"</string>
     <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"சிம் அணுகலுக்குப் பயன்படுத்தும்"</string>
     <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"மீடியாவின் ஆடியோவிற்குப் பயன்படுத்து"</string>
@@ -296,6 +299,8 @@
     <string name="force_msaa_summary" msgid="9123553203895817537">"OpenGL ES 2.0 பயன்பாடுகளில் 4x MSAA ஐ இயக்கு"</string>
     <string name="show_non_rect_clip" msgid="505954950474595172">"செவ்வகம் அல்லாத கிளிப் செயல்பாடுகளைப் பிழைத்திருத்து"</string>
     <string name="track_frame_time" msgid="6146354853663863443">"சுயவிவர GPU வழங்கல்"</string>
+    <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU பிழைத்திருத்த லேயர்களை இயக்கு"</string>
+    <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"பிழைத்திருத்த ஆப்ஸிற்கு, GPU பிழைத்திருத்த லேயர்களை ஏற்றுவதற்கு அனுமதி"</string>
     <string name="window_animation_scale_title" msgid="6162587588166114700">"சாளர அனிமேஷன் அளவு"</string>
     <string name="transition_animation_scale_title" msgid="387527540523595875">"அனிமேஷன் மாற்றத்தின் அளவு"</string>
     <string name="animator_duration_scale_title" msgid="3406722410819934083">"அனிமேட்டர் கால அளவு"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 4b3d2d4..e638b69 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -33,13 +33,15 @@
     <string name="wifi_check_password_try_again" msgid="516958988102584767">"Parolni tekshirib, qaytadan urining"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Xizmat doirasidan tashqarida"</string>
     <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Avtomatik ravishda ulanilmaydi"</string>
-    <string name="wifi_no_internet" msgid="3880396223819116454">"Internet aloqasi yo‘q"</string>
+    <!-- no translation found for wifi_no_internet (4663834955626848401) -->
+    <skip />
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> tomonidan saqlangan"</string>
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s orqali avtomatik ulandi"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Tarmoqlar reytingi muallifi orqali avtomatik ulandi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s orqali ulangan"</string>
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s orqali ishlaydi"</string>
-    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Ulangan, lekin internet aloqasi yo‘q"</string>
+    <!-- no translation found for wifi_connected_no_internet (8202906332837777829) -->
+    <skip />
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Internet kirish nuqtasi vaqtinchalik to‘lgan"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s orqali ulangan"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s orqali ishlaydi"</string>
@@ -82,9 +84,10 @@
     <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Ulanish nuqtasiga ulandi"</string>
     <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Fayl uzatish serveriga ulanmagan"</string>
     <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Kiritish qurilmasiga ulanildi"</string>
-    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Internet manbai qurilmasiga ulanildi"</string>
-    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Qurilmaga mahaliy internet aloqani tarqatish"</string>
-    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Internet manbai sifatida foydalanish"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Internet manbai qurilmasiga ulanildi"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Qurilma modem rejimida ishlamoqda"</string>
+    <!-- no translation found for bluetooth_pan_profile_summary_use_for (5736111170225304239) -->
+    <skip />
     <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Xaritada foydalanish"</string>
     <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM-kartaga kirish uchun foydalanish"</string>
     <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Audio qurilma uchun foydalanish"</string>
@@ -296,6 +299,8 @@
     <string name="force_msaa_summary" msgid="9123553203895817537">"OpenGL ES 2.0 ilovasidan 4x MSAAni yoqish"</string>
     <string name="show_non_rect_clip" msgid="505954950474595172">"To‘g‘ri burchakli bo‘lmagan kesishma amallarini tuzatish"</string>
     <string name="track_frame_time" msgid="6146354853663863443">"GPU ish vaqtini yozib olish"</string>
+    <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Grafik protsessorni tuzatish"</string>
+    <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Grafik protsessorni tuzatish qatlamlarini yuklashni yoqish"</string>
     <string name="window_animation_scale_title" msgid="6162587588166114700">"Oynalar animatsiyasi"</string>
     <string name="transition_animation_scale_title" msgid="387527540523595875">"O‘tish animatsiyasi"</string>
     <string name="animator_duration_scale_title" msgid="3406722410819934083">"Animatsiya tezligi"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 2215fe5..13053f8 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -33,13 +33,15 @@
     <string name="wifi_check_password_try_again" msgid="516958988102584767">"請檢查密碼,然後再試一次"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"不在有效範圍內"</string>
     <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"無法自動連線"</string>
-    <string name="wifi_no_internet" msgid="3880396223819116454">"沒有可用的網際網路連線"</string>
+    <!-- no translation found for wifi_no_internet (4663834955626848401) -->
+    <skip />
     <string name="saved_network" msgid="4352716707126620811">"由「<xliff:g id="NAME">%1$s</xliff:g>」儲存"</string>
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"已透過 %1$s 自動連線"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"已透過網路評分供應商自動連線"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"已透過 %1$s 連線"</string>
     <string name="available_via_passpoint" msgid="1617440946846329613">"可透過 %1$s 使用"</string>
-    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"已連線,沒有網際網路"</string>
+    <!-- no translation found for wifi_connected_no_internet (8202906332837777829) -->
+    <skip />
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"存取點暫時滿載"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"已透過 %1$s 連線"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"可透過 %1$s 使用"</string>
@@ -82,9 +84,10 @@
     <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"已連線到 SAP"</string>
     <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"不要連線到檔案傳輸伺服器"</string>
     <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"已連線到輸入裝置"</string>
-    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"已連線至裝置並取得網際網路存取權"</string>
-    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"與裝置分享本地網際網路連線"</string>
-    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"用於網際網路連線"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"已連線至裝置並取得網際網路連線"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"與裝置分享本地網際網路連線"</string>
+    <!-- no translation found for bluetooth_pan_profile_summary_use_for (5736111170225304239) -->
+    <skip />
     <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"地圖使用偏好"</string>
     <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"用於 SIM 卡存取權"</string>
     <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"用於媒體音訊"</string>
@@ -296,6 +299,8 @@
     <string name="force_msaa_summary" msgid="9123553203895817537">"在 OpenGL ES 2.0 應用程式中啟用 4x MSAA"</string>
     <string name="show_non_rect_clip" msgid="505954950474595172">"針對非矩形裁剪操作進行偵錯"</string>
     <string name="track_frame_time" msgid="6146354853663863443">"剖析 GPU 轉譯"</string>
+    <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"啟用 GPU 偵錯圖層"</string>
+    <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"允許載入 GPU 偵錯圖層為應用程式偵錯"</string>
     <string name="window_animation_scale_title" msgid="6162587588166114700">"視窗動畫比例"</string>
     <string name="transition_animation_scale_title" msgid="387527540523595875">"轉場動畫比例"</string>
     <string name="animator_duration_scale_title" msgid="3406722410819934083">"動畫影片長度比例"</string>
diff --git a/packages/SettingsLib/res/values/styles_support_preference.xml b/packages/SettingsLib/res/values/styles_support_preference.xml
index cf9f3c6..d7032b8 100644
--- a/packages/SettingsLib/res/values/styles_support_preference.xml
+++ b/packages/SettingsLib/res/values/styles_support_preference.xml
@@ -20,73 +20,14 @@
 
     <dimen name="preference_no_icon_padding_start">72dp</dimen>
 
-    <!-- Fragment style -->
-    <style name="PreferenceFragmentStyle.SettingsBase" parent="@*android:style/PreferenceFragment.Material">
-        <item name="allowDividerAfterLastItem">false</item>
-    </style>
-
-    <!-- Preferences -->
-    <style name="Preference.SettingsBase" parent="@style/Preference.Material">
-        <item name="allowDividerAbove">false</item>
-        <item name="allowDividerBelow">true</item>
-        <item name="singleLineTitle">false</item>
-        <item name="iconSpaceReserved">true</item>
-    </style>
-
-    <!-- Preference category -->
-    <style name="Preference.Category.SettingsBase" parent="@style/Preference.Category.Material">
-        <item name="allowDividerAbove">true</item>
-        <item name="allowDividerBelow">true</item>
-        <item name="android:layout">@layout/preference_category_material_settings</item>
-    </style>
-
-    <!-- Preference screen -->
-    <style name="Preference.Screen.SettingsBase" parent="@style/Preference.PreferenceScreen.Material">
-        <item name="allowDividerAbove">false</item>
-        <item name="allowDividerBelow">true</item>
-        <item name="iconSpaceReserved">true</item>
-    </style>
-
     <!-- Footer Preferences -->
-    <style name="Preference.FooterPreference.SettingsBase" parent="Preference.SettingsBase">
+    <style name="Preference.FooterPreference.SettingsBase" parent="@style/Preference.Material">
         <item name="android:layout">@layout/preference_footer</item>
         <item name="allowDividerAbove">true</item>
     </style>
 
-    <!-- Dropdown Preferences -->
-    <style name="Preference.DropdownPreference.SettingsBase" parent="Preference.SettingsBase">
-        <item name="android:layout">@layout/preference_dropdown_material_settings</item>
-    </style>
-
-    <!-- Switch Preferences -->
-    <style name="Preference.SwitchPreference.SettingsBase" parent="@style/Preference.SwitchPreference.Material">
-        <item name="allowDividerAbove">false</item>
-        <item name="allowDividerBelow">true</item>
-        <item name="iconSpaceReserved">true</item>
-        <item name="singleLineTitle">false</item>
-    </style>
-
-    <!-- EditText Preferences -->
-    <style name="Preference.EditTextPreference.SettingsBase"
-           parent="@style/Preference.DialogPreference.EditTextPreference.Material">
-        <item name="allowDividerAbove">false</item>
-        <item name="allowDividerBelow">true</item>
-        <item name="iconSpaceReserved">true</item>
-        <item name="singleLineTitle">false</item>
-    </style>
-
     <style name="PreferenceThemeOverlay.SettingsBase" parent="@style/PreferenceThemeOverlay.v14.Material">
-        <!-- Parent path frameworks/support/v14/preference/res/values/themes.xml -->
-        <item name="android:scrollbars">vertical</item>
-        <item name="preferenceFragmentStyle">@style/PreferenceFragmentStyle.SettingsBase</item>
-        <item name="preferenceCategoryStyle">@style/Preference.Category.SettingsBase</item>
-        <item name="preferenceScreenStyle">@style/Preference.Screen.SettingsBase</item>
-        <item name="preferenceStyle">@style/Preference.SettingsBase</item>
-        <item name="dialogPreferenceStyle">@style/Preference.SettingsBase</item>
-        <item name="editTextPreferenceStyle">@style/Preference.EditTextPreference.SettingsBase</item>
         <item name="footerPreferenceStyle">@style/Preference.FooterPreference.SettingsBase</item>
-        <item name="switchPreferenceStyle">@style/Preference.SwitchPreference.SettingsBase</item>
-        <item name="dropdownPreferenceStyle">@style/Preference.DropdownPreference.SettingsBase</item>
     </style>
 
 </resources>
\ No newline at end of file
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index ba1c9e3..52b4f4d 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -801,6 +801,9 @@
                 Settings.Global.BLUETOOTH_PAN_PRIORITY_PREFIX,
                 GlobalSettingsProto.BLUETOOTH_PAN_PRIORITY_PREFIX);
         dumpSetting(s, p,
+                Settings.Global.BLUETOOTH_HEARING_AID_PRIORITY_PREFIX,
+                GlobalSettingsProto.BLUETOOTH_HEARING_AID_PRIORITY_PREFIX);
+        dumpSetting(s, p,
                 Settings.Global.ACTIVITY_MANAGER_CONSTANTS,
                 GlobalSettingsProto.ACTIVITY_MANAGER_CONSTANTS);
         dumpSetting(s, p,
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 58bddb0..581ac73 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -51,21 +51,15 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"ব্লুটুথ টিথার করা হয়েছে"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"ইনপুট পদ্ধতিগুলি সেট আপ করুন"</string>
     <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"ফিজিক্যাল কীবোর্ড"</string>
-    <!-- no translation found for usb_device_permission_prompt (1825685909587559679) -->
-    <skip />
-    <!-- no translation found for usb_accessory_permission_prompt (2465531696941369047) -->
-    <skip />
-    <!-- no translation found for usb_device_confirm_prompt (7440562274256843905) -->
-    <skip />
-    <!-- no translation found for usb_accessory_confirm_prompt (4333670517539993561) -->
-    <skip />
+    <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="APPLICATION">%1$s</xliff:g> কে <xliff:g id="USB_DEVICE">%2$s</xliff:g> অ্যাক্সেস করতে দেবেন?"</string>
+    <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="APPLICATION">%1$s</xliff:g> কে <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> অ্যাক্সেস করতে দেবেন?"</string>
+    <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ব্যবহার করার জন্য <xliff:g id="APPLICATION">%1$s</xliff:g> চালু করবেন?"</string>
+    <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ব্যবহার করার জন্য <xliff:g id="APPLICATION">%1$s</xliff:g> চালু করবেন?"</string>
     <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"ইনস্টল থাকা কোনো অ্যাপ্লিকেশান এই USB যন্ত্রাংশের সাথে কাজ করে না৷ <xliff:g id="URL">%1$s</xliff:g> এ এই যন্ত্রাংশের সম্পর্কে আরও জানুন৷"</string>
     <string name="title_usb_accessory" msgid="4966265263465181372">"USB যন্ত্রাংশ"</string>
     <string name="label_view" msgid="6304565553218192990">"দেখুন"</string>
-    <!-- no translation found for always_use_device (4015357883336738417) -->
-    <skip />
-    <!-- no translation found for always_use_accessory (3257892669444535154) -->
-    <skip />
+    <string name="always_use_device" msgid="4015357883336738417">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> যখনই সংযুক্ত থাকবে তখনই <xliff:g id="APPLICATION">%1$s</xliff:g> চালু হবে"</string>
+    <string name="always_use_accessory" msgid="3257892669444535154">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> যখনই সংযুক্ত থাকবে তখনই <xliff:g id="APPLICATION">%1$s</xliff:g> চালু হবে"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"USB ডিবাগিং মঞ্জুর করবেন?"</string>
     <string name="usb_debugging_message" msgid="2220143855912376496">"কম্পিউটারের RSA কী আঙ্গুলের ছাপ হল:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"এই কম্পিউটার থেকে সর্বদা অনুমতি দিন"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 6db3e38..dcf8336 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -51,21 +51,15 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Xarxa compartida per Bluetooth"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Configura els mètodes d\'entrada"</string>
     <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Teclat físic"</string>
-    <!-- no translation found for usb_device_permission_prompt (1825685909587559679) -->
-    <skip />
-    <!-- no translation found for usb_accessory_permission_prompt (2465531696941369047) -->
-    <skip />
-    <!-- no translation found for usb_device_confirm_prompt (7440562274256843905) -->
-    <skip />
-    <!-- no translation found for usb_accessory_confirm_prompt (4333670517539993561) -->
-    <skip />
+    <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Vols permetre que <xliff:g id="APPLICATION">%1$s</xliff:g> accedeixi a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+    <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Vols permetre que <xliff:g id="APPLICATION">%1$s</xliff:g> accedeixi a <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+    <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Vols obrir <xliff:g id="APPLICATION">%1$s</xliff:g> per gestionar <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+    <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Vols obrir <xliff:g id="APPLICATION">%1$s</xliff:g> per gestionar <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
     <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Les aplicacions instal·lades no funcionen amb l\'accessori USB. Més informació: <xliff:g id="URL">%1$s</xliff:g>"</string>
     <string name="title_usb_accessory" msgid="4966265263465181372">"Accessori USB"</string>
     <string name="label_view" msgid="6304565553218192990">"Mostra"</string>
-    <!-- no translation found for always_use_device (4015357883336738417) -->
-    <skip />
-    <!-- no translation found for always_use_accessory (3257892669444535154) -->
-    <skip />
+    <string name="always_use_device" msgid="4015357883336738417">"Obre sempre <xliff:g id="APPLICATION">%1$s</xliff:g> quan es connecti <xliff:g id="USB_DEVICE">%2$s</xliff:g>"</string>
+    <string name="always_use_accessory" msgid="3257892669444535154">"Obre sempre <xliff:g id="APPLICATION">%1$s</xliff:g> quan es connecti <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Vols permetre la depuració USB?"</string>
     <string name="usb_debugging_message" msgid="2220143855912376496">"L\'empremta digital de la clau de l\'RSA de l\'equip és:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Dona sempre permís des d\'aquest equip"</string>
@@ -587,7 +581,7 @@
       <item quantity="other">%d minuts</item>
       <item quantity="one">%d minut</item>
     </plurals>
-    <string name="battery_panel_title" msgid="7944156115535366613">"Ús de la bateria"</string>
+    <string name="battery_panel_title" msgid="7944156115535366613">"Consum de la bateria"</string>
     <string name="battery_detail_charging_summary" msgid="4055327085770378335">"La funció Estalvi de bateria no està disponible durant la càrrega"</string>
     <string name="battery_detail_switch_title" msgid="8763441006881907058">"Estalvi de bateria"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Redueix el rendiment i les dades en segon pla"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index ef66a35..dd1f729 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -44,28 +44,22 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"बैटरी बचाएँ"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"सेटिंग"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"वाई-फ़ाई"</string>
-    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"स्‍क्रीन अपनेआप घुमाएं"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"स्‍क्रीन अपने आप घुमाएं"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"म्यूट करें"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"स्वत:"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"सूचनाएं"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"ब्लूटूथ टीदर किया गया"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"इनपुट का तरीका सेट करें"</string>
     <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"भौतिक कीबोर्ड"</string>
-    <!-- no translation found for usb_device_permission_prompt (1825685909587559679) -->
-    <skip />
-    <!-- no translation found for usb_accessory_permission_prompt (2465531696941369047) -->
-    <skip />
-    <!-- no translation found for usb_device_confirm_prompt (7440562274256843905) -->
-    <skip />
-    <!-- no translation found for usb_accessory_confirm_prompt (4333670517539993561) -->
-    <skip />
+    <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="APPLICATION">%1$s</xliff:g> को <xliff:g id="USB_DEVICE">%2$s</xliff:g> के एक्सेस की अनुमति दें?"</string>
+    <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="APPLICATION">%1$s</xliff:g> को <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> के एक्सेस की अनुमति दें?"</string>
+    <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> के लिए <xliff:g id="APPLICATION">%1$s</xliff:g> खोलें?"</string>
+    <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> के लिए <xliff:g id="APPLICATION">%1$s</xliff:g> खोलें?"</string>
     <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"इस USB सहायक डिवाइस के साथ कोई भी इंस्टॉल ऐप्स  काम नहीं करता. इस सहायक डिवाइस के बारे में यहां अधिक जानें: <xliff:g id="URL">%1$s</xliff:g>"</string>
     <string name="title_usb_accessory" msgid="4966265263465181372">"USB सहायक साधन"</string>
     <string name="label_view" msgid="6304565553218192990">"देखें"</string>
-    <!-- no translation found for always_use_device (4015357883336738417) -->
-    <skip />
-    <!-- no translation found for always_use_accessory (3257892669444535154) -->
-    <skip />
+    <string name="always_use_device" msgid="4015357883336738417">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> के कनेक्ट होने पर हमेशा <xliff:g id="APPLICATION">%1$s</xliff:g> खोलें"</string>
+    <string name="always_use_accessory" msgid="3257892669444535154">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> के कनेक्ट होने पर हमेशा <xliff:g id="APPLICATION">%1$s</xliff:g> खोलें"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"USB डीबगिंग करने दें?"</string>
     <string name="usb_debugging_message" msgid="2220143855912376496">"कंप्यूटर का RSA कुंजी फ़िंगरप्रिंट है:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"इस कंप्यूटर से हमेशा अनुमति दें"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index b03d6bf..b882c5e 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -51,21 +51,15 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"ब्लूटूथ टेदर केले"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"इनपुट पद्धती सेट करा"</string>
     <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"वास्तविक कीबोर्ड"</string>
-    <!-- no translation found for usb_device_permission_prompt (1825685909587559679) -->
-    <skip />
-    <!-- no translation found for usb_accessory_permission_prompt (2465531696941369047) -->
-    <skip />
-    <!-- no translation found for usb_device_confirm_prompt (7440562274256843905) -->
-    <skip />
-    <!-- no translation found for usb_accessory_confirm_prompt (4333670517539993561) -->
-    <skip />
+    <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="APPLICATION">%1$s</xliff:g> ला <xliff:g id="USB_DEVICE">%2$s</xliff:g> अॅक्सेस करण्याची अनुमती द्यायची का?"</string>
+    <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="APPLICATION">%1$s</xliff:g> ला <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> अॅक्सेस करण्याची अनुमती द्यायची का?"</string>
+    <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> हाताळण्यासाठी <xliff:g id="APPLICATION">%1$s</xliff:g> उघडायचे का?"</string>
+    <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> हाताळण्यासाठी <xliff:g id="APPLICATION">%1$s</xliff:g> उघडायचे का?"</string>
     <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"इंस्टॉल केलेले अॅप्स या USB उपसाधनासह कार्य करत नाहीत. <xliff:g id="URL">%1$s</xliff:g> येथे या उपसाधनाविषयी अधिक जाणून घ्या"</string>
     <string name="title_usb_accessory" msgid="4966265263465181372">"USB उपसाधन"</string>
     <string name="label_view" msgid="6304565553218192990">"पहा"</string>
-    <!-- no translation found for always_use_device (4015357883336738417) -->
-    <skip />
-    <!-- no translation found for always_use_accessory (3257892669444535154) -->
-    <skip />
+    <string name="always_use_device" msgid="4015357883336738417">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> कनेक्ट केलेली असताना नेहमी <xliff:g id="APPLICATION">%1$s</xliff:g> उघडा"</string>
+    <string name="always_use_accessory" msgid="3257892669444535154">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> कनेक्ट केलेली असताना नेहमी <xliff:g id="APPLICATION">%1$s</xliff:g> उघडा"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"USB डीबग करण्यास अनुमती द्यायची?"</string>
     <string name="usb_debugging_message" msgid="2220143855912376496">"संगणकाची RSA की फिंगरप्रिंट ही आहे:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"या संगणकावरून नेहमी अनुमती द्या"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 02d6613..9972c73 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -51,21 +51,15 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"புளூடூத் இணைக்கப்பட்டது"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"உள்ளீட்டு முறைகளை அமை"</string>
     <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"கைமுறை விசைப்பலகை"</string>
-    <!-- no translation found for usb_device_permission_prompt (1825685909587559679) -->
-    <skip />
-    <!-- no translation found for usb_accessory_permission_prompt (2465531696941369047) -->
-    <skip />
-    <!-- no translation found for usb_device_confirm_prompt (7440562274256843905) -->
-    <skip />
-    <!-- no translation found for usb_accessory_confirm_prompt (4333670517539993561) -->
-    <skip />
+    <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>ஐ அணுக, <xliff:g id="APPLICATION">%1$s</xliff:g> பயன்பாட்டை அனுமதிக்கவா?"</string>
+    <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>ஐ அணுக, <xliff:g id="APPLICATION">%1$s</xliff:g> பயன்பாட்டை அனுமதிக்கவா?"</string>
+    <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>ஐக் கையாள, <xliff:g id="APPLICATION">%1$s</xliff:g> பயன்பாட்டைத் திறக்கவா?"</string>
+    <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>ஐக் கையாள, <xliff:g id="APPLICATION">%1$s</xliff:g> பயன்பாட்டைத் திறக்கவா?"</string>
     <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"நிறுவிய பயன்பாடுகள் எதுவும், USB துணைக்கருவியுடன் இயங்காது. <xliff:g id="URL">%1$s</xliff:g> இல் துணைக்கருவி குறித்து மேலும் அறிக"</string>
     <string name="title_usb_accessory" msgid="4966265263465181372">"USB துணைக்கருவி"</string>
     <string name="label_view" msgid="6304565553218192990">"காட்சி"</string>
-    <!-- no translation found for always_use_device (4015357883336738417) -->
-    <skip />
-    <!-- no translation found for always_use_accessory (3257892669444535154) -->
-    <skip />
+    <string name="always_use_device" msgid="4015357883336738417">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> இணைக்கப்பட்டிருக்கையில், <xliff:g id="APPLICATION">%1$s</xliff:g>ஐ எப்போதும் திற"</string>
+    <string name="always_use_accessory" msgid="3257892669444535154">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> இணைக்கப்பட்டிருக்கையில், <xliff:g id="APPLICATION">%1$s</xliff:g>ஐ எப்போதும் திற"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"USB பிழைத்திருத்தத்தை அனுமதிக்கவா?"</string>
     <string name="usb_debugging_message" msgid="2220143855912376496">"பின்வருவது கணினியின் RSA விசை கைரேகையாகும்:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"இந்தக் கணினியிலிருந்து எப்போதும் அனுமதி"</string>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index b132160..ca85445 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -67,7 +67,7 @@
     <string name="battery_low_percent_format"><xliff:g id="percentage">%s</xliff:g> remaining</string>
 
     <!-- Same as battery_low_percent_format, with a notice about battery saver if on. [CHAR LIMIT=none]-->
-    <string name="battery_low_percent_format_saver_started"><xliff:g id="percentage">%s</xliff:g> remaining. Battery saver is on.</string>
+    <string name="battery_low_percent_format_saver_started"><xliff:g id="percentage">%s</xliff:g> remaining. Battery Saver is on.</string>
 
     <!-- A message that appears when a USB charger is plugged in and the device does not
     support charging on it.  That is, a charger that fits into the USB port and goes into
@@ -86,13 +86,13 @@
     <string name="battery_low_why">Settings</string>
 
     <!-- Battery saver confirmation dialog title [CHAR LIMIT=NONE]-->
-    <string name="battery_saver_confirmation_title">Turn on battery saver?</string>
+    <string name="battery_saver_confirmation_title">Turn on Battery Saver?</string>
 
     <!-- Battery saver confirmation dialog ok text [CHAR LIMIT=40]-->
     <string name="battery_saver_confirmation_ok">Turn on</string>
 
     <!-- Battery saver notification action [CHAR LIMIT=NONE]-->
-    <string name="battery_saver_start_action">Turn on battery saver</string>
+    <string name="battery_saver_start_action">Turn on Battery Saver</string>
 
     <!-- Name of the button that links to the Settings app. [CHAR LIMIT=NONE] -->
     <string name="status_bar_settings_settings_button">Settings</string>
@@ -583,18 +583,6 @@
     <!-- Dialog button indicating that data connection should be re-enabled. [CHAR LIMIT=28] -->
     <string name="data_usage_disabled_dialog_enable">Resume</string>
 
-    <!-- Text to display underneath the graphical signal strength meter when
-         no connection is available. [CHAR LIMIT=20] -->
-    <string name="status_bar_settings_signal_meter_disconnected">
-        No Internet connection
-    </string>
-
-    <!-- Text to display underneath the graphical signal strength meter when
-         it is displaying Wi-Fi status and Wi-Fi is connected to a network
-         whose SSID is not available.
-         [CHAR LIMIT=20] -->
-    <string name="status_bar_settings_signal_meter_wifi_nossid">Wi-Fi connected</string>
-
     <!-- Notification text: when GPS is getting a fix [CHAR LIMIT=50] -->
     <string name="gps_notification_searching_text">Searching for GPS</string>
 
@@ -989,13 +977,13 @@
     <string name="user_remove_user_remove">Remove</string>
 
     <!-- Battery saver notification title. [CHAR LIMIT=60]-->
-    <string name="battery_saver_notification_title">Battery saver is on</string>
+    <string name="battery_saver_notification_title">Battery Saver is on</string>
 
     <!-- Battery saver notification text. [CHAR LIMIT=60] -->
     <string name="battery_saver_notification_text">Reduces performance and background data</string>
 
     <!-- Battery saver notification action text. [CHAR LIMIT=60] -->
-    <string name="battery_saver_notification_action_text">Turn off battery saver</string>
+    <string name="battery_saver_notification_action_text">Turn off Battery Saver</string>
 
     <!-- Media projection permission dialog warning text. [CHAR LIMIT=NONE] -->
     <string name="media_projection_dialog_text"><xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g> will start capturing everything that\'s displayed on your screen.</string>
@@ -1532,10 +1520,10 @@
     <string name="battery_panel_title">Battery usage</string>
 
     <!-- Summary of battery saver not available [CHAR LIMIT=NONE] -->
-    <string name="battery_detail_charging_summary">Battery saver not available during charging</string>
+    <string name="battery_detail_charging_summary">Battery Saver not available during charging</string>
 
     <!-- Title of switch for battery saver [CHAR LIMIT=NONE] -->
-    <string name="battery_detail_switch_title">Battery saver</string>
+    <string name="battery_detail_switch_title">Battery Saver</string>
 
     <!-- Summary of switch for battery saver [CHAR LIMIT=NONE] -->
     <string name="battery_detail_switch_summary">Reduces performance and background data</string>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index f6fab86..eb2d12e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -319,32 +319,39 @@
         mBackgroundExecutor.submit(new Runnable() {
             @Override
             public void run() {
+                boolean result = false;
                 try {
-                    ActivityManager.getService().startActivityFromRecents(taskKey.id,
-                            finalOptions == null ? null : finalOptions.toBundle());
-                    if (resultCallback != null) {
-                        resultCallbackHandler.post(new Runnable() {
-                            @Override
-                            public void run() {
-                                resultCallback.accept(true);
-                            }
-                        });
-                    }
+                    result = startActivityFromRecents(taskKey.id, finalOptions);
                 } catch (Exception e) {
-                    if (resultCallback != null) {
-                        resultCallbackHandler.post(new Runnable() {
-                            @Override
-                            public void run() {
-                                resultCallback.accept(false);
-                            }
-                        });
-                    }
+                    // Fall through
+                }
+                final boolean finalResult = result;
+                if (resultCallback != null) {
+                    resultCallbackHandler.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            resultCallback.accept(finalResult);
+                        }
+                    });
                 }
             }
         });
     }
 
     /**
+     * Starts a task from Recents synchronously.
+     */
+    public boolean startActivityFromRecents(int taskId, ActivityOptions options) {
+        try {
+            Bundle optsBundle = options == null ? null : options.toBundle();
+            ActivityManager.getService().startActivityFromRecents(taskId, optsBundle);
+            return true;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+    /**
      * Registers a task stack listener with the system.
      * This should be called on the main thread.
      */
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
new file mode 100644
index 0000000..705a215
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.shared.system;
+
+import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
+import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+
+import android.app.ActivityOptions;
+
+/**
+ * Wrapper around internal ActivityOptions creation.
+ */
+public abstract class ActivityOptionsCompat {
+
+    /**
+     * @return ActivityOptions for starting a task in split screen.
+     */
+    public static ActivityOptions makeSplitScreenOptions(boolean dockTopLeft) {
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+        options.setSplitScreenCreateMode(dockTopLeft
+                ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
+                : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT);
+        return options;
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
index 1477558..225dbb4 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
@@ -19,8 +19,15 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 
 import android.graphics.Rect;
+import android.os.Handler;
+import android.os.IRemoteCallback;
+import android.os.RemoteException;
+import android.util.Log;
 import android.view.WindowManagerGlobal;
 
+import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
+import com.android.systemui.shared.recents.view.RecentsTransition;
+
 public class WindowManagerWrapper {
 
     private static final String TAG = "WindowManagerWrapper";
@@ -38,8 +45,24 @@
         try {
             WindowManagerGlobal.getWindowManagerService().getStableInsets(DEFAULT_DISPLAY,
                     outStableInsets);
-        } catch (Exception e) {
-            e.printStackTrace();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to get stable insets", e);
+        }
+    }
+
+    /**
+     * Overrides a pending app transition.
+     */
+    public void overridePendingAppTransitionMultiThumbFuture(
+            AppTransitionAnimationSpecsFuture animationSpecFuture,
+            Runnable animStartedCallback, Handler animStartedCallbackHandler, boolean scaleUp) {
+        try {
+            WindowManagerGlobal.getWindowManagerService()
+                    .overridePendingAppTransitionMultiThumbFuture(animationSpecFuture.getFuture(),
+                            RecentsTransition.wrapStartedListener(animStartedCallbackHandler,
+                                    animStartedCallback), scaleUp);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to override pending app transition (multi-thumbnail future): ", e);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 5a02178..8d55eea 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -21,7 +21,7 @@
 import android.os.SystemClock;
 import android.hardware.fingerprint.FingerprintManager;
 import android.telephony.TelephonyManager;
-import android.view.WindowManagerPolicy;
+import android.view.WindowManagerPolicyConstants;
 
 import com.android.internal.telephony.IccCardConstants;
 
@@ -171,9 +171,9 @@
 
     /**
      * Called when the device has finished going to sleep.
-     * @param why either {@link WindowManagerPolicy#OFF_BECAUSE_OF_ADMIN},
-     * {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER}, or
-     * {@link WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT}.
+     * @param why either {@link WindowManagerPolicyConstants#OFF_BECAUSE_OF_ADMIN},
+     * {@link WindowManagerPolicyConstants#OFF_BECAUSE_OF_USER}, or
+     * {@link WindowManagerPolicyConstants#OFF_BECAUSE_OF_TIMEOUT}.
      *
      * @deprecated use {@link com.android.systemui.keyguard.WakefulnessLifecycle}.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index a35ba9f..b99e76a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -60,7 +60,7 @@
 import android.util.Log;
 import android.util.Slog;
 import android.view.ViewGroup;
-import android.view.WindowManagerPolicy;
+import android.view.WindowManagerPolicyConstants;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
 
@@ -129,7 +129,7 @@
  * false, this will override all other conditions for turning on the keyguard.
  *
  * Threading and synchronization:
- * This class is created by the initialization routine of the {@link android.view.WindowManagerPolicy},
+ * This class is created by the initialization routine of the {@link WindowManagerPolicyConstants},
  * and runs on its thread.  The keyguard UI is created from that thread in the
  * constructor of this class.  The apis may be called from other threads, including the
  * {@link com.android.server.input.InputManagerService}'s and {@link android.view.WindowManager}'s.
@@ -766,8 +766,8 @@
 
     /**
      * Called to let us know the screen was turned off.
-     * @param why either {@link android.view.WindowManagerPolicy#OFF_BECAUSE_OF_USER} or
-     *   {@link android.view.WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT}.
+     * @param why either {@link WindowManagerPolicyConstants#OFF_BECAUSE_OF_USER} or
+     *   {@link WindowManagerPolicyConstants#OFF_BECAUSE_OF_TIMEOUT}.
      */
     public void onStartedGoingToSleep(int why) {
         if (DEBUG) Log.d(TAG, "onStartedGoingToSleep(" + why + ")");
@@ -797,8 +797,8 @@
                 }
             } else if (mShowing) {
                 mPendingReset = true;
-            } else if ((why == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT && timeout > 0)
-                    || (why == WindowManagerPolicy.OFF_BECAUSE_OF_USER && !lockImmediately)) {
+            } else if ((why == WindowManagerPolicyConstants.OFF_BECAUSE_OF_TIMEOUT && timeout > 0)
+                    || (why == WindowManagerPolicyConstants.OFF_BECAUSE_OF_USER && !lockImmediately)) {
                 doKeyguardLaterLocked(timeout);
                 mLockLater = true;
             } else if (!mLockPatternUtils.isLockScreenDisabled(currentUser)) {
@@ -1031,7 +1031,7 @@
     }
 
     /**
-     * Same semantics as {@link android.view.WindowManagerPolicy#enableKeyguard}; provide
+     * Same semantics as {@link WindowManagerPolicyConstants#enableKeyguard}; provide
      * a way for external stuff to override normal keyguard behavior.  For instance
      * the phone app disables the keyguard when it receives incoming calls.
      */
@@ -1780,13 +1780,13 @@
                 int flags = 0;
                 if (mStatusBarKeyguardViewManager.shouldDisableWindowAnimationsForUnlock()
                         || mWakeAndUnlocking) {
-                    flags |= WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
+                    flags |= WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
                 }
                 if (mStatusBarKeyguardViewManager.isGoingToNotificationShade()) {
-                    flags |= WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
+                    flags |= WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
                 }
                 if (mStatusBarKeyguardViewManager.isUnlockWithWallpaper()) {
-                    flags |= WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
+                    flags |= WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
                 }
 
                 mUpdateMonitor.setKeyguardGoingAway(true /* goingAway */);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 3b1b2f9..9400fd8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -156,7 +156,8 @@
                     // Launched from app is always the worst case (in terms of how many
                     // thumbnails/tasks visible)
                     launchState.launchedFromApp = true;
-                    mBackgroundLayoutAlgorithm.update(plan.getTaskStack(), EMPTY_SET, launchState);
+                    mBackgroundLayoutAlgorithm.update(plan.getTaskStack(), EMPTY_SET, launchState,
+                            -1 /* lastScrollPPresent */);
                     VisibilityReport visibilityReport =
                             mBackgroundLayoutAlgorithm.computeStackVisibilityReport(
                                     stack.getTasks());
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index d89bab7..cf3cae5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -21,12 +21,10 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 
-import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManager.StackInfo;
 import android.app.ActivityOptions;
@@ -49,9 +47,6 @@
 import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.os.IRemoteCallback;
-import android.os.Looper;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
@@ -63,7 +58,6 @@
 import android.util.Log;
 import android.util.MutableBoolean;
 import android.view.Display;
-import android.view.IAppTransitionAnimationSpecsFuture;
 import android.view.IDockedStackListener;
 import android.view.IWindowManager;
 import android.view.WindowManager;
@@ -78,12 +72,9 @@
 import com.android.systemui.UiOffloadThread;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsImpl;
-import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.system.TaskStackChangeListeners;
 import com.android.systemui.statusbar.policy.UserInfoController;
 
 import java.util.List;
-import java.util.function.Consumer;
 
 /**
  * Acts as a shim around the real system services that we need to access data from, and provides
@@ -268,22 +259,6 @@
         return mIsSafeMode;
     }
 
-    /** Docks a task to the side of the screen and starts it. */
-    public boolean startTaskInDockedMode(int taskId, int createMode) {
-        if (mIam == null) return false;
-
-        try {
-            final ActivityOptions options = ActivityOptions.makeBasic();
-            options.setSplitScreenCreateMode(createMode);
-            options.setLaunchWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
-            mIam.startActivityFromRecents(taskId, options.toBundle());
-            return true;
-        } catch (Exception e) {
-            Log.e(TAG, "Failed to dock task: " + taskId + " with createMode: " + createMode, e);
-        }
-        return false;
-    }
-
     /** Moves an already resumed task to the side of the screen to initiate split screen. */
     public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode,
             Rect initialBounds) {
@@ -540,16 +515,6 @@
         }
     }
 
-    public void overridePendingAppTransitionMultiThumbFuture(
-            IAppTransitionAnimationSpecsFuture future, IRemoteCallback animStartedListener,
-            boolean scaleUp) {
-        try {
-            mIwm.overridePendingAppTransitionMultiThumbFuture(future, animStartedListener, scaleUp);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Failed to override transition: " + e);
-        }
-    }
-
     /**
      * Updates the visibility of recents.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 1440fc1..e3ed1aa 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -16,13 +16,14 @@
 
 package com.android.systemui.recents.views;
 
+import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
+
 import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS;
 
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.annotation.Nullable;
 import android.app.ActivityOptions;
-import android.app.ActivityOptions.OnAnimationStartedListener;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.graphics.Canvas;
@@ -33,11 +34,11 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
+import android.os.IRemoteCallback;
 import android.util.ArraySet;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.MathUtils;
-import android.view.AppTransitionAnimationSpec;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -86,13 +87,15 @@
 import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
 import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.shared.recents.utilities.Utilities;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.TaskStack;
+import com.android.systemui.shared.recents.utilities.Utilities;
 import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat;
 import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
 import com.android.systemui.shared.recents.view.RecentsTransition;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.ActivityOptionsCompat;
+import com.android.systemui.shared.system.WindowManagerWrapper;
 import com.android.systemui.stackdivider.WindowManagerProxy;
 import com.android.systemui.statusbar.FlingAnimationUtils;
 import com.android.systemui.statusbar.phone.ScrimController;
@@ -608,16 +611,17 @@
             // rect to its final layout-space rect
             Utilities.setViewFrameFromTranslation(event.taskView);
 
-            // Dock the task and launch it
-            SystemServicesProxy ssp = Recents.getSystemServices();
-            if (ssp.startTaskInDockedMode(event.task.key.id, dockState.createMode)) {
+            final ActivityOptions options = ActivityOptionsCompat.makeSplitScreenOptions(
+                    dockState.createMode == SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT);
+            if (ActivityManagerWrapper.getInstance().startActivityFromRecents(event.task.key.id,
+                    options)) {
                 final Runnable animStartedListener = () -> {
                     EventBus.getDefault().send(new DockedFirstAnimationFrameEvent());
-                    // Remove the task and don't bother relaying out, as all the tasks will be
-                    // relaid out when the stack changes on the multiwindow change event
+                    // Remove the task and don't bother relaying out, as all the tasks
+                    // will be relaid out when the stack changes on the multiwindow
+                    // change event
                     getStack().removeTask(event.task, null, true /* fromDockGesture */);
                 };
-
                 final Rect taskRect = getTaskRect(event.taskView);
                 AppTransitionAnimationSpecsFuture future = new AppTransitionAnimationSpecsFuture(
                         getHandler()) {
@@ -626,10 +630,8 @@
                         return mTransitionHelper.composeDockAnimationSpec(event.taskView, taskRect);
                     }
                 };
-                ssp.overridePendingAppTransitionMultiThumbFuture(future.getFuture(),
-                        RecentsTransition.wrapStartedListener(getHandler(), animStartedListener),
-                        true /* scaleUp */);
-
+                WindowManagerWrapper.getInstance().overridePendingAppTransitionMultiThumbFuture(
+                        future, animStartedListener, getHandler(), true /* scaleUp */);
                 MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_DRAG_DROP,
                         event.task.getTopComponent().flattenToShortString());
             } else {
@@ -1032,11 +1034,9 @@
                 if (taskIndex > -1) {
                     taskIndexFromFront = stack.getTaskCount() - taskIndex - 1;
                 }
-                EventBus.getDefault().send(new LaunchTaskSucceededEvent(
-                        taskIndexFromFront));
+                EventBus.getDefault().send(new LaunchTaskSucceededEvent(taskIndexFromFront));
             } else {
-                Log.e(TAG, mContext.getString(R.string.recents_launch_error_message,
-                        task.title));
+                Log.e(TAG, mContext.getString(R.string.recents_launch_error_message, task.title));
 
                 // Dismiss the task if we fail to launch it
                 if (taskView != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index 600da04..d9f79bb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -431,7 +431,7 @@
      * in the stack.
      */
     public void update(TaskStack stack, ArraySet<Task.TaskKey> ignoreTasksSet,
-            RecentsActivityLaunchState launchState) {
+            RecentsActivityLaunchState launchState, float lastScrollPPercent) {
         SystemServicesProxy ssp = Recents.getSystemServices();
 
         // Clear the progress map
@@ -506,6 +506,8 @@
 
             if (launchState.launchedWithAltTab) {
                 mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP);
+            } else if (0 <= lastScrollPPercent && lastScrollPPercent <= 1) {
+                mInitialScrollP = Utilities.mapRange(lastScrollPPercent, mMinScrollP, mMaxScrollP);
             } else if (Recents.getConfiguration().isLowRamDevice) {
                 mInitialScrollP = mTaskStackLowRamLayoutAlgorithm.getInitialScrollP(mNumStackTasks,
                         scrollToFront);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 1197501..36c9095 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -209,6 +209,9 @@
     private int mLastHeight;
     private boolean mStackActionButtonVisible;
 
+    // Percentage of last ScrollP from the min to max scrollP that lives after configuration changes
+    private float mLastScrollPPercent;
+
     // We keep track of the task view focused by user interaction and draw a frame around it in the
     // grid layout.
     private TaskViewFocusFrame mTaskViewFocusFrame;
@@ -327,6 +330,7 @@
             mStackScroller.reset();
             mStableLayoutAlgorithm.reset();
             mLayoutAlgorithm.reset();
+            mLastScrollPPercent = -1;
         }
 
         // Since we always animate to the same place in (the initial state), always reset the stack
@@ -822,7 +826,7 @@
    public void updateLayoutAlgorithm(boolean boundScrollToNewMinMax,
            RecentsActivityLaunchState launchState) {
         // Compute the min and max scroll values
-        mLayoutAlgorithm.update(mStack, mIgnoreTasks, launchState);
+        mLayoutAlgorithm.update(mStack, mIgnoreTasks, launchState, mLastScrollPPercent);
 
         if (boundScrollToNewMinMax) {
             mStackScroller.boundScroll();
@@ -1150,6 +1154,8 @@
         if (mTaskViewsClipDirty) {
             clipTaskViews();
         }
+        mLastScrollPPercent = Utilities.clamp(Utilities.unmapRange(mStackScroller.getStackScroll(),
+            mLayoutAlgorithm.mMinScrollP, mLayoutAlgorithm.mMaxScrollP), 0, 1);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
index 1cda301..da79884 100644
--- a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
@@ -20,6 +20,8 @@
 import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
 import static android.os.UserHandle.USER_CURRENT;
 
+import static com.android.systemui.statusbar.phone.NavigationBarGestureHelper.DRAG_MODE_NONE;
+
 import android.app.ActivityManager;
 import android.content.res.Configuration;
 import android.os.RemoteException;
@@ -36,6 +38,7 @@
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.stackdivider.DividerView;
+import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
 
 import java.util.List;
 
@@ -89,20 +92,11 @@
         try {
             int dockSide = mWindowManagerService.getDockedStackSide();
             if (dockSide == WindowManager.DOCKED_INVALID) {
-                // If there is no window docked, we dock the top-most window.
+                // Split the screen
                 Recents recents = getComponent(Recents.class);
-                int dockMode = (shortcutCode == SC_DOCK_LEFT)
+                recents.splitPrimaryTask(DRAG_MODE_NONE, (shortcutCode == SC_DOCK_LEFT)
                         ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
-                        : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
-                List<ActivityManager.RecentTaskInfo> taskList =
-                        ActivityManagerWrapper.getInstance().getRecentTasks(1, USER_CURRENT);
-                recents.showRecentApps(
-                        false /* triggeredFromAltTab */,
-                        false /* fromHome */);
-                if (!taskList.isEmpty()) {
-                    SystemServicesProxy.getInstance(mContext).startTaskInDockedMode(
-                            taskList.get(0).id, dockMode);
-                }
+                        : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT, null, -1);
             } else {
                 // If there is already a docked window, we respond by resizing the docking pane.
                 DividerView dividerView = getComponent(Divider.class).getView();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
index eb211a1..4d58cb8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
@@ -58,6 +58,6 @@
 
     @Override
     public boolean isDimmable() {
-        return false;
+        return getCustomBackgroundColor() == 0;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
index c950036..b81a3b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -80,7 +80,8 @@
 
     @Override
     protected boolean isLightsOut(int mode) {
-        return super.isLightsOut(mode) || (mAutoDim && !mWallpaperVisible);
+        return super.isLightsOut(mode) || (mAutoDim && !mWallpaperVisible
+                && mode != MODE_WARNING);
     }
 
     public LightBarTransitionsController getLightTransitionsController() {
@@ -108,7 +109,9 @@
         // ok, everyone, stop it right there
         navButtons.animate().cancel();
 
-        final float navButtonsAlpha = lightsOut ? 0.6f : 1f;
+        // Bump percentage by 10% if dark.
+        float darkBump = mLightTransitionsController.getCurrentDarkIntensity() / 10;
+        final float navButtonsAlpha = lightsOut ? 0.6f + darkBump : 1f;
 
         if (!animate) {
             navButtons.setAlpha(navButtonsAlpha);
@@ -130,6 +133,9 @@
         for (int i = buttonDispatchers.size() - 1; i >= 0; i--) {
             buttonDispatchers.valueAt(i).setDarkIntensity(darkIntensity);
         }
+        if (mAutoDim) {
+            applyLightsOut(false, true);
+        }
     }
 
     private final View.OnTouchListener mLightsOutListener = new View.OnTouchListener() {
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 98efd52..32af29d 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -173,6 +173,7 @@
 
   // Selection invocation methods. Used as sub-type for TEXT_SELECTION_SESSION events.
   enum TextSelectionInvocationMethod {
+    TEXT_SELECTION_INVOCATION_UNKNOWN = 0;
     TEXT_SELECTION_INVOCATION_MANUAL = 1;
     TEXT_SELECTION_INVOCATION_LINK = 2;
   }
@@ -2805,316 +2806,524 @@
     // OS: O
     TEXT_LONGPRESS = 629;
 
-    // OBSOLETE
+    // ACTION: An app requested an unknown permission
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REQUEST_UNKNOWN = 630;
 
-    // OBSOLETE
+    // ACTION: An app was granted an unknown permission
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_GRANT_UNKNOWN = 631;
 
-    // OBSOLETE
+    // ACTION: An app requested an unknown permission and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_DENIED_UNKNOWN = 632;
 
-    // OBSOLETE
+    // ACTION: An unknown permission was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REVOKE_UNKNOWN = 633;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission READ_CALENDAR
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REQUEST_READ_CALENDAR = 634;
 
-    // OBSOLETE
+    // ACTION: An app was granted the permission READ_CALENDAR
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_GRANT_READ_CALENDAR = 635;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission READ_CALENDAR and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_DENIED_READ_CALENDAR = 636;
 
-    // OBSOLETE
+    // ACTION: The permission READ_CALENDAR was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REVOKE_READ_CALENDAR = 637;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission WRITE_CALENDAR
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REQUEST_WRITE_CALENDAR = 638;
 
-    // OBSOLETE
+    // ACTION: An app was granted the permission WRITE_CALENDAR
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_GRANT_WRITE_CALENDAR = 639;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission WRITE_CALENDAR and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_DENIED_WRITE_CALENDAR = 640;
 
-    // OBSOLETE
+    // ACTION: The permission WRITE_CALENDAR was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REVOKE_WRITE_CALENDAR = 641;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission CAMERA
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REQUEST_CAMERA = 642;
 
-    // OBSOLETE
+    // ACTION: An app was granted the permission CAMERA
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_GRANT_CAMERA = 643;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission CAMERA and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_DENIED_CAMERA = 644;
 
-    // OBSOLETE
+    // ACTION: The permission CAMERA was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REVOKE_CAMERA = 645;
 
-    // AOBSOLETE
+    // ACTION: An app requested the permission READ_CONTACTS
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REQUEST_READ_CONTACTS = 646;
 
-    // OBSOLETE
+    // ACTION: An app was granted the permission READ_CONTACTS
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_GRANT_READ_CONTACTS = 647;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission READ_CONTACTS and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_DENIED_READ_CONTACTS = 648;
 
-    // OBSOLETE
+    // ACTION: The permission READ_CONTACTS was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REVOKE_READ_CONTACTS = 649;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission WRITE_CONTACTS
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REQUEST_WRITE_CONTACTS = 650;
 
-    // OBSOLETE
+    // ACTION: An app was granted the permission WRITE_CONTACTS
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_GRANT_WRITE_CONTACTS = 651;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission WRITE_CONTACTS and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_DENIED_WRITE_CONTACTS = 652;
 
-    // OBSOLETE
+    // ACTION: The permission WRITE_CONTACTS was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REVOKE_WRITE_CONTACTS = 653;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission GET_ACCOUNTS
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REQUEST_GET_ACCOUNTS = 654;
 
-    // OBSOLETE
+    // ACTION: An app was granted the permission GET_ACCOUNTS
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_GRANT_GET_ACCOUNTS = 655;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission GET_ACCOUNTS and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_DENIED_GET_ACCOUNTS = 656;
 
-    // OBSOLETE
+    // ACTION: The permission GET_ACCOUNTS was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REVOKE_GET_ACCOUNTS = 657;
 
-    // AOBSOLETE
+    // ACTION: An app requested the permission ACCESS_FINE_LOCATION
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REQUEST_ACCESS_FINE_LOCATION = 658;
 
-    // OBSOLETE
+    // ACTION: An app was granted the permission ACCESS_FINE_LOCATION
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_GRANT_ACCESS_FINE_LOCATION = 659;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission ACCESS_FINE_LOCATION and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_DENIED_ACCESS_FINE_LOCATION = 660;
 
-    // OBSOLETE
+    // ACTION: The permission ACCESS_FINE_LOCATION was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REVOKE_ACCESS_FINE_LOCATION = 661;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission ACCESS_COARSE_LOCATION
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REQUEST_ACCESS_COARSE_LOCATION = 662;
 
-    // OBSOLETE
+    // ACTION: An app was granted the permission ACCESS_COARSE_LOCATION
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_GRANT_ACCESS_COARSE_LOCATION = 663;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission ACCESS_COARSE_LOCATION and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_DENIED_ACCESS_COARSE_LOCATION = 664;
 
-    // OBSOLETE
+    // ACTION: The permission ACCESS_COARSE_LOCATION was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REVOKE_ACCESS_COARSE_LOCATION = 665;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission RECORD_AUDIO
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REQUEST_RECORD_AUDIO = 666;
 
-    // OBSOLETE
+    // ACTION: An app was granted the permission RECORD_AUDIO
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_GRANT_RECORD_AUDIO = 667;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission RECORD_AUDIO and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_DENIED_RECORD_AUDIO = 668;
 
-    // OBSOLETE
+    // ACTION: The permission RECORD_AUDIO was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REVOKE_RECORD_AUDIO = 669;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission READ_PHONE_STATE
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REQUEST_READ_PHONE_STATE = 670;
 
-    // OBSOLETE
+    // ACTION: An app was granted the permission READ_PHONE_STATE
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_GRANT_READ_PHONE_STATE = 671;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission READ_PHONE_STATE and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_DENIED_READ_PHONE_STATE = 672;
 
-    // OBSOLETE
+    // ACTION: The permission READ_PHONE_STATE was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REVOKE_READ_PHONE_STATE = 673;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission CALL_PHONE
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REQUEST_CALL_PHONE = 674;
 
-    // OBSOLETE
+    // ACTION: An app was granted the permission CALL_PHONE
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_GRANT_CALL_PHONE = 675;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission CALL_PHONE and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_DENIED_CALL_PHONE = 676;
 
-    // OBSOLETE
+    // ACTION: The permission CALL_PHONE was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REVOKE_CALL_PHONE = 677;
 
-    // AOBSOLETE
+    // ACTION: An app requested the permission READ_CALL_LOG
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REQUEST_READ_CALL_LOG = 678;
 
-    // OBSOLETE
+    // ACTION: An app was granted the permission READ_CALL_LOG
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_GRANT_READ_CALL_LOG = 679;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission READ_CALL_LOG and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_DENIED_READ_CALL_LOG = 680;
 
-    // OBSOLETE
+    // ACTION: The permission READ_CALL_LOG was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REVOKE_READ_CALL_LOG = 681;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission WRITE_CALL_LOG
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REQUEST_WRITE_CALL_LOG = 682;
 
-    // OBSOLETE
+    // ACTION: An app was granted the permission WRITE_CALL_LOG
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_GRANT_WRITE_CALL_LOG = 683;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission WRITE_CALL_LOG and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_DENIED_WRITE_CALL_LOG = 684;
 
-    // OBSOLETE
+    // ACTION: The permission WRITE_CALL_LOG was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REVOKE_WRITE_CALL_LOG = 685;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission ADD_VOICEMAIL
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REQUEST_ADD_VOICEMAIL = 686;
 
-    // OBSOLETE
+    // ACTION: An app was granted the permission ADD_VOICEMAIL
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_GRANT_ADD_VOICEMAIL = 687;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission ADD_VOICEMAIL and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_DENIED_ADD_VOICEMAIL = 688;
 
-    // OBSOLETE
+    // ACTION: The permission ADD_VOICEMAIL was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REVOKE_ADD_VOICEMAIL = 689;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission USE_SIP
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REQUEST_USE_SIP = 690;
 
-    // OBSOLETE
+    // ACTION: An app was granted the permission USE_SIP
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_GRANT_USE_SIP = 691;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission USE_SIP and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_DENIED_USE_SIP = 692;
 
-    // OBSOLETE
+    // ACTION: The permission USE_SIP was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REVOKE_USE_SIP = 693;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission PROCESS_OUTGOING_CALLS
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REQUEST_PROCESS_OUTGOING_CALLS = 694;
 
-    // OBSOLETE
+    // ACTION: An app was granted the permission PROCESS_OUTGOING_CALLS
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_GRANT_PROCESS_OUTGOING_CALLS = 695;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission PROCESS_OUTGOING_CALLS and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_DENIED_PROCESS_OUTGOING_CALLS = 696;
 
-    // OBSOLETE
+    // ACTION: The permission PROCESS_OUTGOING_CALLS was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REVOKE_PROCESS_OUTGOING_CALLS = 697;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission READ_CELL_BROADCASTS
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REQUEST_READ_CELL_BROADCASTS = 698;
 
-    // OBSOLETE
+    // ACTION: An app was granted the permission READ_CELL_BROADCASTS
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_GRANT_READ_CELL_BROADCASTS = 699;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission READ_CELL_BROADCASTS and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_DENIED_READ_CELL_BROADCASTS = 700;
 
-    // OBSOLETE
+    // ACTION: The permission READ_CELL_BROADCASTS was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REVOKE_READ_CELL_BROADCASTS = 701;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission BODY_SENSORS
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REQUEST_BODY_SENSORS = 702;
 
-    // OBSOLETE
+    // ACTION: An app was granted the permission BODY_SENSORS
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_GRANT_BODY_SENSORS = 703;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission BODY_SENSORS and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_DENIED_BODY_SENSORS = 704;
 
-    // OBSOLETE
+    // ACTION: The permission BODY_SENSORS was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REVOKE_BODY_SENSORS = 705;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission SEND_SMS
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REQUEST_SEND_SMS = 706;
 
-    // OBSOLETE
+    // ACTION: An app was granted the permission SEND_SMS
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_GRANT_SEND_SMS = 707;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission SEND_SMS and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_DENIED_SEND_SMS = 708;
 
-    // OBSOLETE
+    // ACTION: The permission SEND_SMS was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REVOKE_SEND_SMS = 709;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission RECEIVE_SMS
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REQUEST_RECEIVE_SMS = 710;
 
-    // OBSOLETE
+    // ACTION: An app was granted the permission RECEIVE_SMS
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_GRANT_RECEIVE_SMS = 711;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission RECEIVE_SMS and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_DENIED_RECEIVE_SMS = 712;
 
-    // OBSOLETE
+    // ACTION: The permission RECEIVE_SMS was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REVOKE_RECEIVE_SMS = 713;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission READ_SMS
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REQUEST_READ_SMS = 714;
 
-    // OBSOLETE
+    // ACTION: An app was granted the permission READ_SMS
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_GRANT_READ_SMS = 715;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission READ_SMS and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_DENIED_READ_SMS = 716;
 
-    // OBSOLETE
+    // ACTION: The permission READ_SMS was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REVOKE_READ_SMS = 717;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission RECEIVE_WAP_PUSH
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REQUEST_RECEIVE_WAP_PUSH = 718;
 
-    // OBSOLETE
+    // ACTION: An app was granted the permission RECEIVE_WAP_PUSH
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_GRANT_RECEIVE_WAP_PUSH = 719;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission RECEIVE_WAP_PUSH and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_DENIED_RECEIVE_WAP_PUSH = 720;
 
-    // OBSOLETE
+    // ACTION: The permission RECEIVE_WAP_PUSH was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REVOKE_RECEIVE_WAP_PUSH = 721;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission RECEIVE_MMS
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REQUEST_RECEIVE_MMS = 722;
 
-    // OBSOLETE
+    // ACTION: An app was granted the permission RECEIVE_MMS
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_GRANT_RECEIVE_MMS = 723;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission RECEIVE_MMS and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_DENIED_RECEIVE_MMS = 724;
 
-    // OBSOLETE
+    // ACTION: The permission RECEIVE_MMS was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REVOKE_RECEIVE_MMS = 725;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission READ_EXTERNAL_STORAGE
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REQUEST_READ_EXTERNAL_STORAGE = 726;
 
-    // OBSOLETE
+    // ACTION: An app was granted the permission READ_EXTERNAL_STORAGE
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_GRANT_READ_EXTERNAL_STORAGE = 727;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission READ_EXTERNAL_STORAGE and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_DENIED_READ_EXTERNAL_STORAGE = 728;
 
-    // OBSOLETE
+    // ACTION: The permission READ_EXTERNAL_STORAGE was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REVOKE_READ_EXTERNAL_STORAGE = 729;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission WRITE_EXTERNAL_STORAGE
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE = 730;
 
-    // OBSOLETE
+    // ACTION: An app was granted the permission WRITE_EXTERNAL_STORAGE
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_GRANT_WRITE_EXTERNAL_STORAGE = 731;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission WRITE_EXTERNAL_STORAGE and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_DENIED_WRITE_EXTERNAL_STORAGE = 732;
 
-    // OBSOLETE
+    // ACTION: The permission WRITE_EXTERNAL_STORAGE was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REVOKE_WRITE_EXTERNAL_STORAGE = 733;
 
     // ACTION: Logged when a provisioning session has started
@@ -3123,16 +3332,24 @@
     // ACTION: Logged when a provisioning session has completed
     PROVISIONING_SESSION_COMPLETED = 735;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission READ_PHONE_NUMBERS
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REQUEST_READ_PHONE_NUMBERS = 736;
 
-    // OBSOLETE
+    // ACTION: An app was granted the permission READ_PHONE_NUMBERS
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_GRANT_READ_PHONE_NUMBERS = 737;
 
-    // OBSOLETE
+    // ACTION: An app requested the permission READ_PHONE_NUMBERS and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_DENIED_READ_PHONE_NUMBERS = 738;
 
-    // OBSOLETE
+    // ACTION: The permission READ_PHONE_NUMBERS was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_PERMISSION_REVOKE_READ_PHONE_NUMBERS = 739;
 
     // ACTION: QS Brightness Slider (with auto brightness disabled, and VR enabled)
@@ -3624,52 +3841,84 @@
     // CATEGORY: SETTINGS
     SETTINGS_LOCK_SCREEN_PREFERENCES = 882;
 
-    // OBSOLETE
+    // ACTION: An app requested the app-op permission ACCESS_NOTIFICATIONS
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_APPOP_REQUEST_ACCESS_NOTIFICATIONS = 883;
 
-    // OBSOLETE
+    // ACTION: An app was granted the app-op permission ACCESS_NOTIFICATIONS
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_APPOP_GRANT_ACCESS_NOTIFICATIONS = 884;
 
-    // OBSOLETE
+    // ACTION: An app requested the app-op permission ACCESS_NOTIFICATIONS and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_APPOP_DENIED_ACCESS_NOTIFICATIONS = 885;
 
-    // OBSOLETE
+    // ACTION: The app-op permission ACCESS_NOTIFICATIONS was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_APPOP_REVOKE_ACCESS_NOTIFICATIONS = 886;
 
-    // OBSOLETE
+    // ACTION: An app requested the app-op permission SYSTEM_ALERT_WINDOW
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_APPOP_REQUEST_SYSTEM_ALERT_WINDOW = 887;
 
-    // OBSOLETE
+    // ACTION: An app was granted the app-op permission SYSTEM_ALERT_WINDOW
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_APPOP_GRANT_SYSTEM_ALERT_WINDOW = 888;
 
-    // OBSOLETE
+    // ACTION: An app requested the app-op permission SYSTEM_ALERT_WINDOW and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_APPOP_DENIED_SYSTEM_ALERT_WINDOW = 889;
 
-    // OBSOLETE
+    // ACTION: The app-op permission SYSTEM_ALERT_WINDOW was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_APPOP_REVOKE_SYSTEM_ALERT_WINDOW = 890;
 
-    // OBSOLETE
+    // ACTION: An app requested the app-op permission REQUEST_WRITE_SETTINGS
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_APPOP_REQUEST_WRITE_SETTINGS = 891;
 
-    // OBSOLETE
+    // ACTION: An app was granted the app-op permission REQUEST_WRITE_SETTINGS
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_APPOP_GRANT_WRITE_SETTINGS = 892;
 
-    // OBSOLETE
+    // ACTION: An app requested the app-op permission REQUEST_WRITE_SETTINGS and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_APPOP_DENIED_WRITE_SETTINGS = 893;
 
-    // OBSOLETE
+    // ACTION: The app-op permission REQUEST_WRITE_SETTINGS was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_APPOP_REVOKE_WRITE_SETTINGS = 894;
 
-    // OBSOLETE
+    // ACTION: An app requested the app-op permission REQUEST_INSTALL_PACKAGES
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_APPOP_REQUEST_REQUEST_INSTALL_PACKAGES = 895;
 
-    // OBSOLETE
+    // ACTION: An app was granted the app-op permission REQUEST_INSTALL_PACKAGES
+    // PACKAGE: The package name of the app that was granted the permission
+    // OBSOLETE as of Android P
     ACTION_APPOP_GRANT_REQUEST_INSTALL_PACKAGES = 896;
 
-    // OBSOLETE
+    // ACTION: An app requested the app-op permission REQUEST_INSTALL_PACKAGES and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    // OBSOLETE as of Android P
     ACTION_APPOP_DENIED_REQUEST_INSTALL_PACKAGES = 897;
 
-    // OBSOLETE
+    // ACTION: The app-op permission REQUEST_INSTALL_PACKAGES was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    // OBSOLETE as of Android P
     ACTION_APPOP_REVOKE_REQUEST_INSTALL_PACKAGES = 898;
 
     // ACTION: Phase 1 of instant application resolution occurred
@@ -3761,7 +4010,8 @@
     FIELD_AUTOFILL_NUM_IDS = 917;
 
     // ACTION: An autofill service was reqiested to save data
-    // Type TYPE_SUCCESS: The request succeeded
+    // Type TYPE_SUCCESS: The request succeeded right away
+    // Type TYPE_OPEN: The request succeeded but the service launched an IntentSender
     // Type TYPE_FAILURE: The request failed
     // Package: Package of app that was autofilled
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
@@ -4763,6 +5013,8 @@
     // OS: P
     FIELD_SELECTION_WIDGET_VERSION = 1262;
 
+    // ---- End P Constants, all P constants go above this line ----
+
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
   }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityClientConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityClientConnection.java
index df4c8ed..7e94d7b 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityClientConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityClientConnection.java
@@ -47,7 +47,6 @@
 import android.view.KeyEvent;
 import android.view.MagnificationSpec;
 import android.view.View;
-import android.view.WindowManagerInternal;
 import android.view.accessibility.AccessibilityCache;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityInteractionClient;
@@ -60,6 +59,7 @@
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.DumpUtils;
 import com.android.server.accessibility.AccessibilityManagerService.SecurityPolicy;
+import com.android.server.wm.WindowManagerInternal;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index f6fcaae..11b2343 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -31,11 +31,11 @@
 import android.view.InputFilter;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
-import android.view.WindowManagerPolicy;
 import android.view.accessibility.AccessibilityEvent;
 
 import com.android.internal.util.BitUtils;
 import com.android.server.LocalServices;
+import com.android.server.policy.WindowManagerPolicy;
 
 /**
  * This class is an input filter for implementing accessibility features such
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index d661754..3554448 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -82,7 +82,6 @@
 import android.view.View;
 import android.view.WindowInfo;
 import android.view.WindowManager;
-import android.view.WindowManagerInternal;
 import android.view.accessibility.AccessibilityCache;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityInteractionClient;
@@ -102,6 +101,7 @@
 import com.android.internal.util.IntPair;
 import com.android.server.LocalServices;
 import com.android.server.policy.AccessibilityShortcutController;
+import com.android.server.wm.WindowManagerInternal;
 
 import org.xmlpull.v1.XmlPullParserException;
 
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index eb26752..9cafa1e 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -33,10 +33,10 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Slog;
-import android.view.WindowManagerInternal;
 
 import com.android.server.accessibility.AccessibilityManagerService.SecurityPolicy;
 import com.android.server.accessibility.AccessibilityManagerService.UserState;
+import com.android.server.wm.WindowManagerInternal;
 
 import java.lang.ref.WeakReference;
 import java.util.List;
diff --git a/services/accessibility/java/com/android/server/accessibility/GlobalActionPerformer.java b/services/accessibility/java/com/android/server/accessibility/GlobalActionPerformer.java
index 5867006d..3b8d4bc 100644
--- a/services/accessibility/java/com/android/server/accessibility/GlobalActionPerformer.java
+++ b/services/accessibility/java/com/android/server/accessibility/GlobalActionPerformer.java
@@ -29,10 +29,10 @@
 import android.view.InputDevice;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
-import android.view.WindowManagerInternal;
 
 import com.android.server.LocalServices;
 import com.android.server.statusbar.StatusBarManagerInternal;
+import com.android.server.wm.WindowManagerInternal;
 
 /**
  * Handle the back-end of AccessibilityService#performGlobalAction
diff --git a/services/accessibility/java/com/android/server/accessibility/KeyEventDispatcher.java b/services/accessibility/java/com/android/server/accessibility/KeyEventDispatcher.java
index 3358432..b144e1c 100644
--- a/services/accessibility/java/com/android/server/accessibility/KeyEventDispatcher.java
+++ b/services/accessibility/java/com/android/server/accessibility/KeyEventDispatcher.java
@@ -26,7 +26,8 @@
 import android.util.Slog;
 import android.view.InputEventConsistencyVerifier;
 import android.view.KeyEvent;
-import android.view.WindowManagerPolicy;
+
+import com.android.server.policy.WindowManagerPolicy;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/services/accessibility/java/com/android/server/accessibility/KeyboardInterceptor.java b/services/accessibility/java/com/android/server/accessibility/KeyboardInterceptor.java
index 7724945..bc379c2 100644
--- a/services/accessibility/java/com/android/server/accessibility/KeyboardInterceptor.java
+++ b/services/accessibility/java/com/android/server/accessibility/KeyboardInterceptor.java
@@ -22,7 +22,8 @@
 import android.util.Pools;
 import android.util.Slog;
 import android.view.KeyEvent;
-import android.view.WindowManagerPolicy;
+
+import com.android.server.policy.WindowManagerPolicy;
 
 /**
  * Intercepts key events and forwards them to accessibility manager service.
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
index a10b7a2..a70b88e 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
@@ -34,7 +34,6 @@
 import android.util.Slog;
 import android.view.MagnificationSpec;
 import android.view.View;
-import android.view.WindowManagerInternal;
 import android.view.animation.DecelerateInterpolator;
 
 import com.android.internal.R;
@@ -42,6 +41,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.SomeArgs;
 import com.android.server.LocalServices;
+import com.android.server.wm.WindowManagerInternal;
 
 import java.util.Locale;
 
diff --git a/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java
index b6b7812..46e3226 100644
--- a/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java
+++ b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java
@@ -31,9 +31,9 @@
 import android.util.SparseIntArray;
 import android.view.InputDevice;
 import android.view.MotionEvent;
-import android.view.WindowManagerPolicy;
 
 import com.android.internal.os.SomeArgs;
+import com.android.server.policy.WindowManagerPolicy;
 
 import java.util.ArrayList;
 import java.util.Arrays;
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index a32686d..3419b80 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -26,11 +26,12 @@
 import android.view.MotionEvent.PointerCoords;
 import android.view.MotionEvent.PointerProperties;
 import android.view.ViewConfiguration;
-import android.view.WindowManagerPolicy;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
 
+import com.android.server.policy.WindowManagerPolicy;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
diff --git a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
index a6b81ff..f0571126 100644
--- a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
@@ -26,9 +26,10 @@
 import android.os.IBinder.DeathRecipient;
 import android.os.RemoteException;
 import android.util.Slog;
-import android.view.WindowManagerInternal;
 import android.view.accessibility.AccessibilityEvent;
 
+import com.android.server.wm.WindowManagerInternal;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index af55807..831c488 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -26,6 +26,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentSender;
 import android.content.ServiceConnection;
 import android.os.Handler;
 import android.os.IBinder;
@@ -100,7 +101,8 @@
                 @NonNull String servicePackageName);
         void onFillRequestFailure(@Nullable CharSequence message,
                 @NonNull String servicePackageName);
-        void onSaveRequestSuccess(@NonNull String servicePackageName);
+        void onSaveRequestSuccess(@NonNull String servicePackageName,
+                @Nullable IntentSender intentSender);
         void onSaveRequestFailure(@Nullable CharSequence message,
                 @NonNull String servicePackageName);
         void onServiceDied(RemoteFillService service);
@@ -308,10 +310,11 @@
         });
     }
 
-    private void dispatchOnSaveRequestSuccess(PendingRequest pendingRequest) {
+    private void dispatchOnSaveRequestSuccess(PendingRequest pendingRequest,
+            IntentSender intentSender) {
         mHandler.getHandler().post(() -> {
             if (handleResponseCallbackCommon(pendingRequest)) {
-                mCallbacks.onSaveRequestSuccess(mComponentName.getPackageName());
+                mCallbacks.onSaveRequestSuccess(mComponentName.getPackageName(), intentSender);
             }
         });
     }
@@ -624,12 +627,13 @@
 
             mCallback = new ISaveCallback.Stub() {
                 @Override
-                public void onSuccess() {
+                public void onSuccess(IntentSender intentSender) {
                     if (!finish()) return;
 
                     final RemoteFillService remoteService = getService();
                     if (remoteService != null) {
-                        remoteService.dispatchOnSaveRequestSuccess(PendingSaveRequest.this);
+                        remoteService.dispatchOnSaveRequestSuccess(PendingSaveRequest.this,
+                                intentSender);
                     }
                 }
 
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 9741486..99b92b9 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -561,7 +561,8 @@
 
     // FillServiceCallbacks
     @Override
-    public void onSaveRequestSuccess(@NonNull String servicePackageName) {
+    public void onSaveRequestSuccess(@NonNull String servicePackageName,
+            @Nullable IntentSender intentSender) {
         synchronized (mLock) {
             mIsSaving = false;
 
@@ -572,8 +573,12 @@
             }
         }
         LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST, servicePackageName)
-                .setType(MetricsEvent.TYPE_SUCCESS);
+                .setType(intentSender == null ? MetricsEvent.TYPE_SUCCESS : MetricsEvent.TYPE_OPEN);
         mMetricsLogger.write(log);
+        if (intentSender != null) {
+            if (sDebug) Slog.d(TAG, "Starting intent sender on save()");
+            startIntentSender(intentSender);
+        }
 
         // Nothing left to do...
         removeSelf();
diff --git a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
index dd29a04..2788218 100644
--- a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
@@ -2158,8 +2158,17 @@
             mFullBackupQueue.remove(0);
             CountDownLatch latch = new CountDownLatch(1);
             String[] pkg = new String[]{entry.packageName};
-            mRunningFullBackupTask = new PerformFullTransportBackupTask(this, null, pkg, true,
-                    scheduledJob, latch, null, null, false /* userInitiated */);
+            mRunningFullBackupTask = PerformFullTransportBackupTask.newWithCurrentTransport(
+                    this,
+                    /* observer */ null,
+                    pkg,
+                    /* updateSchedule */ true,
+                    scheduledJob,
+                    latch,
+                    /* backupObserver */ null,
+                    /* monitor */ null,
+                    /* userInitiated */ false,
+                    "BMS.beginFullBackup()");
             // Acquiring wakelock for PerformFullTransportBackupTask before its start.
             mWakelock.acquire();
             (new Thread(mRunningFullBackupTask)).start();
@@ -2513,8 +2522,17 @@
             final long oldId = Binder.clearCallingIdentity();
             try {
                 CountDownLatch latch = new CountDownLatch(1);
-                PerformFullTransportBackupTask task = new PerformFullTransportBackupTask(this, null,
-                        pkgNames, false, null, latch, null, null, false /* userInitiated */);
+                Runnable task = PerformFullTransportBackupTask.newWithCurrentTransport(
+                        this,
+                        /* observer */ null,
+                        pkgNames,
+                        /* updateSchedule */ false,
+                        /* runningJob */ null,
+                        latch,
+                        /* backupObserver */ null,
+                        /* monitor */ null,
+                        /* userInitiated */ false,
+                        "BMS.fullTransportBackup()");
                 // Acquiring wakelock for PerformFullTransportBackupTask before its start.
                 mWakelock.acquire();
                 (new Thread(task, "full-transport-master")).start();
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
index 90134e1..d5b3d98 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
@@ -24,6 +24,7 @@
 import static com.android.server.backup.RefactoredBackupManagerService.OP_TYPE_BACKUP_WAIT;
 import static com.android.server.backup.RefactoredBackupManagerService.TIMEOUT_FULL_BACKUP_INTERVAL;
 
+import android.annotation.Nullable;
 import android.app.IBackupAgent;
 import android.app.backup.BackupManager;
 import android.app.backup.BackupManagerMonitor;
@@ -46,7 +47,11 @@
 import com.android.server.backup.BackupRestoreTask;
 import com.android.server.backup.FullBackupJob;
 import com.android.server.backup.RefactoredBackupManagerService;
+import com.android.server.backup.TransportManager;
+import com.android.server.backup.internal.OnTaskFinishedListener;
 import com.android.server.backup.internal.Operation;
+import com.android.server.backup.transport.TransportClient;
+import com.android.server.backup.transport.TransportNotAvailableException;
 import com.android.server.backup.utils.AppBackupUtils;
 import com.android.server.backup.utils.BackupManagerMonitorUtils;
 import com.android.server.backup.utils.BackupObserverUtils;
@@ -89,6 +94,36 @@
  *       mBackupRunner.getBackupResultBlocking().
  */
 public class PerformFullTransportBackupTask extends FullBackupTask implements BackupRestoreTask {
+    public static PerformFullTransportBackupTask newWithCurrentTransport(
+            RefactoredBackupManagerService backupManagerService,
+            IFullBackupRestoreObserver observer,
+            String[] whichPackages,
+            boolean updateSchedule,
+            FullBackupJob runningJob,
+            CountDownLatch latch,
+            IBackupObserver backupObserver,
+            IBackupManagerMonitor monitor,
+            boolean userInitiated,
+            String caller) {
+        TransportManager transportManager = backupManagerService.getTransportManager();
+        TransportClient transportClient = transportManager.getCurrentTransportClient(caller);
+        OnTaskFinishedListener listener =
+                listenerCaller ->
+                        transportManager.disposeOfTransportClient(transportClient, listenerCaller);
+        return new PerformFullTransportBackupTask(
+                backupManagerService,
+                transportClient,
+                observer,
+                whichPackages,
+                updateSchedule,
+                runningJob,
+                latch,
+                backupObserver,
+                monitor,
+                listener,
+                userInitiated);
+    }
+
     private static final String TAG = "PFTBT";
 
     private RefactoredBackupManagerService backupManagerService;
@@ -102,9 +137,10 @@
     IBackupObserver mBackupObserver;
     IBackupManagerMonitor mMonitor;
     boolean mUserInitiated;
-    private volatile IBackupTransport mTransport;
     SinglePackageBackupRunner mBackupRunner;
     private final int mBackupRunnerOpToken;
+    private final OnTaskFinishedListener mListener;
+    private final TransportClient mTransportClient;
 
     // This is true when a backup operation for some package is in progress.
     private volatile boolean mIsDoingBackup;
@@ -112,18 +148,22 @@
     private final int mCurrentOpToken;
 
     public PerformFullTransportBackupTask(RefactoredBackupManagerService backupManagerService,
+            TransportClient transportClient,
             IFullBackupRestoreObserver observer,
             String[] whichPackages, boolean updateSchedule,
             FullBackupJob runningJob, CountDownLatch latch, IBackupObserver backupObserver,
-            IBackupManagerMonitor monitor, boolean userInitiated) {
+            IBackupManagerMonitor monitor, @Nullable OnTaskFinishedListener listener,
+            boolean userInitiated) {
         super(observer);
         this.backupManagerService = backupManagerService;
+        mTransportClient = transportClient;
         mUpdateSchedule = updateSchedule;
         mLatch = latch;
         mJob = runningJob;
         mPackages = new ArrayList<>(whichPackages.length);
         mBackupObserver = backupObserver;
         mMonitor = monitor;
+        mListener = (listener != null) ? listener : OnTaskFinishedListener.NOP;
         mUserInitiated = userInitiated;
         mCurrentOpToken = backupManagerService.generateRandomIntegerToken();
         mBackupRunnerOpToken = backupManagerService.generateRandomIntegerToken();
@@ -241,8 +281,11 @@
             if (mIsDoingBackup) {
                 backupManagerService.handleCancel(mBackupRunnerOpToken, cancelAll);
                 try {
-                    mTransport.cancelFullBackup();
-                } catch (RemoteException e) {
+                    // If we're running a backup we should be connected to a transport
+                    IBackupTransport transport =
+                            mTransportClient.getConnectedTransport("PFTBT.handleCancel()");
+                    transport.cancelFullBackup();
+                } catch (RemoteException | TransportNotAvailableException e) {
                     Slog.w(TAG, "Error calling cancelFullBackup() on transport: " + e);
                     // Can't do much.
                 }
@@ -291,8 +334,8 @@
                 return;
             }
 
-            mTransport = backupManagerService.getTransportManager().getCurrentTransportBinder();
-            if (mTransport == null) {
+            IBackupTransport transport = mTransportClient.connect("PFTBT.run()");
+            if (transport == null) {
                 Slog.w(TAG, "Transport not present; full data backup not performed");
                 backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED;
                 mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
@@ -325,17 +368,17 @@
                     if (mCancelAll) {
                         break;
                     }
-                    backupPackageStatus = mTransport.performFullBackup(currentPackage,
+                    backupPackageStatus = transport.performFullBackup(currentPackage,
                             transportPipes[0], flags);
 
                     if (backupPackageStatus == BackupTransport.TRANSPORT_OK) {
-                        quota = mTransport.getBackupQuota(currentPackage.packageName,
+                        quota = transport.getBackupQuota(currentPackage.packageName,
                                 true /* isFullBackup */);
                         // Now set up the backup engine / data source end of things
                         enginePipes = ParcelFileDescriptor.createPipe();
                         mBackupRunner =
                                 new SinglePackageBackupRunner(enginePipes[1], currentPackage,
-                                        mTransport, quota, mBackupRunnerOpToken);
+                                        mTransportClient, quota, mBackupRunnerOpToken);
                         // The runner dup'd the pipe half, so we close it here
                         enginePipes[1].close();
                         enginePipes[1] = null;
@@ -389,7 +432,7 @@
                                 out.write(buffer, 0, nRead);
                                 synchronized (mCancelLock) {
                                     if (!mCancelAll) {
-                                        backupPackageStatus = mTransport.sendBackupData(nRead);
+                                        backupPackageStatus = transport.sendBackupData(nRead);
                                     }
                                 }
                                 totalRead += nRead;
@@ -425,12 +468,12 @@
                                 // result based on what finishBackup() returns.  If we're in a
                                 // failure case already, preserve that result and ignore whatever
                                 // finishBackup() reports.
-                                final int finishResult = mTransport.finishBackup();
+                                final int finishResult = transport.finishBackup();
                                 if (backupPackageStatus == BackupTransport.TRANSPORT_OK) {
                                     backupPackageStatus = finishResult;
                                 }
                             } else {
-                                mTransport.cancelFullBackup();
+                                transport.cancelFullBackup();
                             }
                         }
                     }
@@ -469,7 +512,7 @@
 
                     // Also ask the transport how long it wants us to wait before
                     // moving on to the next package, if any.
-                    backoff = mTransport.requestFullBackupTime();
+                    backoff = transport.requestFullBackupTime();
                     if (DEBUG_SCHEDULING) {
                         Slog.i(TAG, "Transport suggested backoff=" + backoff);
                     }
@@ -591,6 +634,8 @@
                 backupManagerService.setRunningFullBackupTask(null);
             }
 
+            mListener.onFinished("PFTBT.run()");
+
             mLatch.countDown();
 
             // Now that we're actually done with schedule-driven work, reschedule
@@ -633,12 +678,13 @@
     class SinglePackageBackupPreflight implements BackupRestoreTask, FullBackupPreflight {
         final AtomicLong mResult = new AtomicLong(BackupTransport.AGENT_ERROR);
         final CountDownLatch mLatch = new CountDownLatch(1);
-        final IBackupTransport mTransport;
+        final TransportClient mTransportClient;
         final long mQuota;
         private final int mCurrentOpToken;
 
-        SinglePackageBackupPreflight(IBackupTransport transport, long quota, int currentOpToken) {
-            mTransport = transport;
+        SinglePackageBackupPreflight(
+                TransportClient transportClient, long quota, int currentOpToken) {
+            mTransportClient = transportClient;
             mQuota = quota;
             mCurrentOpToken = currentOpToken;
         }
@@ -672,7 +718,9 @@
                     Slog.v(TAG, "Got preflight response; size=" + totalSize);
                 }
 
-                result = mTransport.checkFullBackupSize(totalSize);
+                IBackupTransport transport =
+                        mTransportClient.connectOrThrow("PFTBT$SPBP.preflightFullBackup()");
+                result = transport.checkFullBackupSize(totalSize);
                 if (result == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
                     if (MORE_DEBUG) {
                         Slog.d(TAG, "Package hit quota limit on preflight " +
@@ -739,12 +787,13 @@
         private volatile boolean mIsCancelled;
 
         SinglePackageBackupRunner(ParcelFileDescriptor output, PackageInfo target,
-                IBackupTransport transport, long quota, int currentOpToken) throws IOException {
+                TransportClient transportClient, long quota, int currentOpToken)
+                throws IOException {
             mOutput = ParcelFileDescriptor.dup(output.getFileDescriptor());
             mTarget = target;
             mCurrentOpToken = currentOpToken;
             mEphemeralToken = backupManagerService.generateRandomIntegerToken();
-            mPreflight = new SinglePackageBackupPreflight(transport, quota, mEphemeralToken);
+            mPreflight = new SinglePackageBackupPreflight(transportClient, quota, mEphemeralToken);
             mPreflightLatch = new CountDownLatch(1);
             mBackupLatch = new CountDownLatch(1);
             mPreflightResult = BackupTransport.AGENT_ERROR;
diff --git a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
index 1fa215a..5be1b39 100644
--- a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
+++ b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
@@ -184,11 +184,11 @@
                         mPendingFullBackups.toArray(new String[mPendingFullBackups.size()]);
                 mFullBackupTask =
                         new PerformFullTransportBackupTask(backupManagerService,
-                                /*fullBackupRestoreObserver*/
-                                null,
+                                transportClient,
+                                /*fullBackupRestoreObserver*/ null,
                                 fullBackups, /*updateSchedule*/ false, /*runningJob*/ null,
                                 latch,
-                                mObserver, mMonitor, mUserInitiated);
+                                mObserver, mMonitor, mListener, mUserInitiated);
 
                 registerTask();
                 backupManagerService.addBackupTrace("STATE => INITIAL");
@@ -585,11 +585,11 @@
 
         if (!mCancelAll && mStatus == BackupTransport.TRANSPORT_OK &&
                 mPendingFullBackups != null && !mPendingFullBackups.isEmpty()) {
-            // TODO(brufino): Move the onFinish() call to the full-backup task
-            mListener.onFinished(callerLogString);
             Slog.d(TAG, "Starting full backups for: " + mPendingFullBackups);
             // Acquiring wakelock for PerformFullTransportBackupTask before its start.
             backupManagerService.getWakelock().acquire();
+            // The full-backup task is now responsible for calling onFinish() on mListener, which
+            // was the listener we passed it.
             (new Thread(mFullBackupTask, "full-transport-requested")).start();
         } else if (mCancelAll) {
             mListener.onFinished(callerLogString);
diff --git a/services/backup/java/com/android/server/backup/transport/TransportClient.java b/services/backup/java/com/android/server/backup/transport/TransportClient.java
index 9c39729..65f9502 100644
--- a/services/backup/java/com/android/server/backup/transport/TransportClient.java
+++ b/services/backup/java/com/android/server/backup/transport/TransportClient.java
@@ -367,6 +367,25 @@
         return transport;
     }
 
+    /**
+     * If the {@link TransportClient} is already connected to the transport, returns the transport,
+     * otherwise throws {@link TransportNotAvailableException}.
+     *
+     * @param caller A {@link String} identifying the caller for logging/debugging purposes. Check
+     *     {@link #connectAsync(TransportConnectionListener, String)} for more details.
+     * @return A {@link IBackupTransport} transport binder instance.
+     * @throws TransportNotAvailableException if not connected.
+     */
+    public IBackupTransport getConnectedTransport(String caller)
+            throws TransportNotAvailableException {
+        IBackupTransport transport = mTransport;
+        if (transport == null) {
+            log(Log.ERROR, caller, "Transport not connected");
+            throw new TransportNotAvailableException();
+        }
+        return transport;
+    }
+
     @Override
     public String toString() {
         return "TransportClient{"
diff --git a/services/backup/java/com/android/server/backup/transport/TransportNotAvailableException.java b/services/backup/java/com/android/server/backup/transport/TransportNotAvailableException.java
index a02f03c..c4e5a1d 100644
--- a/services/backup/java/com/android/server/backup/transport/TransportNotAvailableException.java
+++ b/services/backup/java/com/android/server/backup/transport/TransportNotAvailableException.java
@@ -25,7 +25,7 @@
  *
  * @see TransportClient#connectAsync(TransportConnectionListener, String)
  */
-class TransportNotAvailableException extends Exception {
+public class TransportNotAvailableException extends Exception {
     TransportNotAvailableException() {
         super("Transport not available");
     }
diff --git a/services/backup/java/com/android/server/backup/transport/TransportUtils.java b/services/backup/java/com/android/server/backup/transport/TransportUtils.java
index 514717f..85599b7 100644
--- a/services/backup/java/com/android/server/backup/transport/TransportUtils.java
+++ b/services/backup/java/com/android/server/backup/transport/TransportUtils.java
@@ -25,6 +25,7 @@
 
 /** Utility methods for transport-related operations. */
 public class TransportUtils {
+    private static final String TAG = "TransportUtils";
 
     /**
      * Throws {@link TransportNotAvailableException} if {@param transport} is null. The semantics is
@@ -33,6 +34,7 @@
     public static IBackupTransport checkTransport(@Nullable IBackupTransport transport)
             throws TransportNotAvailableException {
         if (transport == null) {
+            log(Log.ERROR, TAG, "Transport not available");
             throw new TransportNotAvailableException();
         }
         return transport;
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index a903f3d..b7b5bd9 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -40,13 +40,13 @@
 import android.util.MutableBoolean;
 import android.util.Slog;
 import android.view.KeyEvent;
-import android.view.WindowManagerInternal;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.server.LocalServices;
 import com.android.server.statusbar.StatusBarManagerInternal;
+import com.android.server.wm.WindowManagerInternal;
 
 /**
  * The service that listens for gestures detected in sensor firmware and starts the intent
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index f007bcc..fc57a0d 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -128,7 +128,6 @@
 import android.view.ViewGroup;
 import android.view.Window;
 import android.view.WindowManager;
-import android.view.WindowManagerInternal;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputBinding;
 import android.view.inputmethod.InputConnection;
@@ -147,6 +146,8 @@
 import android.widget.TextView;
 import android.widget.Toast;
 
+import com.android.server.wm.WindowManagerInternal;
+
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java
index 1ad1404..2c24798 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java
@@ -69,13 +69,10 @@
     private static final String ACTION_POLL =
             "com.android.server.NetworkTimeUpdateService.action.POLL";
 
-    private static final int NETWORK_CHANGE_EVENT_DELAY_MS = 1000;
-    private static int POLL_REQUEST = 0;
+    private static final int POLL_REQUEST = 0;
 
     private static final long NOT_SET = -1;
     private long mNitzTimeSetTime = NOT_SET;
-    // TODO: Have a way to look up the timezone we are in
-    private long mNitzZoneSetTime = NOT_SET;
     private Network mDefaultNetwork = null;
 
     private Context mContext;
@@ -144,7 +141,6 @@
     private void registerForTelephonyIntents() {
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIME);
-        intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE);
         mContext.registerReceiver(mNitzReceiver, intentFilter);
     }
 
@@ -257,8 +253,6 @@
             if (DBG) Log.d(TAG, "Received " + action);
             if (TelephonyIntents.ACTION_NETWORK_SET_TIME.equals(action)) {
                 mNitzTimeSetTime = SystemClock.elapsedRealtime();
-            } else if (TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE.equals(action)) {
-                mNitzZoneSetTime = SystemClock.elapsedRealtime();
             }
         }
     };
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 3c955eb..66b3adb 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -2192,6 +2192,11 @@
         mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
             "no permission to access the crypt keeper");
 
+        if (StorageManager.isFileEncryptedNativeOnly()) {
+            // Not supported on FBE devices
+            return -1;
+        }
+
         if (type == StorageManager.CRYPT_TYPE_DEFAULT) {
             password = "";
         } else if (TextUtils.isEmpty(password)) {
@@ -2268,6 +2273,11 @@
         mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
             "no permission to access the crypt keeper");
 
+        if (StorageManager.isFileEncryptedNativeOnly()) {
+            // Not supported on FBE devices
+            return;
+        }
+
         try {
             mVold.fdeSetField(field, contents);
             return;
@@ -2287,6 +2297,11 @@
         mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
             "no permission to access the crypt keeper");
 
+        if (StorageManager.isFileEncryptedNativeOnly()) {
+            // Not supported on FBE devices
+            return null;
+        }
+
         try {
             return mVold.fdeGetField(field);
         } catch (Exception e) {
@@ -2568,7 +2583,7 @@
     }
 
     @Override
-    public int mkdirs(String callingPkg, String appPath) {
+    public void mkdirs(String callingPkg, String appPath) {
         final int userId = UserHandle.getUserId(Binder.getCallingUid());
         final UserEnvironment userEnv = new UserEnvironment(userId);
 
@@ -2581,8 +2596,7 @@
         try {
             appFile = new File(appPath).getCanonicalFile();
         } catch (IOException e) {
-            Slog.e(TAG, "Failed to resolve " + appPath + ": " + e);
-            return -1;
+            throw new IllegalStateException("Failed to resolve " + appPath + ": " + e);
         }
 
         // Try translating the app path into a vold path, but require that it
@@ -2597,9 +2611,8 @@
 
             try {
                 mVold.mkdirs(appPath);
-                return 0;
             } catch (Exception e) {
-                Slog.wtf(TAG, e);
+                throw new IllegalStateException("Failed to prepare " + appPath + ": " + e);
             }
         }
 
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index 2289f85..3dbee42 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -42,6 +42,8 @@
 import android.app.ActivityManagerInternal;
 import android.app.ActivityOptions;
 import android.app.WindowConfiguration;
+import android.graphics.Point;
+import android.graphics.Rect;
 import android.util.IntArray;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
@@ -89,6 +91,9 @@
     private ActivityStack mPinnedStack = null;
     private ActivityStack mSplitScreenPrimaryStack = null;
 
+    // Used in updating the display size
+    private Point mTmpDisplaySize = new Point();
+
     ActivityDisplay(ActivityStackSupervisor supervisor, int displayId) {
         mSupervisor = supervisor;
         mDisplayId = displayId;
@@ -97,6 +102,13 @@
             throw new IllegalStateException("Display does not exist displayId=" + displayId);
         }
         mDisplay = display;
+
+        updateBounds();
+    }
+
+    void updateBounds() {
+        mDisplay.getSize(mTmpDisplaySize);
+        setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y);
     }
 
     void addChild(ActivityStack stack, int position) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ae91b82..9ac241e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -713,6 +713,12 @@
 
     final UserController mUserController;
 
+    /**
+     * Packages that are being allowed to perform unrestricted app switches.  Mapping is
+     * User -> Type -> uid.
+     */
+    final SparseArray<ArrayMap<String, Integer>> mAllowAppSwitchUids = new SparseArray<>();
+
     final AppErrors mAppErrors;
 
     final AppWarnings mAppWarnings;
@@ -2494,7 +2500,7 @@
                     DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO);
             ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
             ServiceManager.addService("meminfo", new MemBinder(this), /* allowIsolated= */ false,
-                    DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL);
+                    DUMP_FLAG_PRIORITY_HIGH);
             ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
             ServiceManager.addService("dbinfo", new DbBinder(this));
             if (MONITOR_CPU_USAGE) {
@@ -2552,9 +2558,15 @@
         private final PriorityDump.PriorityDumper mPriorityDumper =
                 new PriorityDump.PriorityDumper() {
             @Override
-            public void dumpNormal(FileDescriptor fd, PrintWriter pw, String[] args,
+            public void dumpHigh(FileDescriptor fd, PrintWriter pw, String[] args,
                     boolean asProto) {
                 if (asProto) return;
+                mActivityManagerService.dumpApplicationMemoryUsage(fd,
+                        pw, "  ", new String[] {"-a"}, false, null);
+            }
+            @Override
+            public void dump(FileDescriptor fd, PrintWriter pw, String[] args, boolean asProto) {
+                if (asProto) return;
                 mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, "  ", args, false, null);
             }
         };
@@ -2866,6 +2878,7 @@
 
     void onUserStoppedLocked(int userId) {
         mRecentTasks.unloadUserDataFromMemoryLocked(userId);
+        mAllowAppSwitchUids.remove(userId);
     }
 
     public void initPowerManagement() {
@@ -8092,7 +8105,7 @@
                     return false;
                 }
                 // An activity is consider to be in multi-window mode if its task isn't fullscreen.
-                return !r.getTask().mFullscreen;
+                return r.inMultiWindowMode();
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -10111,8 +10124,8 @@
                 } else {
                     // Task isn't in window manager yet since it isn't associated with a stack.
                     // Return the persist value from activity manager
-                    if (task.mBounds != null) {
-                        rect.set(task.mBounds);
+                    if (!task.matchParentBounds()) {
+                        rect.set(task.getBounds());
                     } else if (task.mLastNonFullscreenBounds != null) {
                         rect.set(task.mLastNonFullscreenBounds);
                     }
@@ -12605,6 +12618,18 @@
         }
     }
 
+    boolean checkAllowAppSwitchUid(int uid) {
+        ArrayMap<String, Integer> types = mAllowAppSwitchUids.get(UserHandle.getUserId(uid));
+        if (types != null) {
+            for (int i = types.size() - 1; i >= 0; i--) {
+                if (types.valueAt(i).intValue() == uid) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     boolean checkAppSwitchAllowedLocked(int sourcePid, int sourceUid,
             int callingPid, int callingUid, String name) {
         if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
@@ -12617,6 +12642,9 @@
         if (perm == PackageManager.PERMISSION_GRANTED) {
             return true;
         }
+        if (checkAllowAppSwitchUid(sourceUid)) {
+            return true;
+        }
 
         // If the actual IPC caller is different from the logical source, then
         // also see if they are allowed to control app switches.
@@ -12627,6 +12655,9 @@
             if (perm == PackageManager.PERMISSION_GRANTED) {
                 return true;
             }
+            if (checkAllowAppSwitchUid(callingUid)) {
+                return true;
+            }
         }
 
         Slog.w(TAG, name + " request from " + sourceUid + " stopped");
@@ -14903,6 +14934,7 @@
         boolean dumpVisibleStacksOnly = false;
         boolean dumpFocusedStackOnly = false;
         String dumpPackage = null;
+        int dumpAppId = -1;
 
         int opti = 0;
         while (opti < args.length) {
@@ -14997,6 +15029,16 @@
             return;
         }
 
+        if (dumpPackage != null) {
+            try {
+                ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
+                        dumpPackage, 0);
+                dumpAppId = UserHandle.getAppId(info.uid);
+            } catch (NameNotFoundException e) {
+                e.printStackTrace();
+            }
+        }
+
         boolean more = false;
         // Is the caller requesting to dump a particular piece of data?
         if (opti < args.length) {
@@ -15104,7 +15146,7 @@
                             args.length - opti);
                 }
                 synchronized (this) {
-                    dumpProcessesLocked(fd, pw, args, opti, true, dumpPackage);
+                    dumpProcessesLocked(fd, pw, args, opti, true, dumpPackage, dumpAppId);
                 }
             } else if ("oom".equals(cmd) || "o".equals(cmd)) {
                 synchronized (this) {
@@ -15290,7 +15332,7 @@
                 if (dumpAll) {
                     pw.println("-------------------------------------------------------------------------------");
                 }
-                dumpProcessesLocked(fd, pw, args, opti, dumpAll, dumpPackage);
+                dumpProcessesLocked(fd, pw, args, opti, dumpAll, dumpPackage, dumpAppId);
             }
 
         } else {
@@ -15367,7 +15409,7 @@
                 if (dumpAll) {
                     pw.println("-------------------------------------------------------------------------------");
                 }
-                dumpProcessesLocked(fd, pw, args, opti, dumpAll, dumpPackage);
+                dumpProcessesLocked(fd, pw, args, opti, dumpAll, dumpPackage, dumpAppId);
             }
         }
         Binder.restoreCallingIdentity(origId);
@@ -15522,22 +15564,12 @@
         }
     }
 
-    boolean dumpUids(PrintWriter pw, String dumpPackage, SparseArray<UidRecord> uids,
+    boolean dumpUids(PrintWriter pw, String dumpPackage, int dumpAppId, SparseArray<UidRecord> uids,
             String header, boolean needSep) {
         boolean printed = false;
-        int whichAppId = -1;
-        if (dumpPackage != null) {
-            try {
-                ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
-                        dumpPackage, 0);
-                whichAppId = UserHandle.getAppId(info.uid);
-            } catch (NameNotFoundException e) {
-                e.printStackTrace();
-            }
-        }
         for (int i=0; i<uids.size(); i++) {
             UidRecord uidRec = uids.valueAt(i);
-            if (dumpPackage != null && UserHandle.getAppId(uidRec.uid) != whichAppId) {
+            if (dumpPackage != null && UserHandle.getAppId(uidRec.uid) != dumpAppId) {
                 continue;
             }
             if (!printed) {
@@ -15584,7 +15616,7 @@
     }
 
     void dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
-            int opti, boolean dumpAll, String dumpPackage) {
+            int opti, boolean dumpAll, String dumpPackage, int dumpAppId) {
         boolean needSep = false;
         boolean printedAnything = false;
         int numPers = 0;
@@ -15662,13 +15694,14 @@
         }
 
         if (mActiveUids.size() > 0) {
-            if (dumpUids(pw, dumpPackage, mActiveUids, "UID states:", needSep)) {
+            if (dumpUids(pw, dumpPackage, dumpAppId, mActiveUids, "UID states:", needSep)) {
                 printedAnything = needSep = true;
             }
         }
         if (dumpAll) {
             if (mValidateUids.size() > 0) {
-                if (dumpUids(pw, dumpPackage, mValidateUids, "UID validation:", needSep)) {
+                if (dumpUids(pw, dumpPackage, dumpAppId, mValidateUids, "UID validation:",
+                        needSep)) {
                     printedAnything = needSep = true;
                 }
             }
@@ -15972,6 +16005,32 @@
                 pw.println("  mNativeDebuggingApp=" + mNativeDebuggingApp);
             }
         }
+        if (mAllowAppSwitchUids.size() > 0) {
+            boolean printed = false;
+            for (int i = 0; i < mAllowAppSwitchUids.size(); i++) {
+                ArrayMap<String, Integer> types = mAllowAppSwitchUids.valueAt(i);
+                for (int j = 0; j < types.size(); j++) {
+                    if (dumpPackage == null ||
+                            UserHandle.getAppId(types.valueAt(j).intValue()) == dumpAppId) {
+                        if (needSep) {
+                            pw.println();
+                            needSep = false;
+                        }
+                        if (!printed) {
+                            pw.println("  mAllowAppSwitchUids:");
+                            printed = true;
+                        }
+                        pw.print("    User ");
+                        pw.print(mAllowAppSwitchUids.keyAt(i));
+                        pw.print(": Type ");
+                        pw.print(types.keyAt(j));
+                        pw.print(" = ");
+                        UserHandle.formatUid(pw, types.valueAt(j).intValue());
+                        pw.println();
+                    }
+                }
+            }
+        }
         if (dumpPackage == null) {
             if (mAlwaysFinishActivities) {
                 pw.println("  mAlwaysFinishActivities=" + mAlwaysFinishActivities);
@@ -17950,7 +18009,7 @@
             PrintWriter catPw = new FastPrintWriter(catSw, false, 256);
             String[] emptyArgs = new String[] { };
             catPw.println();
-            dumpProcessesLocked(null, catPw, emptyArgs, 0, false, null);
+            dumpProcessesLocked(null, catPw, emptyArgs, 0, false, null, -1);
             catPw.println();
             mServices.newServiceDumperLocked(null, catPw, emptyArgs, 0,
                     false, null).dumpLocked();
@@ -24250,6 +24309,32 @@
                 }
             }
         }
+
+        @Override
+        public void setAllowAppSwitches(@NonNull String type, int uid, int userId) {
+            synchronized (ActivityManagerService.this) {
+                if (mUserController.isUserRunning(userId, ActivityManager.FLAG_OR_STOPPED)) {
+                    ArrayMap<String, Integer> types = mAllowAppSwitchUids.get(userId);
+                    if (types == null) {
+                        if (uid < 0) {
+                            return;
+                        }
+                        types = new ArrayMap<>();
+                        mAllowAppSwitchUids.put(userId, types);
+                    }
+                    if (uid < 0) {
+                        types.remove(type);
+                    } else {
+                        types.put(type, uid);
+                    }
+                }
+            }
+        }
+
+        @Override
+        public boolean isRuntimeRestarted() {
+            return mSystemServiceManager.isRuntimeRestarted();
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 5927666..11590d6 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -79,7 +79,6 @@
 import static android.os.Build.VERSION_CODES.O;
 import static android.os.Process.SYSTEM_UID;
 import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
-import static android.view.WindowManagerPolicy.NAV_BAR_LEFT;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STATES;
@@ -117,6 +116,7 @@
 import static com.android.server.am.proto.ActivityRecordProto.PROC_ID;
 import static com.android.server.am.proto.ActivityRecordProto.STATE;
 import static com.android.server.am.proto.ActivityRecordProto.VISIBLE;
+import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_LEFT;
 import static com.android.server.wm.proto.IdentifierProto.HASH_CODE;
 import static com.android.server.wm.proto.IdentifierProto.TITLE;
 import static com.android.server.wm.proto.IdentifierProto.USER_ID;
@@ -165,7 +165,6 @@
 import android.view.WindowManager.LayoutParams;
 
 import com.android.internal.R;
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.ResolverActivity;
 import com.android.internal.content.ReferrerIntent;
 import com.android.internal.util.XmlUtils;
@@ -343,12 +342,6 @@
     // on the window.
     int mRotationAnimationHint = -1;
 
-    // The bounds of this activity. Mainly used for aspect-ratio compatibility.
-    // TODO(b/36505427): Every level on ConfigurationContainer now has bounds information, which
-    // directly affects the configuration. We should probably move this into that class and have it
-    // handle calculating override configuration from the bounds.
-    private final Rect mBounds = new Rect();
-
     private boolean mShowWhenLocked;
     private boolean mTurnScreenOn;
 
@@ -414,8 +407,8 @@
         if (!getOverrideConfiguration().equals(EMPTY)) {
             pw.println(prefix + "OverrideConfiguration=" + getOverrideConfiguration());
         }
-        if (!mBounds.isEmpty()) {
-            pw.println(prefix + "mBounds=" + mBounds);
+        if (!matchParentBounds()) {
+            pw.println(prefix + "bounds=" + getBounds());
         }
         if (resultTo != null || resultWho != null) {
             pw.print(prefix); pw.print("resultTo="); pw.print(resultTo);
@@ -648,7 +641,7 @@
         }
 
         // An activity is considered to be in multi-window mode if its task isn't fullscreen.
-        final boolean inMultiWindowMode = !task.mFullscreen;
+        final boolean inMultiWindowMode = task.inMultiWindowMode();
         if (inMultiWindowMode != mLastReportedMultiWindowMode) {
             mLastReportedMultiWindowMode = inMultiWindowMode;
             scheduleMultiWindowModeChanged(getConfiguration());
@@ -966,14 +959,14 @@
                 (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, info.configChanges,
                 task.voiceSession != null, mLaunchTaskBehind, isAlwaysFocusable(),
                 appInfo.targetSdkVersion, mRotationAnimationHint,
-                ActivityManagerService.getInputDispatchingTimeoutLocked(this) * 1000000L, mBounds);
+                ActivityManagerService.getInputDispatchingTimeoutLocked(this) * 1000000L);
 
         task.addActivityToTop(this);
 
         // When an activity is started directly into a split-screen fullscreen stack, we need to
         // update the initial multi-window modes so that the callbacks are scheduled correctly when
         // the user leaves that mode.
-        mLastReportedMultiWindowMode = !task.mFullscreen;
+        mLastReportedMultiWindowMode = inMultiWindowMode();
         mLastReportedPictureInPictureMode = inPinnedWindowingMode();
     }
 
@@ -2172,33 +2165,25 @@
         mLastReportedConfiguration.setConfiguration(global, override);
     }
 
-    @Override
-    public void onOverrideConfigurationChanged(Configuration newConfig) {
-        final Configuration currentConfig = getOverrideConfiguration();
-        if (currentConfig.equals(newConfig)) {
-            return;
-        }
-        super.onOverrideConfigurationChanged(newConfig);
-        if (mWindowContainerController == null) {
-            return;
-        }
-        mWindowContainerController.onOverrideConfigurationChanged(newConfig, mBounds);
-    }
-
     // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
     private void updateOverrideConfiguration() {
         mTmpConfig.unset();
         computeBounds(mTmpBounds);
-        if (mTmpBounds.equals(mBounds)) {
+
+        if (mTmpBounds.equals(getOverrideBounds())) {
             return;
         }
 
-        mBounds.set(mTmpBounds);
+        setBounds(mTmpBounds);
+
+        final Rect updatedBounds = getOverrideBounds();
+
         // Bounds changed...update configuration to match.
-        if (!mBounds.isEmpty()) {
-            task.computeOverrideConfiguration(mTmpConfig, mBounds, null /* insetBounds */,
+        if (!matchParentBounds()) {
+            task.computeOverrideConfiguration(mTmpConfig, updatedBounds, null /* insetBounds */,
                     false /* overrideWidth */, false /* overrideHeight */);
         }
+
         onOverrideConfigurationChanged(mTmpConfig);
     }
 
@@ -2225,7 +2210,7 @@
         outBounds.setEmpty();
         final float maxAspectRatio = info.maxAspectRatio;
         final ActivityStack stack = getStack();
-        if (task == null || stack == null || !task.mFullscreen || maxAspectRatio == 0
+        if (task == null || stack == null || task.inMultiWindowMode() || maxAspectRatio == 0
                 || isInVrUiMode(getConfiguration())) {
             // We don't set override configuration if that activity task isn't fullscreen. I.e. the
             // activity is in multi-window mode. Or, there isn't a max aspect ratio specified for
@@ -2256,11 +2241,11 @@
         if (containingAppWidth <= maxActivityWidth && containingAppHeight <= maxActivityHeight) {
             // The display matches or is less than the activity aspect ratio, so nothing else to do.
             // Return the existing bounds. If this method is running for the first time,
-            // {@link mBounds} will be empty (representing no override). If the method has run
-            // before, then effect of {@link mBounds} will already have been applied to the
+            // {@link #getOverrideBounds()} will be empty (representing no override). If the method has run
+            // before, then effect of {@link #getOverrideBounds()} will already have been applied to the
             // value returned from {@link getConfiguration}. Refer to
             // {@link TaskRecord#computeOverrideConfiguration}.
-            outBounds.set(mBounds);
+            outBounds.set(getOverrideBounds());
             return;
         }
 
@@ -2272,12 +2257,6 @@
         outBounds.offsetTo(left, 0 /* top */);
     }
 
-    /** Get bounds of the activity. */
-    @VisibleForTesting
-    Rect getBounds() {
-        return new Rect(mBounds);
-    }
-
     /**
      * Make sure the given activity matches the current configuration. Returns false if the activity
      * had to be destroyed.  Returns true if the configuration is the same, or the activity will
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 6985d6e..4816998 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -156,7 +156,6 @@
  */
 class ActivityStack<T extends StackWindowController> extends ConfigurationContainer
         implements StackWindowListener {
-
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStack" : TAG_AM;
     private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
     private static final String TAG_APP = TAG + POSTFIX_APP;
@@ -322,11 +321,6 @@
      */
     boolean mForceHidden = false;
 
-    // Whether or not this stack covers the entire screen; by default stacks are fullscreen
-    boolean mFullscreen = true;
-    // Current bounds of the stack or null if fullscreen.
-    Rect mBounds = null;
-
     private boolean mUpdateBoundsDeferred;
     private boolean mUpdateBoundsDeferredCalled;
     private final Rect mDeferredBounds = new Rect();
@@ -342,8 +336,6 @@
     /** The attached Display's unique identifier, or -1 if detached */
     int mDisplayId;
 
-    /** Temp variables used during override configuration update. */
-    private final SparseArray<Configuration> mTmpConfigs = new SparseArray<>();
     private final SparseArray<Rect> mTmpBounds = new SparseArray<>();
     private final SparseArray<Rect> mTmpInsetBounds = new SparseArray<>();
     private final Rect mTmpRect2 = new Rect();
@@ -574,7 +566,7 @@
                 }
             }
 
-            if (!Objects.equals(mBounds, mTmpRect2)) {
+            if (!Objects.equals(getOverrideBounds(), mTmpRect2)) {
                 resize(mTmpRect2, null /* tempTaskBounds */, null /* tempTaskInsetBounds */);
             }
         } finally {
@@ -641,9 +633,7 @@
      */
     private void postAddToDisplay(ActivityDisplay activityDisplay, Rect bounds, boolean onTop) {
         mDisplayId = activityDisplay.mDisplayId;
-        mBounds = bounds != null ? new Rect(bounds) : null;
-        mFullscreen = mBounds == null;
-
+        setBounds(bounds);
         onParentChanged();
 
         activityDisplay.addChild(this, onTop ? POSITION_TOP : POSITION_BOTTOM);
@@ -651,7 +641,7 @@
             // If we created a docked stack we want to resize it so it resizes all other stacks
             // in the system.
             mStackSupervisor.resizeDockedStackLocked(
-                    mBounds, null, null, null, null, PRESERVE_WINDOWS);
+                    getOverrideBounds(), null, null, null, null, PRESERVE_WINDOWS);
         }
     }
 
@@ -766,8 +756,9 @@
         return false;
     }
 
-    void setBounds(Rect bounds) {
-        mBounds = mFullscreen ? null : new Rect(bounds);
+    @Override
+    public int setBounds(Rect bounds) {
+        return super.setBounds(!inMultiWindowMode() ? null : bounds);
     }
 
     ActivityRecord topRunningActivityLocked() {
@@ -2495,7 +2486,7 @@
             // apps, maybeUpdateTransitToWallpaper() will fail to identify this as a
             // TRANSIT_WALLPAPER_OPEN animation, and run some funny animation.
             final boolean lastActivityTranslucent = lastStack != null
-                    && (!lastStack.mFullscreen
+                    && (lastStack.inMultiWindowMode()
                     || (lastStack.mLastPausedActivity != null
                     && !lastStack.mLastPausedActivity.fullscreen));
 
@@ -2739,8 +2730,7 @@
         position = getAdjustedPositionForTask(task, position, null /* starting */);
         mTaskHistory.remove(task);
         mTaskHistory.add(position, task);
-        mWindowContainerController.positionChildAt(task.getWindowContainerController(), position,
-                task.mBounds, task.getOverrideConfiguration());
+        mWindowContainerController.positionChildAt(task.getWindowContainerController(), position);
         updateTaskMovement(task, true);
     }
 
@@ -4602,8 +4592,6 @@
     // TODO: Can only be called from special methods in ActivityStackSupervisor.
     // Need to consolidate those calls points into this resize method so anyone can call directly.
     void resize(Rect bounds, Rect tempTaskBounds, Rect tempTaskInsetBounds) {
-        bounds = TaskRecord.validateBounds(bounds);
-
         if (!updateBoundsAllowed(bounds, tempTaskBounds, tempTaskInsetBounds)) {
             return;
         }
@@ -4613,7 +4601,6 @@
         final Rect insetBounds = tempTaskInsetBounds != null ? tempTaskInsetBounds : taskBounds;
 
         mTmpBounds.clear();
-        mTmpConfigs.clear();
         mTmpInsetBounds.clear();
 
         for (int i = mTaskHistory.size() - 1; i >= 0; i--) {
@@ -4624,7 +4611,7 @@
                     // For freeform stack we don't adjust the size of the tasks to match that
                     // of the stack, but we do try to make sure the tasks are still contained
                     // with the bounds of the stack.
-                    mTmpRect2.set(task.mBounds);
+                    mTmpRect2.set(task.getOverrideBounds());
                     fitWithinBounds(mTmpRect2, bounds);
                     task.updateOverrideConfiguration(mTmpRect2);
                 } else {
@@ -4632,15 +4619,13 @@
                 }
             }
 
-            mTmpConfigs.put(task.taskId, task.getOverrideConfiguration());
-            mTmpBounds.put(task.taskId, task.mBounds);
+            mTmpBounds.put(task.taskId, task.getOverrideBounds());
             if (tempTaskInsetBounds != null) {
                 mTmpInsetBounds.put(task.taskId, tempTaskInsetBounds);
             }
         }
 
-        mFullscreen = mWindowContainerController.resize(bounds, mTmpConfigs, mTmpBounds,
-                mTmpInsetBounds);
+        mWindowContainerController.resize(bounds, mTmpBounds, mTmpInsetBounds);
         setBounds(bounds);
     }
 
@@ -4655,7 +4640,7 @@
      * @param stackBounds Bounds within which the other bounds should remain.
      */
     private static void fitWithinBounds(Rect bounds, Rect stackBounds) {
-        if (stackBounds == null || stackBounds.contains(bounds)) {
+        if (stackBounds == null || stackBounds.isEmpty() || stackBounds.contains(bounds)) {
             return;
         }
 
@@ -4873,8 +4858,7 @@
                 pw.println("");
             }
             pw.println(prefix + "Task id #" + task.taskId);
-            pw.println(prefix + "mFullscreen=" + task.mFullscreen);
-            pw.println(prefix + "mBounds=" + task.mBounds);
+            pw.println(prefix + "mBounds=" + task.getOverrideBounds());
             pw.println(prefix + "mMinWidth=" + task.mMinWidth);
             pw.println(prefix + "mMinHeight=" + task.mMinHeight);
             pw.println(prefix + "mLastNonFullscreenBounds=" + task.mLastNonFullscreenBounds);
@@ -4981,7 +4965,7 @@
             if (isOnHomeDisplay() && mode != REMOVE_TASK_MODE_MOVING_TO_TOP
                     && mStackSupervisor.isFocusedStack(this)) {
                 String myReason = reason + " leftTaskHistoryEmpty";
-                if (mFullscreen || !adjustFocusToNextFocusableStack(myReason)) {
+                if (!inMultiWindowMode() || !adjustFocusToNextFocusableStack(myReason)) {
                     mStackSupervisor.moveHomeStackToFront(myReason);
                 }
             }
@@ -5011,8 +4995,8 @@
         final boolean isLockscreenShown = mService.mStackSupervisor.getKeyguardController()
                 .isKeyguardShowing(mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY);
         if (!mStackSupervisor.getLaunchingBoundsController().layoutTask(task, info.windowLayout)
-                && mBounds != null && task.isResizeable() && !isLockscreenShown) {
-            task.updateOverrideConfiguration(mBounds);
+                && !matchParentBounds() && task.isResizeable() && !isLockscreenShown) {
+            task.updateOverrideConfiguration(getOverrideBounds());
         }
         task.createWindowContainer(toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0);
         return task;
@@ -5174,10 +5158,13 @@
             mResumedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY);
         }
         proto.write(DISPLAY_ID, mDisplayId);
-        if (mBounds != null) {
-            mBounds.writeToProto(proto, BOUNDS);
+        if (!matchParentBounds()) {
+            final Rect bounds = getOverrideBounds();
+            bounds.writeToProto(proto, BOUNDS);
         }
-        proto.write(FULLSCREEN, mFullscreen);
+
+        // TODO: Remove, no longer needed with windowingMode.
+        proto.write(FULLSCREEN, matchParentBounds());
         proto.end(token);
     }
 }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index ddde4bc..5525cdb 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2118,7 +2118,7 @@
         }
 
         if (task.isResizeable() && canUseActivityOptionsLaunchBounds(options)) {
-            final Rect bounds = TaskRecord.validateBounds(options.getLaunchBounds());
+            final Rect bounds = options.getLaunchBounds();
             task.updateOverrideConfiguration(bounds);
 
             ActivityStack stack = getLaunchStack(null, options, task, ON_TOP);
@@ -2626,7 +2626,8 @@
 
             // TODO: Checking for isAttached might not be needed as if the user passes in null
             // dockedBounds then they want the docked stack to be dismissed.
-            if (stack.mFullscreen || (dockedBounds == null && !stack.isAttached())) {
+            if (stack.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
+                    || (dockedBounds == null && !stack.isAttached())) {
                 // The dock stack either was dismissed or went fullscreen, which is kinda the same.
                 // In this case we make all other static stacks fullscreen and move all
                 // docked stack tasks to the fullscreen stack.
@@ -3058,7 +3059,7 @@
             // Resize the pinned stack to match the current size of the task the activity we are
             // going to be moving is currently contained in. We do this to have the right starting
             // animation bounds for the pinned stack to the desired bounds the caller wants.
-            resizeStackLocked(stack, task.mBounds, null /* tempTaskBounds */,
+            resizeStackLocked(stack, task.getOverrideBounds(), null /* tempTaskBounds */,
                     null /* tempTaskInsetBounds */, !PRESERVE_WINDOWS,
                     true /* allowResizeInDockedMode */, !DEFER_RESUME);
 
@@ -3782,9 +3783,8 @@
                 pw.println("  Stack #" + stack.mStackId
                         + ": type=" + activityTypeToString(stack.getActivityType())
                         + " mode=" + windowingModeToString(stack.getWindowingMode()));
-                pw.println("  mFullscreen=" + stack.mFullscreen);
                 pw.println("  isSleeping=" + stack.shouldSleepActivities());
-                pw.println("  mBounds=" + stack.mBounds);
+                pw.println("  mBounds=" + stack.getOverrideBounds());
 
                 printed |= stack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage,
                         needSep);
@@ -4054,6 +4054,7 @@
     private void handleDisplayChanged(int displayId) {
         synchronized (mService) {
             ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
+            // TODO: The following code block should be moved into {@link ActivityDisplay}.
             if (activityDisplay != null) {
                 // The window policy is responsible for stopping activities on the default display
                 if (displayId != Display.DEFAULT_DISPLAY) {
@@ -4067,7 +4068,8 @@
                         activityDisplay.mOffToken = null;
                     }
                 }
-                // TODO: Update the bounds.
+
+                activityDisplay.updateBounds();
             }
             mWindowManager.onDisplayChanged(displayId);
         }
@@ -4289,7 +4291,7 @@
             return;
         }
 
-        scheduleUpdatePictureInPictureModeIfNeeded(task, stack.mBounds);
+        scheduleUpdatePictureInPictureModeIfNeeded(task, stack.getOverrideBounds());
     }
 
     void scheduleUpdatePictureInPictureModeIfNeeded(TaskRecord task, Rect targetStackBounds) {
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index 76b4679..35f4f25 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -19,9 +19,9 @@
 import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
-import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
-import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
-import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
+import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
+import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
+import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
@@ -41,8 +41,11 @@
 import android.os.Trace;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
+
 import com.android.internal.policy.IKeyguardDismissCallback;
+import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.wm.WindowManagerService;
+
 import java.io.PrintWriter;
 
 /**
@@ -118,7 +121,7 @@
     /**
      * Called when Keyguard is going away.
      *
-     * @param flags See {@link android.view.WindowManagerPolicy#KEYGUARD_GOING_AWAY_FLAG_TO_SHADE}
+     * @param flags See {@link WindowManagerPolicy#KEYGUARD_GOING_AWAY_FLAG_TO_SHADE}
      *              etc.
      */
     void keyguardGoingAway(int flags) {
diff --git a/services/core/java/com/android/server/am/LaunchingActivityPositioner.java b/services/core/java/com/android/server/am/LaunchingActivityPositioner.java
index d5f9cf3..793884d 100644
--- a/services/core/java/com/android/server/am/LaunchingActivityPositioner.java
+++ b/services/core/java/com/android/server/am/LaunchingActivityPositioner.java
@@ -47,10 +47,10 @@
             return RESULT_SKIP;
         }
 
-        final Rect bounds = TaskRecord.validateBounds(options.getLaunchBounds());
+        final Rect bounds = options.getLaunchBounds();
 
         // Bounds weren't valid.
-        if (bounds == null) {
+        if (bounds == null || bounds.isEmpty()) {
             return RESULT_SKIP;
         }
 
diff --git a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java b/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
index c958fca..d89568e 100644
--- a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
+++ b/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
@@ -88,7 +88,7 @@
 
         final ArrayList<TaskRecord> tasks = task.getStack().getAllTasks();
 
-        updateAvailableRect(task, mAvailableRect);
+        mAvailableRect.set(task.getParent().getBounds());
 
         if (layout == null) {
             positionCenter(tasks, mAvailableRect, getFreeformWidth(mAvailableRect),
@@ -123,17 +123,6 @@
         return RESULT_CONTINUE;
     }
 
-    private void updateAvailableRect(TaskRecord task, Rect availableRect) {
-        final Rect stackBounds = task.getStack().mBounds;
-
-        if (stackBounds != null) {
-            availableRect.set(stackBounds);
-        } else {
-            task.getStack().getDisplay().mDisplay.getSize(mDisplaySize);
-            availableRect.set(0, 0, mDisplaySize.x, mDisplaySize.y);
-        }
-    }
-
     @VisibleForTesting
     static int getFreeformStartLeft(Rect bounds) {
         return bounds.left + bounds.width() / MARGIN_SIZE_DENOMINATOR;
@@ -294,9 +283,9 @@
 
     private static boolean boundsConflict(Rect proposal, ArrayList<TaskRecord> tasks) {
         for (int i = tasks.size() - 1; i >= 0; i--) {
-            TaskRecord task = tasks.get(i);
-            if (!task.mActivities.isEmpty() && task.mBounds != null) {
-                Rect bounds = task.mBounds;
+            final TaskRecord task = tasks.get(i);
+            if (!task.mActivities.isEmpty() && !task.matchParentBounds()) {
+                final Rect bounds = task.getOverrideBounds();
                 if (closeLeftTopCorner(proposal, bounds) || closeRightTopCorner(proposal, bounds)
                         || closeLeftBottomCorner(proposal, bounds)
                         || closeRightBottomCorner(proposal, bounds)) {
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index d35c37b..6e6d7e9 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -1426,9 +1426,6 @@
      * Creates a new RecentTaskInfo from a TaskRecord.
      */
     ActivityManager.RecentTaskInfo createRecentTaskInfo(TaskRecord tr) {
-        // Update the task description to reflect any changes in the task stack
-        tr.updateTaskDescription();
-
         // Compose the recent task info
         ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
         rti.id = tr.getTopActivity() == null ? INVALID_TASK_ID : tr.taskId;
@@ -1444,8 +1441,8 @@
         rti.affiliatedTaskId = tr.mAffiliatedTaskId;
         rti.affiliatedTaskColor = tr.mAffiliatedTaskColor;
         rti.numActivities = 0;
-        if (tr.mBounds != null) {
-            rti.bounds = new Rect(tr.mBounds);
+        if (!tr.matchParentBounds()) {
+            rti.bounds = new Rect(tr.getOverrideBounds());
         }
         rti.supportsSplitScreenMultiWindow = tr.supportsSplitScreenWindowingMode();
         rti.resizeMode = tr.mResizeMode;
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index a9c6eee..365990f 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -19,9 +19,6 @@
 import static android.app.ActivityManager.RESIZE_MODE_FORCED;
 import static android.app.ActivityManager.RESIZE_MODE_SYSTEM;
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
@@ -293,11 +290,6 @@
 
     final ActivityManagerService mService;
 
-    // Whether or not this task covers the entire screen; by default tasks are fullscreen.
-    boolean mFullscreen = true;
-
-    // Bounds of the Task. null for fullscreen tasks.
-    Rect mBounds = null;
     private final Rect mTmpStableBounds = new Rect();
     private final Rect mTmpNonDecorBounds = new Rect();
     private final Rect mTmpRect = new Rect();
@@ -480,68 +472,76 @@
     }
 
     boolean resize(Rect bounds, int resizeMode, boolean preserveWindow, boolean deferResume) {
-        if (!isResizeable()) {
-            Slog.w(TAG, "resizeTask: task " + this + " not resizeable.");
-            return true;
-        }
+        mService.mWindowManager.deferSurfaceLayout();
 
-        // If this is a forced resize, let it go through even if the bounds is not changing,
-        // as we might need a relayout due to surface size change (to/from fullscreen).
-        final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0;
-        if (Objects.equals(mBounds, bounds) && !forced) {
-            // Nothing to do here...
-            return true;
-        }
-        bounds = validateBounds(bounds);
-
-        if (mWindowContainerController == null) {
-            // Task doesn't exist in window manager yet (e.g. was restored from recents).
-            // All we can do for now is update the bounds so it can be used when the task is
-            // added to window manager.
-            updateOverrideConfiguration(bounds);
-            if (!inFreeformWindowingMode()) {
-                // re-restore the task so it can have the proper stack association.
-                mService.mStackSupervisor.restoreRecentTaskLocked(this, null, !ON_TOP);
+        try {
+            if (!isResizeable()) {
+                Slog.w(TAG, "resizeTask: task " + this + " not resizeable.");
+                return true;
             }
-            return true;
-        }
 
-        if (!canResizeToBounds(bounds)) {
-            throw new IllegalArgumentException("resizeTask: Can not resize task=" + this
-                    + " to bounds=" + bounds + " resizeMode=" + mResizeMode);
-        }
+            // If this is a forced resize, let it go through even if the bounds is not changing,
+            // as we might need a relayout due to surface size change (to/from fullscreen).
+            final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0;
+            if (equivalentOverrideBounds(bounds) && !forced) {
+                // Nothing to do here...
+                return true;
+            }
 
-        // Do not move the task to another stack here.
-        // This method assumes that the task is already placed in the right stack.
-        // we do not mess with that decision and we only do the resize!
+            if (mWindowContainerController == null) {
+                // Task doesn't exist in window manager yet (e.g. was restored from recents).
+                // All we can do for now is update the bounds so it can be used when the task is
+                // added to window manager.
+                updateOverrideConfiguration(bounds);
+                if (!inFreeformWindowingMode()) {
+                    // re-restore the task so it can have the proper stack association.
+                    mService.mStackSupervisor.restoreRecentTaskLocked(this, null, !ON_TOP);
+                }
+                return true;
+            }
 
-        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeTask_" + taskId);
+            if (!canResizeToBounds(bounds)) {
+                throw new IllegalArgumentException("resizeTask: Can not resize task=" + this
+                        + " to bounds=" + bounds + " resizeMode=" + mResizeMode);
+            }
 
-        final boolean updatedConfig = updateOverrideConfiguration(bounds);
-        // This variable holds information whether the configuration didn't change in a significant
-        // way and the activity was kept the way it was. If it's false, it means the activity had
-        // to be relaunched due to configuration change.
-        boolean kept = true;
-        if (updatedConfig) {
-            final ActivityRecord r = topRunningActivityLocked();
-            if (r != null && !deferResume) {
-                kept = r.ensureActivityConfigurationLocked(0 /* globalChanges */, preserveWindow);
-                mService.mStackSupervisor.ensureActivitiesVisibleLocked(r, 0, !PRESERVE_WINDOWS);
-                if (!kept) {
-                    mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
+            // Do not move the task to another stack here.
+            // This method assumes that the task is already placed in the right stack.
+            // we do not mess with that decision and we only do the resize!
+
+            Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeTask_" + taskId);
+
+            final boolean updatedConfig = updateOverrideConfiguration(bounds);
+            // This variable holds information whether the configuration didn't change in a significant
+
+            // way and the activity was kept the way it was. If it's false, it means the activity
+            // had
+            // to be relaunched due to configuration change.
+            boolean kept = true;
+            if (updatedConfig) {
+                final ActivityRecord r = topRunningActivityLocked();
+                if (r != null && !deferResume) {
+                    kept = r.ensureActivityConfigurationLocked(0 /* globalChanges */,
+                            preserveWindow);
+                    mService.mStackSupervisor.ensureActivitiesVisibleLocked(r, 0,
+                            !PRESERVE_WINDOWS);
+                    if (!kept) {
+                        mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
+                    }
                 }
             }
-        }
-        mWindowContainerController.resize(mBounds, getOverrideConfiguration(), kept, forced);
+            mWindowContainerController.resize(kept, forced);
 
-        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
-        return kept;
+            Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
+            return kept;
+        } finally {
+            mService.mWindowManager.continueSurfaceLayout();
+        }
     }
 
     // TODO: Investigate combining with the resize() method above.
     void resizeWindowContainer() {
-        mWindowContainerController.resize(mBounds, getOverrideConfiguration(), false /* relayout */,
-                false /* forced */);
+        mWindowContainerController.resize(false /* relayout */, false /* forced */);
     }
 
     void getWindowContainerBounds(Rect bounds) {
@@ -686,16 +686,17 @@
             // Make sure the task has the appropriate bounds/size for the stack it is in.
             final boolean toStackSplitScreenPrimary =
                     toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+            final Rect configBounds = getOverrideBounds();
             if ((toStackWindowingMode == WINDOWING_MODE_FULLSCREEN
                     || toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY)
-                    && !Objects.equals(mBounds, toStack.mBounds)) {
-                kept = resize(toStack.mBounds, RESIZE_MODE_SYSTEM, !mightReplaceWindow,
+                    && !Objects.equals(configBounds, toStack.getOverrideBounds())) {
+                kept = resize(toStack.getOverrideBounds(), RESIZE_MODE_SYSTEM, !mightReplaceWindow,
                         deferResume);
             } else if (toStackWindowingMode == WINDOWING_MODE_FREEFORM) {
                 Rect bounds = getLaunchBounds();
                 if (bounds == null) {
                     mService.mStackSupervisor.getLaunchingBoundsController().layoutTask(this, null);
-                    bounds = mBounds;
+                    bounds = configBounds;
                 }
                 kept = resize(bounds, RESIZE_MODE_FORCED, !mightReplaceWindow, deferResume);
             } else if (toStackSplitScreenPrimary || toStackWindowingMode == WINDOWING_MODE_PINNED) {
@@ -704,7 +705,7 @@
                     // mode
                     mService.mStackSupervisor.moveRecentsStackToFront(reason);
                 }
-                kept = resize(toStack.mBounds, RESIZE_MODE_SYSTEM, !mightReplaceWindow,
+                kept = resize(toStack.getOverrideBounds(), RESIZE_MODE_SYSTEM, !mightReplaceWindow,
                         deferResume);
             }
         } finally {
@@ -1501,8 +1502,10 @@
             return true;
         }
         final boolean landscape = bounds.width() > bounds.height();
+        final Rect configBounds = getOverrideBounds();
         if (mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION) {
-            return mBounds == null || landscape == (mBounds.width() > mBounds.height());
+            return configBounds.isEmpty()
+                    || landscape == (configBounds.width() > configBounds.height());
         }
         return (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY || !landscape)
                 && (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY || landscape);
@@ -1623,6 +1626,9 @@
         final int effectiveRootIndex = findEffectiveRootIndex();
         final ActivityRecord r = mActivities.get(effectiveRootIndex);
         setIntent(r);
+
+        // Update the task description when the activities change
+        updateTaskDescription();
     }
 
     void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
@@ -1920,8 +1926,9 @@
             return;
         }
 
+        final Rect configBounds = getOverrideBounds();
         if (adjustWidth) {
-            if (mBounds != null && bounds.right == mBounds.right) {
+            if (!configBounds.isEmpty() && bounds.right == configBounds.right) {
                 bounds.left = bounds.right - minWidth;
             } else {
                 // Either left bounds match, or neither match, or the previous bounds were
@@ -1930,7 +1937,7 @@
             }
         }
         if (adjustHeight) {
-            if (mBounds != null && bounds.bottom == mBounds.bottom) {
+            if (!configBounds.isEmpty() && bounds.bottom == configBounds.bottom) {
                 bounds.top = bounds.bottom - minHeight;
             } else {
                 // Either top bounds match, or neither match, or the previous bounds were
@@ -1977,38 +1984,37 @@
      * @return True if the override configuration was updated.
      */
     boolean updateOverrideConfiguration(Rect bounds, @Nullable Rect insetBounds) {
-        if (Objects.equals(mBounds, bounds)) {
+        if (equivalentOverrideBounds(bounds)) {
             return false;
         }
+        final Rect currentBounds = getOverrideBounds();
+
         mTmpConfig.setTo(getOverrideConfiguration());
-        final boolean oldFullscreen = mFullscreen;
+        final boolean oldMatchParentBounds = matchParentBounds();
         final Configuration newConfig = getOverrideConfiguration();
 
-        mFullscreen = bounds == null;
+        final boolean matchParentBounds = bounds == null || bounds.isEmpty();
         final boolean persistBounds = getWindowConfiguration().persistTaskBounds();
-        if (mFullscreen) {
-            if (mBounds != null && persistBounds) {
-                mLastNonFullscreenBounds = mBounds;
+        if (matchParentBounds) {
+            if (!currentBounds.isEmpty() && persistBounds) {
+                mLastNonFullscreenBounds = currentBounds;
             }
-            mBounds = null;
+            setBounds(null);
             newConfig.unset();
         } else {
             mTmpRect.set(bounds);
             adjustForMinimalTaskDimensions(mTmpRect);
-            if (mBounds == null) {
-                mBounds = new Rect(mTmpRect);
-            } else {
-                mBounds.set(mTmpRect);
-            }
+            setBounds(mTmpRect);
+
             if (mStack == null || persistBounds) {
-                mLastNonFullscreenBounds = mBounds;
+                mLastNonFullscreenBounds = getOverrideBounds();
             }
             computeOverrideConfiguration(newConfig, mTmpRect, insetBounds,
                     mTmpRect.right != bounds.right, mTmpRect.bottom != bounds.bottom);
         }
         onOverrideConfigurationChanged(newConfig);
 
-        if (mFullscreen != oldFullscreen) {
+        if (matchParentBounds != oldMatchParentBounds) {
             mService.mStackSupervisor.scheduleUpdateMultiWindowMode(this);
         }
 
@@ -2053,23 +2059,19 @@
         final int longSize = Math.max(compatScreenHeightDp, compatScreenWidthDp);
         final int shortSize = Math.min(compatScreenHeightDp, compatScreenWidthDp);
         config.screenLayout = Configuration.reduceScreenLayout(sl, longSize, shortSize);
-
     }
 
     Rect updateOverrideConfigurationFromLaunchBounds() {
-        final Rect bounds = validateBounds(getLaunchBounds());
+        final Rect bounds = getLaunchBounds();
         updateOverrideConfiguration(bounds);
-        if (bounds != null) {
-            bounds.set(mBounds);
+        if (bounds != null && !bounds.isEmpty()) {
+            // TODO: Review if we actually want to do this - we are setting the launch bounds
+            // directly here.
+            bounds.set(getOverrideBounds());
         }
         return bounds;
     }
 
-    static Rect validateBounds(Rect bounds) {
-        // TODO: Not needed once we have bounds in WindowConfiguration.
-        return (bounds != null && bounds.isEmpty()) ? null : bounds;
-    }
-
     /** Updates the task's bounds and override configuration to match what is expected for the
      * input stack. */
     void updateOverrideConfigurationForStack(ActivityStack inStack) {
@@ -2082,7 +2084,7 @@
                 throw new IllegalArgumentException("Can not position non-resizeable task="
                         + this + " in stack=" + inStack);
             }
-            if (mBounds != null) {
+            if (!matchParentBounds()) {
                 return;
             }
             if (mLastNonFullscreenBounds != null) {
@@ -2091,7 +2093,7 @@
                 mService.mStackSupervisor.getLaunchingBoundsController().layoutTask(this, null);
             }
         } else {
-            updateOverrideConfiguration(inStack.mBounds);
+            updateOverrideConfiguration(inStack.getOverrideBounds());
         }
     }
 
@@ -2105,9 +2107,9 @@
         if (!isActivityTypeStandardOrUndefined()
                 || windowingMode == WINDOWING_MODE_FULLSCREEN
                 || (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && !isResizeable())) {
-            return isResizeable() ? mStack.mBounds : null;
+            return isResizeable() ? mStack.getOverrideBounds() : null;
         } else if (!getWindowConfiguration().persistTaskBounds()) {
-            return mStack.mBounds;
+            return mStack.getOverrideBounds();
         }
         return mLastNonFullscreenBounds;
     }
@@ -2287,9 +2289,12 @@
         }
         proto.write(ACTIVITY_TYPE, getActivityType());
         proto.write(RESIZE_MODE, mResizeMode);
-        proto.write(FULLSCREEN, mFullscreen);
-        if (mBounds != null) {
-            mBounds.writeToProto(proto, BOUNDS);
+        // TODO: Remove, no longer needed with windowingMode.
+        proto.write(FULLSCREEN, matchParentBounds());
+
+        if (!matchParentBounds()) {
+            final Rect bounds = getOverrideBounds();
+            bounds.writeToProto(proto, BOUNDS);
         }
         proto.write(MIN_WIDTH, mMinWidth);
         proto.write(MIN_HEIGHT, mMinHeight);
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 7530f3e..379aaad 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -68,13 +68,13 @@
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.Surface;
-import android.view.WindowManagerInternal;
 
 import com.android.server.AnimationThread;
 import com.android.server.DisplayThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.UiThread;
+import com.android.server.wm.WindowManagerInternal;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 600bc42..29a007a 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -20,6 +20,7 @@
 import com.android.internal.app.IBatteryStats;
 import com.android.server.LocalServices;
 import com.android.server.am.BatteryStatsService;
+import com.android.server.policy.WindowManagerPolicy;
 
 import android.animation.Animator;
 import android.animation.ObjectAnimator;
@@ -43,7 +44,6 @@
 import android.util.Spline;
 import android.util.TimeUtils;
 import android.view.Display;
-import android.view.WindowManagerPolicy;
 
 import java.io.PrintWriter;
 
diff --git a/services/core/java/com/android/server/display/OWNERS b/services/core/java/com/android/server/display/OWNERS
index 7e7335d..8361421 100644
--- a/services/core/java/com/android/server/display/OWNERS
+++ b/services/core/java/com/android/server/display/OWNERS
@@ -1 +1,3 @@
 michaelwr@google.com
+
+per-file ColorDisplayService.java=christyfranks@google.com
\ No newline at end of file
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index fa9b107..4050790 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -33,6 +33,7 @@
 import com.android.server.DisplayThread;
 import com.android.server.LocalServices;
 import com.android.server.Watchdog;
+import com.android.server.policy.WindowManagerPolicy;
 
 import org.xmlpull.v1.XmlPullParser;
 
@@ -98,7 +99,6 @@
 import android.view.PointerIcon;
 import android.view.Surface;
 import android.view.ViewConfiguration;
-import android.view.WindowManagerPolicy;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodSubtype;
 
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 94a4dc8..60f451a 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -2099,7 +2099,7 @@
 
             long handle = getSyntheticPasswordHandleLocked(userId);
             authResult = mSpManager.unwrapPasswordBasedSyntheticPassword(
-                    getGateKeeperService(), handle, userCredential, userId);
+                    getGateKeeperService(), handle, userCredential, userId, progressCallback);
 
             if (authResult.credentialType != credentialType) {
                 Slog.e(TAG, "Credential type mismatch.");
@@ -2122,9 +2122,6 @@
         }
 
         if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
-            if (progressCallback != null) {
-                progressCallback.onCredentialVerified();
-            }
             notifyActivePasswordMetricsAvailable(userCredential, userId);
             unlockKeystore(authResult.authToken.deriveKeyStorePassword(), userId);
 
@@ -2223,7 +2220,7 @@
         }
         long handle = getSyntheticPasswordHandleLocked(userId);
         AuthenticationResult authResult = mSpManager.unwrapPasswordBasedSyntheticPassword(
-                getGateKeeperService(), handle, savedCredential, userId);
+                getGateKeeperService(), handle, savedCredential, userId, null);
         VerifyCredentialResponse response = authResult.gkResponse;
         AuthenticationToken auth = authResult.authToken;
 
@@ -2277,7 +2274,7 @@
                 } else /* isSyntheticPasswordBasedCredentialLocked(userId) */ {
                     long pwdHandle = getSyntheticPasswordHandleLocked(userId);
                     auth = mSpManager.unwrapPasswordBasedSyntheticPassword(getGateKeeperService(),
-                            pwdHandle, null, userId).authToken;
+                            pwdHandle, null, userId, null).authToken;
                 }
             }
             if (isSyntheticPasswordBasedCredentialLocked(userId)) {
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index 1a1aa56..7a3a746 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -781,7 +781,8 @@
      * unknown. Caller might choose to validate it by examining AuthenticationResult.credentialType
      */
     public AuthenticationResult unwrapPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper,
-            long handle, String credential, int userId) throws RemoteException {
+            long handle, String credential, int userId,
+            ICheckCredentialProgressCallback progressCallback) throws RemoteException {
         if (credential == null) {
             credential = DEFAULT_PASSWORD;
         }
@@ -841,7 +842,11 @@
             applicationId = transformUnderSecdiscardable(pwdToken,
                     loadSecdiscardable(handle, userId));
         }
-
+        // Supplied credential passes first stage weaver/gatekeeper check so it should be correct.
+        // Notify the callback so the keyguard UI can proceed immediately.
+        if (progressCallback != null) {
+            progressCallback.onCredentialVerified();
+        }
         result.authToken = unwrapSyntheticPasswordBlob(handle, SYNTHETIC_PASSWORD_PASSWORD_BASED,
                 applicationId, sid, userId);
 
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 08da568..cf01400 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -152,7 +152,6 @@
 import android.util.SparseArray;
 import android.util.Xml;
 import android.util.proto.ProtoOutputStream;
-import android.view.WindowManagerInternal;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.widget.Toast;
@@ -180,6 +179,7 @@
 import com.android.server.notification.ManagedServices.UserProfiles;
 import com.android.server.policy.PhoneWindowManager;
 import com.android.server.statusbar.StatusBarManagerInternal;
+import com.android.server.wm.WindowManagerInternal;
 
 import libcore.io.IoUtils;
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 8a9b45b..2d5f7c7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -8045,24 +8045,24 @@
         return finalList;
     }
 
-    private void scanDirTracedLI(File dir, final int parseFlags, int scanFlags, long currentTime) {
-        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + dir.getAbsolutePath() + "]");
+    private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags, long currentTime) {
+        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
         try {
-            scanDirLI(dir, parseFlags, scanFlags, currentTime);
+            scanDirLI(scanDir, parseFlags, scanFlags, currentTime);
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
     }
 
-    private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
-        final File[] files = dir.listFiles();
+    private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime) {
+        final File[] files = scanDir.listFiles();
         if (ArrayUtils.isEmpty(files)) {
-            Log.d(TAG, "No files in app dir " + dir);
+            Log.d(TAG, "No files in app dir " + scanDir);
             return;
         }
 
         if (DEBUG_PACKAGE_SCANNING) {
-            Log.d(TAG, "Scanning app dir " + dir + " scanFlags=" + scanFlags
+            Log.d(TAG, "Scanning app dir " + scanDir + " scanFlags=" + scanFlags
                     + " flags=0x" + Integer.toHexString(parseFlags));
         }
         try (ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
@@ -8094,7 +8094,7 @@
                     }
                     try {
                         if (errorCode == PackageManager.INSTALL_SUCCEEDED) {
-                            scanPackageLI(parseResult.pkg, parseResult.scanFile, parseFlags, scanFlags,
+                            scanPackageChildLI(parseResult.pkg, parseFlags, scanFlags,
                                     currentTime, null);
                         }
                     } catch (PackageManagerException e) {
@@ -8126,14 +8126,14 @@
         logCriticalInfo(priority, msg);
     }
 
-    private void collectCertificatesLI(PackageSetting ps, PackageParser.Package pkg, File srcFile,
+    private void collectCertificatesLI(PackageSetting ps, PackageParser.Package pkg,
             final @ParseFlags int parseFlags) throws PackageManagerException {
         // When upgrading from pre-N MR1, verify the package time stamp using the package
         // directory and not the APK file.
         final long lastModifiedTime = mIsPreNMR1Upgrade
-                ? new File(pkg.codePath).lastModified() : getLastModifiedTime(pkg, srcFile);
+                ? new File(pkg.codePath).lastModified() : getLastModifiedTime(pkg);
         if (ps != null
-                && ps.codePath.equals(srcFile)
+                && ps.codePathString.equals(pkg.codePath)
                 && ps.timeStamp == lastModifiedTime
                 && !isCompatSignatureUpdateNeeded(pkg)
                 && !isRecoverSignatureUpdateNeeded(pkg)) {
@@ -8156,7 +8156,7 @@
             Slog.w(TAG, "PackageSetting for " + ps.name
                     + " is missing signatures.  Collecting certs again to recover them.");
         } else {
-            Slog.i(TAG, srcFile.toString() + " changed; collecting certs");
+            Slog.i(TAG, toString() + " changed; collecting certs");
         }
 
         try {
@@ -8211,14 +8211,14 @@
             renameStaticSharedLibraryPackage(pkg);
         }
 
-        return scanPackageLI(pkg, scanFile, parseFlags, scanFlags, currentTime, user);
+        return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user);
     }
 
     /**
      *  Scans a package and returns the newly parsed package.
      *  @throws PackageManagerException on a parse error.
      */
-    private PackageParser.Package scanPackageLI(PackageParser.Package pkg, File scanFile,
+    private PackageParser.Package scanPackageChildLI(PackageParser.Package pkg,
             final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
             @Nullable UserHandle user)
                     throws PackageManagerException {
@@ -8236,20 +8236,20 @@
         }
 
         // Scan the parent
-        PackageParser.Package scannedPkg = scanPackageInternalLI(pkg, scanFile, parseFlags,
+        PackageParser.Package scannedPkg = scanPackageInternalLI(pkg, parseFlags,
                 scanFlags, currentTime, user);
 
         // Scan the children
         final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
         for (int i = 0; i < childCount; i++) {
             PackageParser.Package childPackage = pkg.childPackages.get(i);
-            scanPackageInternalLI(childPackage, scanFile, parseFlags, scanFlags,
+            scanPackageInternalLI(childPackage, parseFlags, scanFlags,
                     currentTime, user);
         }
 
 
         if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
-            return scanPackageLI(pkg, scanFile, parseFlags, scanFlags, currentTime, user);
+            return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user);
         }
 
         return scannedPkg;
@@ -8259,12 +8259,12 @@
      *  Scans a package and returns the newly parsed package.
      *  @throws PackageManagerException on a parse error.
      */
-    private PackageParser.Package scanPackageInternalLI(PackageParser.Package pkg, File scanFile,
+    private PackageParser.Package scanPackageInternalLI(PackageParser.Package pkg,
             @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
             @Nullable UserHandle user)
                     throws PackageManagerException {
         PackageSetting ps = null;
-        PackageSetting updatedPkg;
+        PackageSetting updatedPs;
         // reader
         synchronized (mPackages) {
             // Look to see if we already know about this package.
@@ -8281,8 +8281,8 @@
             // Check to see if this package could be hiding/updating a system
             // package.  Must look for it either under the original or real
             // package name depending on our state.
-            updatedPkg = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName);
-            if (DEBUG_INSTALL && updatedPkg != null) Slog.d(TAG, "updatedPkg = " + updatedPkg);
+            updatedPs = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName);
+            if (DEBUG_INSTALL && updatedPs != null) Slog.d(TAG, "updatedPkg = " + updatedPs);
 
             // If this is a package we don't know about on the system partition, we
             // may need to remove disabled child packages on the system partition
@@ -8316,27 +8316,27 @@
             }
         }
 
-        final boolean isUpdatedPkg = updatedPkg != null;
+        final boolean isUpdatedPkg = updatedPs != null;
         final boolean isUpdatedSystemPkg = isUpdatedPkg && (scanFlags & SCAN_AS_SYSTEM) != 0;
         boolean isUpdatedPkgBetter = false;
         // First check if this is a system package that may involve an update
         if (isUpdatedSystemPkg) {
             // If new package is not located in "/system/priv-app" (e.g. due to an OTA),
             // it needs to drop FLAG_PRIVILEGED.
-            if (locationIsPrivileged(scanFile)) {
-                updatedPkg.pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
+            if (locationIsPrivileged(pkg.codePath)) {
+                updatedPs.pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
             } else {
-                updatedPkg.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
+                updatedPs.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
             }
             // If new package is not located in "/oem" (e.g. due to an OTA),
             // it needs to drop FLAG_OEM.
-            if (locationIsOem(scanFile)) {
-                updatedPkg.pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_OEM;
+            if (locationIsOem(pkg.codePath)) {
+                updatedPs.pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_OEM;
             } else {
-                updatedPkg.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_OEM;
+                updatedPs.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_OEM;
             }
 
-            if (ps != null && !ps.codePath.equals(scanFile)) {
+            if (ps != null && !ps.codePathString.equals(pkg.codePath)) {
                 // The path has changed from what was last scanned...  check the
                 // version of the new path against what we have stored to determine
                 // what to do.
@@ -8344,26 +8344,27 @@
                 if (pkg.mVersionCode <= ps.versionCode) {
                     // The system package has been updated and the code path does not match
                     // Ignore entry. Skip it.
-                    if (DEBUG_INSTALL) Slog.i(TAG, "Package " + ps.name + " at " + scanFile
+                    if (DEBUG_INSTALL) Slog.i(TAG, "Package " + ps.name + " at " + pkg.codePath
                             + " ignored: updated version " + ps.versionCode
                             + " better than this " + pkg.mVersionCode);
-                    if (!updatedPkg.codePath.equals(scanFile)) {
+                    if (!updatedPs.codePathString.equals(pkg.codePath)) {
                         Slog.w(PackageManagerService.TAG, "Code path for hidden system pkg "
-                                + ps.name + " changing from " + updatedPkg.codePathString
-                                + " to " + scanFile);
-                        updatedPkg.codePath = scanFile;
-                        updatedPkg.codePathString = scanFile.toString();
-                        updatedPkg.resourcePath = scanFile;
-                        updatedPkg.resourcePathString = scanFile.toString();
+                                + ps.name + " changing from " + updatedPs.codePathString
+                                + " to " + pkg.codePath);
+                        final File codePath = new File(pkg.codePath);
+                        updatedPs.codePath = codePath;
+                        updatedPs.codePathString = pkg.codePath;
+                        updatedPs.resourcePath = codePath;
+                        updatedPs.resourcePathString = pkg.codePath;
                     }
-                    updatedPkg.pkg = pkg;
-                    updatedPkg.versionCode = pkg.mVersionCode;
+                    updatedPs.pkg = pkg;
+                    updatedPs.versionCode = pkg.mVersionCode;
 
                     // Update the disabled system child packages to point to the package too.
-                    final int childCount = updatedPkg.childPackageNames != null
-                            ? updatedPkg.childPackageNames.size() : 0;
+                    final int childCount = updatedPs.childPackageNames != null
+                            ? updatedPs.childPackageNames.size() : 0;
                     for (int i = 0; i < childCount; i++) {
-                        String childPackageName = updatedPkg.childPackageNames.get(i);
+                        String childPackageName = updatedPs.childPackageNames.get(i);
                         PackageSetting updatedChildPkg = mSettings.getDisabledSystemPkgLPr(
                                 childPackageName);
                         if (updatedChildPkg != null) {
@@ -8384,7 +8385,7 @@
                         mPackages.remove(ps.name);
                     }
 
-                    logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + scanFile
+                    logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + pkg.codePath
                             + " reverting from " + ps.codePathString
                             + ": new version " + pkg.mVersionCode
                             + " better than installed " + ps.versionCode);
@@ -8431,16 +8432,16 @@
         if (isUpdatedSystemPkg && !isUpdatedPkgBetter) {
             // Set CPU Abis to application info.
             if ((scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0) {
-                final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, updatedPkg);
-                derivePackageAbi(pkg, scanFile, cpuAbiOverride, false, mAppLib32InstallDir);
+                final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, updatedPs);
+                derivePackageAbi(pkg, cpuAbiOverride, false, mAppLib32InstallDir);
             } else {
-                pkg.applicationInfo.primaryCpuAbi = updatedPkg.primaryCpuAbiString;
-                pkg.applicationInfo.secondaryCpuAbi = updatedPkg.secondaryCpuAbiString;
+                pkg.applicationInfo.primaryCpuAbi = updatedPs.primaryCpuAbiString;
+                pkg.applicationInfo.secondaryCpuAbi = updatedPs.secondaryCpuAbiString;
             }
-            pkg.mExtras = updatedPkg;
+            pkg.mExtras = updatedPs;
 
             throw new PackageManagerException(Log.WARN, "Package " + ps.name + " at "
-                    + scanFile + " ignored: updated version " + ps.versionCode
+                    + pkg.codePath + " ignored: updated version " + ps.versionCode
                     + " better than this " + pkg.mVersionCode);
         }
 
@@ -8450,19 +8451,19 @@
 
             // An updated privileged application will not have the PARSE_IS_PRIVILEGED
             // flag set initially
-            if ((updatedPkg.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
+            if ((updatedPs.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
                 scanFlags |= SCAN_AS_PRIVILEGED;
             }
 
             // An updated OEM app will not have the PARSE_IS_OEM
             // flag set initially
-            if ((updatedPkg.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0) {
+            if ((updatedPs.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0) {
                 scanFlags |= SCAN_AS_OEM;
             }
         }
 
         // Verify certificates against what was last scanned
-        collectCertificatesLI(ps, pkg, scanFile, parseFlags);
+        collectCertificatesLI(ps, pkg, parseFlags);
 
         /*
          * A new system app appeared, but we already had a non-system one of the
@@ -8492,7 +8493,7 @@
                  */
                 if (pkg.mVersionCode <= ps.versionCode) {
                     shouldHideSystemApp = true;
-                    logCriticalInfo(Log.INFO, "Package " + ps.name + " appeared at " + scanFile
+                    logCriticalInfo(Log.INFO, "Package " + ps.name + " appeared at " + pkg.codePath
                             + " but new version " + pkg.mVersionCode + " better than installed "
                             + ps.versionCode + "; hiding system");
                 } else {
@@ -8502,7 +8503,7 @@
                      * already-installed application and replace it with our own
                      * while keeping the application data.
                      */
-                    logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + scanFile
+                    logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + pkg.codePath
                             + " reverting from " + ps.codePathString + ": new version "
                             + pkg.mVersionCode + " better than installed " + ps.versionCode);
                     InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
@@ -9976,8 +9977,7 @@
             if ((scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0) {
                 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
                 final boolean extractNativeLibs = !pkg.isLibrary();
-                derivePackageAbi(pkg, scanFile, cpuAbiOverride, extractNativeLibs,
-                        mAppLib32InstallDir);
+                derivePackageAbi(pkg, cpuAbiOverride, extractNativeLibs, mAppLib32InstallDir);
                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
 
                 // Some system apps still use directory structure for native libraries
@@ -10084,7 +10084,7 @@
         }
 
         // Take care of first install / last update times.
-        final long scanFileTime = getLastModifiedTime(pkg, scanFile);
+        final long scanFileTime = getLastModifiedTime(pkg);
         if (currentTime != 0) {
             if (pkgSetting.firstInstallTime == 0) {
                 pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = currentTime;
@@ -10864,10 +10864,9 @@
      *
      * If {@code extractLibs} is true, native libraries are extracted from the app if required.
      */
-    private static void derivePackageAbi(PackageParser.Package pkg, File scanFile,
-                                 String cpuAbiOverride, boolean extractLibs,
-                                 File appLib32InstallDir)
-            throws PackageManagerException {
+    private static void derivePackageAbi(PackageParser.Package pkg, String cpuAbiOverride,
+            boolean extractLibs, File appLib32InstallDir)
+                    throws PackageManagerException {
         // Give ourselves some initial paths; we'll come back for another
         // pass once we've determined ABI below.
         setNativeLibraryPaths(pkg, appLib32InstallDir);
@@ -15000,7 +14999,12 @@
             resourceFile = afterCodeFile;
 
             // Reflect the rename in scanned details
-            pkg.setCodePath(afterCodeFile.getAbsolutePath());
+            try {
+                pkg.setCodePath(afterCodeFile.getCanonicalPath());
+            } catch (IOException e) {
+                Slog.e(TAG, "Failed to get path: " + afterCodeFile, e);
+                return false;
+            }
             pkg.setBaseCodePath(FileUtils.rewriteAfterRename(beforeCodeFile,
                     afterCodeFile, pkg.baseCodePath));
             pkg.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
@@ -16482,8 +16486,7 @@
                 String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
                     args.abiOverride : pkg.cpuAbiOverride);
                 final boolean extractNativeLibs = !pkg.isLibrary();
-                derivePackageAbi(pkg, new File(pkg.codePath), abiOverride,
-                        extractNativeLibs, mAppLib32InstallDir);
+                derivePackageAbi(pkg, abiOverride, extractNativeLibs, mAppLib32InstallDir);
             } catch (PackageManagerException pme) {
                 Slog.e(TAG, "Error deriving application ABI", pme);
                 res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI");
@@ -17487,21 +17490,19 @@
         }
     }
 
-    static boolean locationIsPrivileged(File path) {
+    static boolean locationIsPrivileged(String path) {
         try {
-            final String privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app")
-                    .getCanonicalPath();
-            return path.getCanonicalPath().startsWith(privilegedAppDir);
+            final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
+            return path.startsWith(privilegedAppDir.getCanonicalPath());
         } catch (IOException e) {
             Slog.e(TAG, "Unable to access code path " + path);
         }
         return false;
     }
 
-    static boolean locationIsOem(File path) {
+    static boolean locationIsOem(String path) {
         try {
-            return path.getCanonicalPath().startsWith(
-                    Environment.getOemDirectory().getCanonicalPath());
+            return path.startsWith(Environment.getOemDirectory().getCanonicalPath());
         } catch (IOException e) {
             Slog.e(TAG, "Unable to access code path " + path);
         }
@@ -17597,7 +17598,7 @@
         // Install the system package
         if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs);
         try {
-            installPackageFromSystemLIF(disabledPs.codePath, false /*isPrivileged*/, allUserHandles,
+            installPackageFromSystemLIF(disabledPs.codePathString, false, allUserHandles,
                     outInfo.origUsers, deletedPs.getPermissionsState(), writeSettings);
         } catch (PackageManagerException e) {
             Slog.w(TAG, "Failed to restore system package:" + deletedPkg.packageName + ": "
@@ -17614,7 +17615,7 @@
     /**
      * Installs a package that's already on the system partition.
      */
-    private PackageParser.Package installPackageFromSystemLIF(@NonNull File codePath,
+    private PackageParser.Package installPackageFromSystemLIF(@NonNull String codePathString,
             boolean isPrivileged, @Nullable int[] allUserHandles, @Nullable int[] origUserHandles,
             @Nullable PermissionsState origPermissionState, boolean writeSettings)
                     throws PackageManagerException {
@@ -17623,13 +17624,14 @@
                 | PackageParser.PARSE_MUST_BE_APK
                 | PackageParser.PARSE_IS_SYSTEM_DIR;
         @ScanFlags int scanFlags = SCAN_AS_SYSTEM;
-        if (isPrivileged || locationIsPrivileged(codePath)) {
+        if (isPrivileged || locationIsPrivileged(codePathString)) {
             scanFlags |= SCAN_AS_PRIVILEGED;
         }
-        if (locationIsOem(codePath)) {
+        if (locationIsOem(codePathString)) {
             scanFlags |= SCAN_AS_OEM;
         }
 
+        final File codePath = new File(codePathString);
         final PackageParser.Package pkg =
                 scanPackageTracedLI(codePath, parseFlags, scanFlags, 0 /*currentTime*/, null);
 
@@ -19741,7 +19743,7 @@
                                 // until we can disable the package later.
                                 enableSystemPackageLPw(deletedPkg);
                             }
-                            installPackageFromSystemLIF(new File(deletedPkg.codePath),
+                            installPackageFromSystemLIF(deletedPkg.codePath,
                                     false /*isPrivileged*/, null /*allUserHandles*/,
                                     null /*origUserHandles*/, null /*origPermissionsState*/,
                                     true /*writeSettings*/);
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 758abd7..fb6278a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -295,19 +295,20 @@
         return false;
     }
 
-    public static long getLastModifiedTime(PackageParser.Package pkg, File srcFile) {
-        if (srcFile.isDirectory()) {
-            final File baseFile = new File(pkg.baseCodePath);
-            long maxModifiedTime = baseFile.lastModified();
-            if (pkg.splitCodePaths != null) {
-                for (int i = pkg.splitCodePaths.length - 1; i >=0; --i) {
-                    final File splitFile = new File(pkg.splitCodePaths[i]);
-                    maxModifiedTime = Math.max(maxModifiedTime, splitFile.lastModified());
-                }
-            }
-            return maxModifiedTime;
+    public static long getLastModifiedTime(PackageParser.Package pkg) {
+        final File srcFile = new File(pkg.codePath);
+        if (!srcFile.isDirectory()) {
+            return srcFile.lastModified();
         }
-        return srcFile.lastModified();
+        final File baseFile = new File(pkg.baseCodePath);
+        long maxModifiedTime = baseFile.lastModified();
+        if (pkg.splitCodePaths != null) {
+            for (int i = pkg.splitCodePaths.length - 1; i >=0; --i) {
+                final File splitFile = new File(pkg.splitCodePaths[i]);
+                maxModifiedTime = Math.max(maxModifiedTime, splitFile.lastModified());
+            }
+        }
+        return maxModifiedTime;
     }
 
     /**
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 7077fd1..ddad677 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3572,11 +3572,10 @@
         int pkgFlags = 0;
         int pkgPrivateFlags = 0;
         pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
-        final File codePathFile = new File(codePathStr);
-        if (PackageManagerService.locationIsPrivileged(codePathFile)) {
+        if (PackageManagerService.locationIsPrivileged(codePathStr)) {
             pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
         }
-        PackageSetting ps = new PackageSetting(name, realName, codePathFile,
+        PackageSetting ps = new PackageSetting(name, realName, new File(codePathStr),
                 new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiStr,
                 secondaryCpuAbiStr, cpuAbiOverrideStr, versionCode, pkgFlags, pkgPrivateFlags,
                 parentPackageName, null /*childPackageNames*/, 0 /*sharedUserId*/, null, null);
diff --git a/services/core/java/com/android/server/policy/BarController.java b/services/core/java/com/android/server/policy/BarController.java
index b179235..10d9565 100644
--- a/services/core/java/com/android/server/policy/BarController.java
+++ b/services/core/java/com/android/server/policy/BarController.java
@@ -24,9 +24,9 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
-import android.view.WindowManagerPolicy.WindowState;
 
 import com.android.server.LocalServices;
+import com.android.server.policy.WindowManagerPolicy.WindowState;
 import com.android.server.statusbar.StatusBarManagerInternal;
 
 import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
index 3707a5e..108b6b2 100644
--- a/services/core/java/com/android/server/policy/GlobalActions.java
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -14,14 +14,14 @@
 
 package com.android.server.policy;
 
-import com.android.server.LocalServices;
-import com.android.server.statusbar.StatusBarManagerInternal;
-import com.android.server.statusbar.StatusBarManagerInternal.GlobalActionsListener;
-
 import android.content.Context;
 import android.os.Handler;
 import android.util.Slog;
-import android.view.WindowManagerPolicy.WindowManagerFuncs;
+
+import com.android.server.LocalServices;
+import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs;
+import com.android.server.statusbar.StatusBarManagerInternal;
+import com.android.server.statusbar.StatusBarManagerInternal.GlobalActionsListener;
 
 class GlobalActions implements GlobalActionsListener {
 
diff --git a/services/core/java/com/android/server/policy/LegacyGlobalActions.java b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
index 8eb6d06..96d062d 100644
--- a/services/core/java/com/android/server/policy/LegacyGlobalActions.java
+++ b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
@@ -25,6 +25,7 @@
 import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.R;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs;
 
 import android.app.ActivityManager;
 import android.app.Dialog;
@@ -64,7 +65,6 @@
 import android.view.ViewGroup;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
-import android.view.WindowManagerPolicy.WindowManagerFuncs;
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.AdapterView;
 import android.widget.BaseAdapter;
@@ -919,7 +919,7 @@
         /**
          * @param enabledIconResId The icon for when this action is on.
          * @param disabledIconResid The icon for when this action is off.
-         * @param essage The general information message, e.g 'Silent Mode'
+         * @param message The general information message, e.g 'Silent Mode'
          * @param enabledStatusMessageResId The on status message, e.g 'sound disabled'
          * @param disabledStatusMessageResId The off status message, e.g. 'sound enabled'
          */
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 384070c..7415ec3 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -119,12 +119,13 @@
 import static android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION;
 import static android.view.WindowManagerGlobal.ADD_OKAY;
 import static android.view.WindowManagerGlobal.ADD_PERMISSION_DENIED;
-import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
-import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
-import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
-import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
-import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED;
-import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
+
+import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
+import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
+import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
+import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
+import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED;
+import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
 
 import android.annotation.Nullable;
 import android.app.ActivityManager;
@@ -210,7 +211,6 @@
 import android.util.SparseArray;
 import android.util.proto.ProtoOutputStream;
 import android.view.Display;
-import android.view.DisplayFrames;
 import android.view.Gravity;
 import android.view.HapticFeedbackConstants;
 import android.view.IApplicationToken;
@@ -230,9 +230,6 @@
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
 import android.view.WindowManagerGlobal;
-import android.view.WindowManagerInternal;
-import android.view.WindowManagerInternal.AppTransitionListener;
-import android.view.WindowManagerPolicy;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.animation.Animation;
@@ -243,6 +240,7 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IShortcutService;
@@ -259,6 +257,9 @@
 import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.vr.VrManagerInternal;
 import com.android.server.wm.AppTransition;
+import com.android.server.wm.DisplayFrames;
+import com.android.server.wm.WindowManagerInternal;
+import com.android.server.wm.WindowManagerInternal.AppTransitionListener;
 
 import java.io.File;
 import java.io.FileReader;
@@ -1053,7 +1054,8 @@
 
     private ImmersiveModeConfirmation mImmersiveModeConfirmation;
 
-    private SystemGesturesPointerEventListener mSystemGestures;
+    @VisibleForTesting
+    SystemGesturesPointerEventListener mSystemGestures;
 
     IStatusBarService getStatusBarService() {
         synchronized (mServiceAquireLock) {
@@ -2664,17 +2666,21 @@
             // The status bar is the only window allowed to exhibit keyguard behavior.
             attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
         }
+    }
 
+    private int getImpliedSysUiFlagsForLayout(LayoutParams attrs) {
+        int impliedFlags = 0;
         if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0) {
-            attrs.subtreeSystemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+            impliedFlags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
         }
         final boolean forceWindowDrawsStatusBarBackground =
                 (attrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) != 0;
         if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
                 || forceWindowDrawsStatusBarBackground
                         && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT) {
-            attrs.subtreeSystemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+            impliedFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
         }
+        return impliedFlags;
     }
 
     void readLidState() {
@@ -2724,7 +2730,7 @@
     @Override
     public void onConfigurationChanged() {
         // TODO(multi-display): Define policy for secondary displays.
-        Context uiContext = ActivityThread.currentActivityThread().getSystemUiContext();
+        Context uiContext = getSystemUiContext();
         final Resources res = uiContext.getResources();
 
         mStatusBarHeight =
@@ -2765,6 +2771,11 @@
         }
     }
 
+    @VisibleForTesting
+    Context getSystemUiContext() {
+        return ActivityThread.currentActivityThread().getSystemUiContext();
+    }
+
     @Override
     public int getMaxWallpaperLayer() {
         return getWindowLayerFromTypeLw(TYPE_STATUS_BAR);
@@ -4825,7 +4836,8 @@
         final int fl = PolicyControl.getWindowFlags(win, attrs);
         final int pfl = attrs.privateFlags;
         final int sim = attrs.softInputMode;
-        final int sysUiFl = PolicyControl.getSystemUiVisibility(win, null);
+        final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(win, null);
+        final int sysUiFl = requestedSysUiFl | getImpliedSysUiFlagsForLayout(attrs);
 
         final Rect pf = mTmpParentFrame;
         final Rect df = mTmpDisplayFrame;
diff --git a/services/core/java/com/android/server/policy/PolicyControl.java b/services/core/java/com/android/server/policy/PolicyControl.java
index dbafc42..3f26d86 100644
--- a/services/core/java/com/android/server/policy/PolicyControl.java
+++ b/services/core/java/com/android/server/policy/PolicyControl.java
@@ -25,7 +25,8 @@
 import android.view.View;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
-import android.view.WindowManagerPolicy.WindowState;
+
+import com.android.server.policy.WindowManagerPolicy.WindowState;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -36,7 +37,7 @@
  * This includes forcing immersive mode behavior for one or both system bars (based on a package
  * list) and permanently disabling immersive mode confirmations for specific packages.
  *
- * Control by setting {@link Settings.Global.POLICY_CONTROL} to one or more name-value pairs.
+ * Control by setting {@link Settings.Global#POLICY_CONTROL} to one or more name-value pairs.
  * e.g.
  *   to force immersive mode everywhere:
  *     "immersive.full=*"
diff --git a/services/core/java/com/android/server/policy/SplashScreenSurface.java b/services/core/java/com/android/server/policy/SplashScreenSurface.java
index 37d6c0b..b9202c3 100644
--- a/services/core/java/com/android/server/policy/SplashScreenSurface.java
+++ b/services/core/java/com/android/server/policy/SplashScreenSurface.java
@@ -23,11 +23,10 @@
 import android.util.Slog;
 import android.view.View;
 import android.view.WindowManager;
-import android.view.WindowManagerPolicy;
-import android.view.WindowManagerPolicy.StartingSurface;
 
 import com.android.internal.policy.DecorView;
 import com.android.internal.policy.PhoneWindow;
+import com.android.server.policy.WindowManagerPolicy.StartingSurface;
 
 /**
  * Holds the contents of a splash screen starting window, i.e. the {@link DecorView} of a
diff --git a/services/core/java/com/android/server/policy/StatusBarController.java b/services/core/java/com/android/server/policy/StatusBarController.java
index ecc88b5..af7e91c 100644
--- a/services/core/java/com/android/server/policy/StatusBarController.java
+++ b/services/core/java/com/android/server/policy/StatusBarController.java
@@ -18,7 +18,7 @@
 
 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
 import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
-import static android.view.WindowManagerInternal.AppTransitionListener;
+import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
 
 import android.app.StatusBarManager;
 import android.os.IBinder;
diff --git a/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java b/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
index 598c58e..d3cc8ef 100644
--- a/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
+++ b/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
@@ -24,7 +24,7 @@
 import android.view.GestureDetector;
 import android.view.InputDevice;
 import android.view.MotionEvent;
-import android.view.WindowManagerPolicy.PointerEventListener;
+import android.view.WindowManagerPolicyConstants.PointerEventListener;
 import android.widget.OverScroller;
 
 /*
diff --git a/core/java/android/view/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
similarity index 92%
rename from core/java/android/view/WindowManagerPolicy.java
rename to services/core/java/com/android/server/policy/WindowManagerPolicy.java
index c192f5c..b4e3583 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,10 +14,8 @@
  * limitations under the License.
  */
 
-package android.view;
+package com.android.server.policy;
 
-import static android.Manifest.permission;
-import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
@@ -63,9 +61,9 @@
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType;
 
+import android.Manifest;
 import android.annotation.IntDef;
 import android.annotation.Nullable;
-import android.annotation.SystemApi;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.res.CompatibilityInfo;
@@ -78,10 +76,20 @@
 import android.os.RemoteException;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
+import android.view.Display;
+import android.view.IApplicationToken;
+import android.view.IWindowManager;
+import android.view.InputEventReceiver;
+import android.view.KeyEvent;
+import android.view.Surface;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+import android.view.WindowManagerPolicyConstants;
 import android.view.animation.Animation;
 
 import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IShortcutService;
+import com.android.server.wm.DisplayFrames;
 
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -125,62 +133,26 @@
  * acquired by the window manager while it holds the window lock, so this is
  * even more restrictive than <var>Lw</var>.
  * </dl>
- *
- * @hide
  */
-public interface WindowManagerPolicy {
-    // Policy flags.  These flags are also defined in frameworks/base/include/ui/Input.h.
-    public final static int FLAG_WAKE = 0x00000001;
-    public final static int FLAG_VIRTUAL = 0x00000002;
-
-    public final static int FLAG_INJECTED = 0x01000000;
-    public final static int FLAG_TRUSTED = 0x02000000;
-    public final static int FLAG_FILTERED = 0x04000000;
-    public final static int FLAG_DISABLE_KEY_REPEAT = 0x08000000;
-
-    public final static int FLAG_INTERACTIVE = 0x20000000;
-    public final static int FLAG_PASS_TO_USER = 0x40000000;
-
-    // Flags for IActivityManager.keyguardGoingAway()
-    public final static int KEYGUARD_GOING_AWAY_FLAG_TO_SHADE = 1 << 0;
-    public final static int KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS = 1 << 1;
-    public final static int KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER = 1 << 2;
-
-    // Flags used for indicating whether the internal and/or external input devices
-    // of some type are available.
-    public final static int PRESENCE_INTERNAL = 1 << 0;
-    public final static int PRESENCE_EXTERNAL = 1 << 1;
-
+public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
     // Navigation bar position values
     int NAV_BAR_LEFT = 1 << 0;
     int NAV_BAR_RIGHT = 1 << 1;
     int NAV_BAR_BOTTOM = 1 << 2;
 
-    public final static boolean WATCH_POINTER = false;
-
-    /**
-     * Sticky broadcast of the current HDMI plugged state.
-     */
-    public final static String ACTION_HDMI_PLUGGED = "android.intent.action.HDMI_PLUGGED";
-
-    /**
-     * Extra in {@link #ACTION_HDMI_PLUGGED} indicating the state: true if
-     * plugged in to HDMI, false if not.
-     */
-    public final static String EXTRA_HDMI_PLUGGED_STATE = "state";
-
-    /**
-     * Set to {@code true} when intent was invoked from pressing the home key.
-     * @hide
-     */
-    @SystemApi
-    public static final String EXTRA_FROM_HOME_KEY = "android.intent.extra.FROM_HOME_KEY";
-
     /**
      * Pass this event to the user / app.  To be returned from
      * {@link #interceptKeyBeforeQueueing}.
      */
-    public final static int ACTION_PASS_TO_USER = 0x00000001;
+    int ACTION_PASS_TO_USER = 0x00000001;
+    /** Layout state may have changed (so another layout will be performed) */
+    int FINISH_LAYOUT_REDO_LAYOUT = 0x0001;
+    /** Configuration state may have changed */
+    int FINISH_LAYOUT_REDO_CONFIG = 0x0002;
+    /** Wallpaper may need to move */
+    int FINISH_LAYOUT_REDO_WALLPAPER = 0x0004;
+    /** Need to recompute animations */
+    int FINISH_LAYOUT_REDO_ANIM = 0x0008;
 
     /**
      * Register shortcuts for window manager to dispatch.
@@ -241,7 +213,7 @@
          */
         public void computeFrameLw(Rect parentFrame, Rect displayFrame,
                 Rect overlayFrame, Rect contentFrame, Rect visibleFrame, Rect decorFrame,
-                Rect stableFrame, Rect outsetFrame);
+                Rect stableFrame, @Nullable Rect outsetFrame);
 
         /**
          * Retrieve the current frame of the window that has been assigned by
@@ -483,7 +455,7 @@
 
         /**
          * Returns true if the window owner can add internal system windows.
-         * That is, they have {@link permission#INTERNAL_SYSTEM_WINDOW}.
+         * That is, they have {@link Manifest.permission#INTERNAL_SYSTEM_WINDOW}.
          */
         default boolean canAddInternalSystemWindow() {
             return false;
@@ -491,7 +463,7 @@
 
         /**
          * Returns true if the window owner has the permission to acquire a sleep token when it's
-         * visible. That is, they have the permission {@link permission#DEVICE_POWER}.
+         * visible. That is, they have the permission {@link Manifest.permission#DEVICE_POWER}.
          */
         boolean canAcquireSleepToken();
     }
@@ -648,24 +620,6 @@
         }
     }
 
-    public interface PointerEventListener {
-        /**
-         * 1. onPointerEvent will be called on the service.UiThread.
-         * 2. motionEvent will be recycled after onPointerEvent returns so if it is needed later a
-         * copy() must be made and the copy must be recycled.
-         **/
-        void onPointerEvent(MotionEvent motionEvent);
-
-        /**
-         * @see #onPointerEvent(MotionEvent)
-         **/
-        default void onPointerEvent(MotionEvent motionEvent, int displayId) {
-            if (displayId == DEFAULT_DISPLAY) {
-                onPointerEvent(motionEvent);
-            }
-        }
-    }
-
     /** Window has been added to the screen. */
     public static final int TRANSIT_ENTER = 1;
     /** Window has been removed from the screen. */
@@ -682,13 +636,6 @@
     // NOTE: screen off reasons are in order of significance, with more
     // important ones lower than less important ones.
 
-    /** Screen turned off because of a device admin */
-    public final int OFF_BECAUSE_OF_ADMIN = 1;
-    /** Screen turned off because of power button */
-    public final int OFF_BECAUSE_OF_USER = 2;
-    /** Screen turned off because of timeout */
-    public final int OFF_BECAUSE_OF_TIMEOUT = 3;
-
     /** @hide */
     @IntDef({USER_ROTATION_FREE, USER_ROTATION_LOCKED})
     @Retention(RetentionPolicy.SOURCE)
@@ -806,7 +753,7 @@
      * @param type The type of window being assigned.
      * @param canAddInternalSystemWindow If the owner window associated with the type we are
      *        evaluating can add internal system windows. I.e they have
-     *        {@link permission#INTERNAL_SYSTEM_WINDOW}. If true, alert window
+     *        {@link Manifest.permission#INTERNAL_SYSTEM_WINDOW}. If true, alert window
      *        types {@link android.view.WindowManager.LayoutParams#isSystemAlertWindowType(int)}
      *        can be assigned layers greater than the layer for
      *        {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY} Else, their
@@ -916,13 +863,6 @@
         }
     }
 
-    int APPLICATION_LAYER = 2;
-    int APPLICATION_MEDIA_SUBLAYER = -2;
-    int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
-    int APPLICATION_PANEL_SUBLAYER = 1;
-    int APPLICATION_SUB_PANEL_SUBLAYER = 2;
-    int APPLICATION_ABOVE_SUB_PANEL_SUBLAYER = 3;
-
     /**
      * Return how to Z-order sub-windows in relation to the window they are attached to.
      * Return positive to have them ordered in front, negative for behind.
@@ -975,7 +915,7 @@
     /**
      * Return the available screen width that we should report for the
      * configuration.  This must be no larger than
-     * {@link #getNonDecorDisplayWidth(int, int, int)}; it may be smaller than
+     * {@link #getNonDecorDisplayWidth(int, int, int, int int, int)}; it may be smaller than
      * that to account for more transient decoration like a status bar.
      */
     public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation,
@@ -984,7 +924,7 @@
     /**
      * Return the available screen height that we should report for the
      * configuration.  This must be no larger than
-     * {@link #getNonDecorDisplayHeight(int, int, int)}; it may be smaller than
+     * {@link #getNonDecorDisplayHeight(int, int, int, int, int)}; it may be smaller than
      * that to account for more transient decoration like a status bar.
      */
     public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation,
@@ -1213,15 +1153,6 @@
         return false;
     }
 
-    /** Layout state may have changed (so another layout will be performed) */
-    static final int FINISH_LAYOUT_REDO_LAYOUT = 0x0001;
-    /** Configuration state may have changed */
-    static final int FINISH_LAYOUT_REDO_CONFIG = 0x0002;
-    /** Wallpaper may need to move */
-    static final int FINISH_LAYOUT_REDO_WALLPAPER = 0x0004;
-    /** Need to recompute animations */
-    static final int FINISH_LAYOUT_REDO_ANIM = 0x0008;
-
     /**
      * Called following layout of all windows before each window has policy applied.
      *
@@ -1374,7 +1305,7 @@
     public void enableKeyguard(boolean enabled);
 
     /**
-     * Callback used by {@link WindowManagerPolicy#exitKeyguardSecurely}
+     * Callback used by {@link #exitKeyguardSecurely}
      */
     interface OnKeyguardExitResult {
         void onKeyguardExitResult(boolean success);
@@ -1552,8 +1483,8 @@
      *
      * @return The rotation mode.
      *
-     * @see WindowManagerPolicy#USER_ROTATION_LOCKED
-     * @see WindowManagerPolicy#USER_ROTATION_FREE
+     * @see #USER_ROTATION_LOCKED
+     * @see #USER_ROTATION_FREE
      */
     @UserRotationMode
     public int getUserRotationMode();
@@ -1561,8 +1492,7 @@
     /**
      * Inform the policy that the user has chosen a preferred orientation ("rotation lock").
      *
-     * @param mode One of {@link WindowManagerPolicy#USER_ROTATION_LOCKED} or
-     *             {@link WindowManagerPolicy#USER_ROTATION_FREE}.
+     * @param mode One of {@link #USER_ROTATION_LOCKED} or {@link #USER_ROTATION_FREE}.
      * @param rotation One of {@link Surface#ROTATION_0}, {@link Surface#ROTATION_90},
      *                 {@link Surface#ROTATION_180}, {@link Surface#ROTATION_270}.
      */
@@ -1757,20 +1687,4 @@
                 return Integer.toString(mode);
         }
     }
-
-    /**
-     * Convert the off reason to a human readable format.
-     */
-    static String offReasonToString(int why) {
-        switch (why) {
-            case OFF_BECAUSE_OF_ADMIN:
-                return "OFF_BECAUSE_OF_ADMIN";
-            case OFF_BECAUSE_OF_USER:
-                return "OFF_BECAUSE_OF_USER";
-            case OFF_BECAUSE_OF_TIMEOUT:
-                return "OFF_BECAUSE_OF_TIMEOUT";
-            default:
-                return Integer.toString(why);
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 70cd54ff..58002bc 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -15,14 +15,14 @@
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.Slog;
-import android.view.WindowManagerPolicy;
-import android.view.WindowManagerPolicy.OnKeyguardExitResult;
+import android.view.WindowManagerPolicyConstants;
 
 import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IKeyguardDrawnCallback;
 import com.android.internal.policy.IKeyguardExitCallback;
 import com.android.internal.policy.IKeyguardService;
 import com.android.server.UiThread;
+import com.android.server.policy.WindowManagerPolicy.OnKeyguardExitResult;
 
 import java.io.PrintWriter;
 
@@ -419,7 +419,7 @@
         pw.println(prefix + "deviceHasKeyguard=" + mKeyguardState.deviceHasKeyguard);
         pw.println(prefix + "enabled=" + mKeyguardState.enabled);
         pw.println(prefix + "offReason=" +
-                WindowManagerPolicy.offReasonToString(mKeyguardState.offReason));
+                WindowManagerPolicyConstants.offReasonToString(mKeyguardState.offReason));
         pw.println(prefix + "currentUser=" + mKeyguardState.currentUser);
         pw.println(prefix + "bootCompleted=" + mKeyguardState.bootCompleted);
         pw.println(prefix + "screenState=" + screenStateToString(mKeyguardState.screenState));
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 0ecf0e1..8ee26f29 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -25,6 +25,7 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
+import com.android.server.policy.WindowManagerPolicy;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -49,7 +50,6 @@
 import android.provider.Settings;
 import android.util.EventLog;
 import android.util.Slog;
-import android.view.WindowManagerPolicy;
 import android.view.inputmethod.InputMethodManagerInternal;
 
 /**
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 2c87a40..7f1a534 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -69,7 +69,6 @@
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 import android.view.Display;
-import android.view.WindowManagerPolicy;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IAppOpsService;
@@ -90,6 +89,7 @@
 import com.android.server.am.BatteryStatsService;
 import com.android.server.lights.Light;
 import com.android.server.lights.LightsManager;
+import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.power.batterysaver.BatterySaverController;
 
 import libcore.util.Objects;
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
index ae01ea57..80bc935 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
@@ -16,6 +16,7 @@
 package com.android.server.power.batterysaver;
 
 import android.Manifest;
+import android.app.ActivityManagerInternal;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -109,6 +110,9 @@
         final IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
         filter.addAction(Intent.ACTION_SCREEN_OFF);
         mContext.registerReceiver(mReceiver, filter);
+
+        mFileUpdater.systemReady(LocalServices.getService(ActivityManagerInternal.class)
+                .isRuntimeRestarted());
     }
 
     private PowerManager getPowerManager() {
@@ -217,13 +221,6 @@
             pmi.powerHint(PowerHint.LOW_POWER, enabled ? 1 : 0);
         }
 
-        if (enabled) {
-            // STOPSHIP Remove the toast.
-            Toast.makeText(mContext,
-                    com.android.internal.R.string.battery_saver_warning,
-                    Toast.LENGTH_LONG).show();
-        }
-
         if (ArrayUtils.isEmpty(fileValues)) {
             mFileUpdater.restoreDefault();
         } else {
@@ -231,6 +228,13 @@
         }
 
         if (sendBroadcast) {
+            if (enabled) {
+                // STOPSHIP Remove the toast.
+                Toast.makeText(mContext,
+                        com.android.internal.R.string.battery_saver_warning,
+                        Toast.LENGTH_LONG).show();
+            }
+
             if (DEBUG) {
                 Slog.i(TAG, "Sending broadcasts for mode: " + enabled);
             }
diff --git a/services/core/java/com/android/server/power/batterysaver/FileUpdater.java b/services/core/java/com/android/server/power/batterysaver/FileUpdater.java
index cc1b540..e0ab9e9 100644
--- a/services/core/java/com/android/server/power/batterysaver/FileUpdater.java
+++ b/services/core/java/com/android/server/power/batterysaver/FileUpdater.java
@@ -16,19 +16,34 @@
 package com.android.server.power.batterysaver;
 
 import android.content.Context;
+import android.os.Environment;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.SystemProperties;
 import android.util.ArrayMap;
+import android.util.AtomicFile;
 import android.util.Slog;
+import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
 import com.android.server.IoThread;
 
 import libcore.io.IoUtils;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.io.FileWriter;
 import java.io.IOException;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Map;
 
@@ -47,6 +62,14 @@
 
     private static final boolean DEBUG = BatterySaverController.DEBUG;
 
+    /**
+     * If this system property is set to 1, it'll skip all file writes. This can be used when
+     * one needs to change max CPU frequency for benchmarking, for example.
+     */
+    private static final String PROP_SKIP_WRITE = "debug.batterysaver.no_write_files";
+
+    private static final String TAG_DEFAULT_ROOT = "defaults";
+
     // Don't do disk access with this lock held.
     private final Object mLock = new Object();
 
@@ -93,6 +116,21 @@
         RETRY_INTERVAL_MS = retryIntervalMs;
     }
 
+    public void systemReady(boolean runtimeRestarted) {
+        synchronized (mLock) {
+            if (runtimeRestarted) {
+                // If it runtime restarted, read the original values from the disk and apply.
+                if (loadDefaultValuesLocked()) {
+                    Slog.d(TAG, "Default values loaded after runtime restart; writing them...");
+                    restoreDefault();
+                }
+            } else {
+                // Delete it, without checking the result. (file-not-exist is not an exception.)
+                injectDefaultValuesFilename().delete();
+            }
+        }
+    }
+
     /**
      * Write values to files. (Note the actual writes happen ASAP but asynchronously.)
      */
@@ -241,6 +279,7 @@
         }
         synchronized (mLock) {
             mDefaultValues.put(file, originalValue);
+            saveDefaultValuesLocked();
         }
         return true;
     }
@@ -252,17 +291,92 @@
 
     @VisibleForTesting
     void injectWriteToFile(String file, String value) throws IOException {
+        if (injectShouldSkipWrite()) {
+            Slog.i(TAG, "Skipped writing to '" + file + "'");
+            return;
+        }
         if (DEBUG) {
             Slog.d(TAG, "Writing: '" + value + "' to '" + file + "'");
         }
         try (FileWriter out = new FileWriter(file)) {
             out.write(value);
-        } catch (IOException e) {
+        } catch (IOException | RuntimeException e) {
             Slog.w(TAG, "Failed writing '" + value + "' to '" + file + "': " + e.getMessage());
             throw e;
         }
     }
 
+    private void saveDefaultValuesLocked() {
+        final AtomicFile file = new AtomicFile(injectDefaultValuesFilename());
+
+        FileOutputStream outs = null;
+        try {
+            file.getBaseFile().getParentFile().mkdirs();
+            outs = file.startWrite();
+
+            // Write to XML
+            XmlSerializer out = new FastXmlSerializer();
+            out.setOutput(outs, StandardCharsets.UTF_8.name());
+            out.startDocument(null, true);
+            out.startTag(null, TAG_DEFAULT_ROOT);
+
+            XmlUtils.writeMapXml(mDefaultValues, out, null);
+
+            // Epilogue.
+            out.endTag(null, TAG_DEFAULT_ROOT);
+            out.endDocument();
+
+            // Close.
+            file.finishWrite(outs);
+        } catch (IOException | XmlPullParserException | RuntimeException e) {
+            Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e);
+            file.failWrite(outs);
+        }
+    }
+
+    @VisibleForTesting
+    boolean loadDefaultValuesLocked() {
+        final AtomicFile file = new AtomicFile(injectDefaultValuesFilename());
+        if (DEBUG) {
+            Slog.d(TAG, "Loading from " + file.getBaseFile());
+        }
+        Map<String, String> read = null;
+        try (FileInputStream in = file.openRead()) {
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(in, StandardCharsets.UTF_8.name());
+
+            int type;
+            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+                if (type != XmlPullParser.START_TAG) {
+                    continue;
+                }
+                final int depth = parser.getDepth();
+                // Check the root tag
+                final String tag = parser.getName();
+                if (depth == 1) {
+                    if (!TAG_DEFAULT_ROOT.equals(tag)) {
+                        Slog.e(TAG, "Invalid root tag: " + tag);
+                        return false;
+                    }
+                    continue;
+                }
+                final String[] tagName = new String[1];
+                read = (ArrayMap<String, String>) XmlUtils.readThisArrayMapXml(parser,
+                        TAG_DEFAULT_ROOT, tagName, null);
+            }
+        } catch (FileNotFoundException e) {
+            read = null;
+        } catch (IOException | XmlPullParserException | RuntimeException e) {
+            Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e);
+        }
+        if (read != null) {
+            mDefaultValues.clear();
+            mDefaultValues.putAll(read);
+            return true;
+        }
+        return false;
+    }
+
     private void doWtf(String message) {
         injectWtf(message, null);
     }
@@ -271,4 +385,20 @@
     void injectWtf(String message, Throwable e) {
         Slog.wtf(TAG, message, e);
     }
+
+    File injectDefaultValuesFilename() {
+        final File dir = new File(Environment.getDataSystemDirectory(), "battery-saver");
+        dir.mkdirs();
+        return new File(dir, "default-values.xml");
+    }
+
+    @VisibleForTesting
+    boolean injectShouldSkipWrite() {
+        return SystemProperties.getBoolean(PROP_SKIP_WRITE, false);
+    }
+
+    @VisibleForTesting
+    ArrayMap<String, String> getDefaultValuesForTest() {
+        return mDefaultValues;
+    }
 }
diff --git a/services/core/java/com/android/server/vr/Vr2dDisplay.java b/services/core/java/com/android/server/vr/Vr2dDisplay.java
index 95d03d4..7866e7d 100644
--- a/services/core/java/com/android/server/vr/Vr2dDisplay.java
+++ b/services/core/java/com/android/server/vr/Vr2dDisplay.java
@@ -24,9 +24,8 @@
 import android.service.vr.IVrManager;
 import android.util.Log;
 import android.view.Surface;
-import android.view.WindowManagerInternal;
 
-import com.android.server.vr.VrManagerService;
+import com.android.server.wm.WindowManagerInternal;
 
 /**
  * Creates a 2D Virtual Display while VR Mode is enabled. This display will be used to run and
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 5493207..1f4e64e 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -58,7 +58,7 @@
 import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
-import android.view.WindowManagerInternal;
+import com.android.server.wm.WindowManagerInternal;
 
 import com.android.internal.R;
 import com.android.internal.util.DumpUtils;
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 88d1e55..95b139a 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -55,14 +55,14 @@
 import android.view.ViewConfiguration;
 import android.view.WindowInfo;
 import android.view.WindowManager;
-import android.view.WindowManagerInternal.MagnificationCallbacks;
-import android.view.WindowManagerInternal.WindowsForAccessibilityCallback;
-import android.view.WindowManagerPolicy;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 
 import com.android.internal.R;
 import com.android.internal.os.SomeArgs;
+import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.wm.WindowManagerInternal.MagnificationCallbacks;
+import com.android.server.wm.WindowManagerInternal.WindowsForAccessibilityCallback;
 
 import java.util.ArrayList;
 import java.util.HashSet;
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index c19ede0..c2cbced 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -16,7 +16,6 @@
 
 package com.android.server.wm;
 
-import static android.view.WindowManagerInternal.AppTransitionListener;
 import static com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation;
 import static com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
 import static com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation;
@@ -44,6 +43,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index accfc65..5c1d5b2 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -16,7 +16,7 @@
 
 package com.android.server.wm;
 
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
 import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index 5841840..00a0d3d 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -45,10 +45,11 @@
 import android.util.Slog;
 import android.view.DisplayInfo;
 import android.view.IApplicationToken;
-import android.view.WindowManagerPolicy.StartingSurface;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.AttributeCache;
+import com.android.server.policy.WindowManagerPolicy.StartingSurface;
+
 /**
  * Controller for the app window token container. This is created by activity manager to link
  * activity records to the app window token container they use in window manager.
@@ -180,13 +181,12 @@
             IApplicationToken token, AppWindowContainerListener listener, int index,
             int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
             boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
-            int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
-            Rect bounds) {
+            int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos) {
         this(taskController, token, listener, index, requestedOrientation, fullscreen,
                 showForAllUsers,
                 configChanges, voiceInteraction, launchTaskBehind, alwaysFocusable,
                 targetSdkVersion, rotationAnimationHint, inputDispatchingTimeoutNanos,
-                WindowManagerService.getInstance(), bounds);
+                WindowManagerService.getInstance());
     }
 
     public AppWindowContainerController(TaskWindowContainerController taskController,
@@ -194,7 +194,7 @@
             int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
             boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
             int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
-            WindowManagerService service, Rect bounds) {
+            WindowManagerService service) {
         super(listener, service);
         mHandler = new H(service.mH.getLooper());
         mToken = token;
@@ -215,7 +215,7 @@
             atoken = createAppWindow(mService, token, voiceInteraction, task.getDisplayContent(),
                     inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion,
                     requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
-                    alwaysFocusable, this, bounds);
+                    alwaysFocusable, this);
             if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
                     + " controller=" + taskController + " at " + index);
             task.addChild(atoken, index);
@@ -227,11 +227,11 @@
             boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
             boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
             int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
-            boolean alwaysFocusable, AppWindowContainerController controller, Rect bounds) {
+            boolean alwaysFocusable, AppWindowContainerController controller) {
         return new AppWindowToken(service, token, voiceInteraction, dc,
                 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation,
                 rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
-                controller, bounds);
+                controller);
     }
 
     public void removeContainer(int displayId) {
@@ -298,17 +298,6 @@
         }
     }
 
-    // TODO(b/36505427): Maybe move to WindowContainerController so other sub-classes can use it as
-    // a generic way to set override config. Need to untangle current ways the override config is
-    // currently set for tasks and displays before we are doing that though.
-    public void onOverrideConfigurationChanged(Configuration overrideConfiguration, Rect bounds) {
-        synchronized(mWindowMap) {
-            if (mContainer != null) {
-                mContainer.onOverrideConfigurationChanged(overrideConfiguration, bounds);
-            }
-        }
-    }
-
     public void setDisablePreviewScreenshots(boolean disable) {
         synchronized (mWindowMap) {
             if (mContainer == null) {
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 98db80e..c39ce98 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -16,7 +16,6 @@
 
 package com.android.server.wm;
 
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
@@ -28,8 +27,8 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
@@ -67,10 +66,10 @@
 import android.view.SurfaceControl;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
-import android.view.WindowManagerPolicy.StartingSurface;
 
 import com.android.internal.util.ToBooleanFunction;
 import com.android.server.input.InputApplicationHandle;
+import com.android.server.policy.WindowManagerPolicy.StartingSurface;
 import com.android.server.wm.WindowManagerService.H;
 
 import java.io.PrintWriter;
@@ -176,11 +175,6 @@
     private boolean mLastContainsShowWhenLockedWindow;
     private boolean mLastContainsDismissKeyguardWindow;
 
-    // The bounds of this activity. Mainly used for aspect-ratio compatibility.
-    // TODO(b/36505427): Every level on WindowContainer now has bounds information, which directly
-    // affects the configuration. We should probably move this into that class.
-    private final Rect mBounds = new Rect();
-
     ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
     ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>();
 
@@ -197,8 +191,8 @@
             DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen,
             boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint,
             int configChanges, boolean launchTaskBehind, boolean alwaysFocusable,
-            AppWindowContainerController controller, Rect bounds) {
-        this(service, token, voiceInteraction, dc, fullscreen, bounds);
+            AppWindowContainerController controller) {
+        this(service, token, voiceInteraction, dc, fullscreen);
         setController(controller);
         mInputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
         mShowForAllUsers = showForAllUsers;
@@ -215,7 +209,7 @@
     }
 
     AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction,
-            DisplayContent dc, boolean fillsParent, Rect bounds) {
+            DisplayContent dc, boolean fillsParent) {
         super(service, token != null ? token.asBinder() : null, TYPE_APPLICATION, true, dc,
                 false /* ownerCanManageAppTokens */);
         appToken = token;
@@ -223,27 +217,6 @@
         mFillsParent = fillsParent;
         mInputApplicationHandle = new InputApplicationHandle(this);
         mAppAnimator = new AppWindowAnimator(this, service);
-        if (bounds != null) {
-            mBounds.set(bounds);
-        }
-    }
-
-    void onOverrideConfigurationChanged(Configuration overrideConfiguration, Rect bounds) {
-        onOverrideConfigurationChanged(overrideConfiguration);
-        if (mBounds.equals(bounds)) {
-            return;
-        }
-        // TODO(b/36505427): If bounds is in WC, then we can automatically call onResize() when set.
-        mBounds.set(bounds);
-        onResize();
-    }
-
-    void getBounds(Rect outBounds) {
-        outBounds.set(mBounds);
-    }
-
-    boolean hasBounds() {
-        return !mBounds.isEmpty();
     }
 
     void onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator) {
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index 7953ee4..ba67ff6 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -33,7 +33,6 @@
 import android.util.Slog;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
-import android.view.WindowManagerInternal;
 
 import com.android.internal.annotations.VisibleForTesting;
 
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index b534b8a..d340923 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -36,6 +36,7 @@
 import android.annotation.CallSuper;
 import android.app.WindowConfiguration;
 import android.content.res.Configuration;
+import android.graphics.Rect;
 import android.util.proto.ProtoOutputStream;
 
 import java.io.PrintWriter;
@@ -46,6 +47,11 @@
  * hierarchy.
  */
 public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
+    /**
+     * {@link #Rect} returned from {@link #getOverrideBounds()} to prevent original value from being
+     * set directly.
+     */
+    private Rect mReturnBounds = new Rect();
 
     /** Contains override configuration settings applied to this configuration container. */
     private Configuration mOverrideConfiguration = new Configuration();
@@ -71,6 +77,16 @@
     // TODO: Can't have ag/2592611 soon enough!
     private final Configuration mTmpConfig = new Configuration();
 
+    // Used for setting bounds
+    private final Rect mTmpRect = new Rect();
+
+    static final int BOUNDS_CHANGE_NONE = 0;
+    // Return value from {@link setBounds} indicating the position of the override bounds changed.
+    static final int BOUNDS_CHANGE_POSITION = 1;
+    // Return value from {@link setBounds} indicating the size of the override bounds changed.
+    static final int BOUNDS_CHANGE_SIZE = 1 << 1;
+
+
     /**
      * Returns full configuration applied to this configuration container.
      * This method should be used for getting settings applied in each particular level of the
@@ -148,6 +164,118 @@
         }
     }
 
+    /**
+     * Indicates whether this container has not specified any bounds different from its parent. In
+     * this case, it will inherit the bounds of the first ancestor which specifies a bounds.
+     * @return {@code true} if no explicit bounds have been set at this container level.
+     *         {@code false} otherwise.
+     */
+    public boolean matchParentBounds() {
+        return getOverrideBounds().isEmpty();
+    }
+
+    /**
+     * Returns whether the bounds specified is considered the same as the existing override bounds.
+     * This is either when the two bounds are equal or the override bounds is empty and the
+     * specified bounds is null.
+     *
+     * @return {@code true} if the bounds are equivalent, {@code false} otherwise
+     */
+    public boolean equivalentOverrideBounds(Rect bounds) {
+        return equivalentBounds(getOverrideBounds(),  bounds);
+    }
+
+    /**
+     * Returns whether the two bounds are equal to each other or are a combination of null or empty.
+     */
+    public static boolean equivalentBounds(Rect bounds, Rect other) {
+        return bounds == other
+                || (bounds != null && (bounds.equals(other) || (bounds.isEmpty() && other == null)))
+                || (other != null && other.isEmpty() && bounds == null);
+    }
+
+    /**
+     * Returns the effective bounds of this container, inheriting the first non-empty bounds set in
+     * its ancestral hierarchy, including itself.
+     * @return
+     */
+    public Rect getBounds() {
+        mReturnBounds.set(getConfiguration().windowConfiguration.getBounds());
+        return mReturnBounds;
+    }
+
+    public void getBounds(Rect outBounds) {
+        outBounds.set(getBounds());
+    }
+
+    /**
+     * Returns the current bounds explicitly set on this container. The {@link Rect} handed back is
+     * shared for all calls to this method and should not be modified.
+     */
+    public Rect getOverrideBounds() {
+        mReturnBounds.set(getOverrideConfiguration().windowConfiguration.getBounds());
+
+        return mReturnBounds;
+    }
+
+    /**
+     * Sets the passed in {@link Rect} to the current bounds.
+     * @see {@link #getOverrideBounds()}.
+     */
+    public void getOverrideBounds(Rect outBounds) {
+        outBounds.set(getOverrideBounds());
+    }
+
+    /**
+     * Sets the bounds at the current hierarchy level, overriding any bounds set on an ancestor.
+     * This value will be reported when {@link #getBounds()} and {@link #getOverrideBounds()}. If
+     * an empty {@link Rect} or null is specified, this container will be considered to match its
+     * parent bounds {@see #matchParentBounds} and will inherit bounds from its parent.
+     * @param bounds The bounds defining the container size.
+     * @return a bitmask representing the types of changes made to the bounds.
+     */
+    public int setBounds(Rect bounds) {
+        int boundsChange = diffOverrideBounds(bounds);
+
+        if (boundsChange == BOUNDS_CHANGE_NONE) {
+            return boundsChange;
+        }
+
+
+        mTmpConfig.setTo(getOverrideConfiguration());
+        mTmpConfig.windowConfiguration.setBounds(bounds);
+        onOverrideConfigurationChanged(mTmpConfig);
+
+        return boundsChange;
+    }
+
+    public int setBounds(int left, int top, int right, int bottom) {
+        mTmpRect.set(left, top, right, bottom);
+        return setBounds(mTmpRect);
+    }
+
+    int diffOverrideBounds(Rect bounds) {
+        if (equivalentOverrideBounds(bounds)) {
+            return BOUNDS_CHANGE_NONE;
+        }
+
+        int boundsChange = BOUNDS_CHANGE_NONE;
+
+        final Rect existingBounds = getOverrideBounds();
+
+        if (bounds == null || existingBounds.left != bounds.left
+                || existingBounds.top != bounds.top) {
+            boundsChange |= BOUNDS_CHANGE_POSITION;
+        }
+
+        if (bounds == null || existingBounds.width() != bounds.width()
+                || existingBounds.height() != bounds.height()) {
+            boundsChange |= BOUNDS_CHANGE_SIZE;
+        }
+
+        return boundsChange;
+    }
+
     public WindowConfiguration getWindowConfiguration() {
         return mFullConfiguration.windowConfiguration;
     }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 17312b2..56e5922 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -58,10 +58,10 @@
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_UNOCCLUDE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
@@ -146,12 +146,11 @@
 import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
-import android.view.WindowManagerPolicy;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ToBooleanFunction;
 import com.android.internal.view.IInputMethodClient;
-import android.view.DisplayFrames;
+import com.android.server.policy.WindowManagerPolicy;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -182,8 +181,8 @@
     private final TaskStackContainers mTaskStackContainers = new TaskStackContainers();
     // Contains all non-app window containers that should be displayed above the app containers
     // (e.g. Status bar)
-    private final NonAppWindowContainers mAboveAppWindowsContainers =
-            new NonAppWindowContainers("mAboveAppWindowsContainers");
+    private final AboveAppWindowContainers mAboveAppWindowsContainers =
+            new AboveAppWindowContainers("mAboveAppWindowsContainers");
     // Contains all non-app window containers that should be displayed below the app containers
     // (e.g. Wallpaper).
     private final NonAppWindowContainers mBelowAppWindowsContainers =
@@ -315,6 +314,9 @@
     private final Matrix mTmpMatrix = new Matrix();
     private final Region mTmpRegion = new Region();
 
+    /** Used for handing back size of display */
+    private final Rect mTmpBounds = new Rect();
+
     WindowManagerService mService;
 
     /** Remove this display when animation on it has completed. */
@@ -354,7 +356,8 @@
     /**
      * We organize all top-level Surfaces in to the following layers.
      * mOverlayLayer contains a few Surfaces which are always on top of others
-     * and omitted from Screen-Magnification ({@link WindowState#isScreenOverlay})
+     * and omitted from Screen-Magnification, for example the strict mode flash or
+     * the magnification overlay itself.
      * {@link #mWindowingLayer} contains everything else.
      */
     private SurfaceControl mOverlayLayer;
@@ -1224,6 +1227,8 @@
             mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(mDisplayMetrics,
                     mCompatDisplayMetrics);
         }
+
+        updateBounds();
         return mDisplayInfo;
     }
 
@@ -1542,8 +1547,17 @@
         // See {@link PhoneWindowManager#setInitialDisplaySize}...sigh...
         mService.reconfigureDisplayLocked(this);
 
-        getDockedDividerController().onConfigurationChanged();
-        getPinnedStackController().onConfigurationChanged();
+        final DockedStackDividerController dividerController = getDockedDividerController();
+
+        if (dividerController != null) {
+            getDockedDividerController().onConfigurationChanged();
+        }
+
+        final PinnedStackController pinnedStackController = getPinnedStackController();
+
+        if (pinnedStackController != null) {
+            getPinnedStackController().onConfigurationChanged();
+        }
     }
 
     /**
@@ -1682,33 +1696,6 @@
         mInitialDisplayDensity = mDisplayInfo.logicalDensityDpi;
     }
 
-    void getLogicalDisplayRect(Rect out) {
-        // Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked.
-        final int orientation = mDisplayInfo.rotation;
-        boolean rotated = (orientation == ROTATION_90 || orientation == ROTATION_270);
-        final int physWidth = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
-        final int physHeight = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
-        int width = mDisplayInfo.logicalWidth;
-        int left = (physWidth - width) / 2;
-        int height = mDisplayInfo.logicalHeight;
-        int top = (physHeight - height) / 2;
-        out.set(left, top, left + width, top + height);
-    }
-
-    private void getLogicalDisplayRect(Rect out, int orientation) {
-        getLogicalDisplayRect(out);
-
-        // Rotate the Rect if needed.
-        final int currentRotation = mDisplayInfo.rotation;
-        final int rotationDelta = deltaRotation(currentRotation, orientation);
-        if (rotationDelta == ROTATION_90 || rotationDelta == ROTATION_270) {
-            createRotationMatrix(rotationDelta, mBaseDisplayWidth, mBaseDisplayHeight, mTmpMatrix);
-            mTmpRectF.set(out);
-            mTmpMatrix.mapRect(mTmpRectF);
-            mTmpRectF.round(out);
-        }
-    }
-
     /**
      * If display metrics changed, overrides are not set and it's not just a rotation - update base
      * values.
@@ -1776,6 +1763,8 @@
         }
 
         mBaseDisplayRect.set(0, 0, mBaseDisplayWidth, mBaseDisplayHeight);
+
+        updateBounds();
     }
 
     void getContentRect(Rect out) {
@@ -2105,7 +2094,7 @@
     }
 
     void rotateBounds(int oldRotation, int newRotation, Rect bounds) {
-        getLogicalDisplayRect(mTmpRect, newRotation);
+        getBounds(mTmpRect, newRotation);
 
         // Compute a transform matrix to undo the coordinate space transformation,
         // and present the window at the same physical position it previously occupied.
@@ -2882,6 +2871,44 @@
         return mTmpApplySurfaceChangesTransactionState.focusDisplayed;
     }
 
+    private void updateBounds() {
+        calculateBounds(mTmpBounds);
+        setBounds(mTmpBounds);
+    }
+
+    // Determines the current display bounds based on the current state
+    private void calculateBounds(Rect out) {
+        // Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked.
+        final int orientation = mDisplayInfo.rotation;
+        boolean rotated = (orientation == ROTATION_90 || orientation == ROTATION_270);
+        final int physWidth = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
+        final int physHeight = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
+        int width = mDisplayInfo.logicalWidth;
+        int left = (physWidth - width) / 2;
+        int height = mDisplayInfo.logicalHeight;
+        int top = (physHeight - height) / 2;
+        out.set(left, top, left + width, top + height);
+    }
+
+    @Override
+    public void getBounds(Rect out) {
+        calculateBounds(out);
+    }
+
+    private void getBounds(Rect out, int orientation) {
+        getBounds(out);
+
+        // Rotate the Rect if needed.
+        final int currentRotation = mDisplayInfo.rotation;
+        final int rotationDelta = deltaRotation(currentRotation, orientation);
+        if (rotationDelta == ROTATION_90 || rotationDelta == ROTATION_270) {
+            createRotationMatrix(rotationDelta, mBaseDisplayWidth, mBaseDisplayHeight, mTmpMatrix);
+            mTmpRectF.set(out);
+            mTmpMatrix.mapRect(mTmpRectF);
+            mTmpRectF.round(out);
+        }
+    }
+
     void performLayout(boolean initial, boolean updateInputWindows) {
         if (!isLayoutNeeded()) {
             return;
@@ -3720,11 +3747,39 @@
         }
     }
 
+    private final class AboveAppWindowContainers extends NonAppWindowContainers {
+        AboveAppWindowContainers(String name) {
+            super(name);
+        }
+
+        void assignChildLayers(SurfaceControl.Transaction t, WindowContainer imeContainer) {
+            boolean needAssignIme = imeContainer != null
+                    && imeContainer.getSurfaceControl() != null;
+            for (int j = 0; j < mChildren.size(); ++j) {
+                final WindowToken wt = mChildren.get(j);
+                wt.assignLayer(t, j);
+                wt.assignChildLayers(t);
+
+                int layer = mService.mPolicy.getWindowLayerFromTypeLw(
+                        wt.windowType, wt.mOwnerCanManageAppTokens);
+                if (needAssignIme && layer >= TYPE_INPUT_METHOD_DIALOG) {
+                    t.setRelativeLayer(imeContainer.getSurfaceControl(),
+                            wt.getSurfaceControl(), -1);
+                    needAssignIme = false;
+                }
+            }
+            if (needAssignIme) {
+                t.setRelativeLayer(imeContainer.getSurfaceControl(),
+                        getSurfaceControl(), Integer.MIN_VALUE);
+            }
+        }
+    }
+
     /**
      * Window container class that contains all containers on this display that are not related to
      * Apps. E.g. status bar.
      */
-    private final class NonAppWindowContainers extends DisplayChildWindowContainer<WindowToken> {
+    private class NonAppWindowContainers extends DisplayChildWindowContainer<WindowToken> {
         /**
          * Compares two child window tokens returns -1 if the first is lesser than the second in
          * terms of z-order and 1 otherwise.
@@ -3822,12 +3877,8 @@
             return b;
         }
 
-        b.setName(child.getName());
-        if (child.isScreenOverlay()) {
-            return b.setParent(mOverlayLayer);
-        } else {
-            return b.setParent(mWindowingLayer);
-        }
+        return b.setName(child.getName())
+                .setParent(mWindowingLayer);
     }
 
     /**
@@ -3865,26 +3916,36 @@
         mAboveAppWindowsContainers.assignLayer(t, 2);
 
         WindowState imeTarget = mService.mInputMethodTarget;
-        if (imeTarget == null || imeTarget.inSplitScreenWindowingMode()) {
-            // In split-screen windowing mode we can't layer the
-            // IME relative to the IME target because it needs to
-            // go over the docked divider, so instead we place it on top
-            // of everything and use relative layering of windows which need
-            // to go above it (see special logic in WindowState#assignLayer)
-            mImeWindowsContainers.assignLayer(t, 3);
-        } else {
+        boolean needAssignIme = true;
+
+        // In the case where we have an IME target that is not in split-screen
+        // mode IME assignment is easy. We just need the IME to go directly above
+        // the target. This way children of the target will naturally go above the IME
+        // and everyone is happy.
+        //
+        // In the case of split-screen windowing mode, we need to elevate the IME above the
+        // docked divider while keeping the app itself below the docked divider, so instead
+        // we use relative layering of the IME targets child windows, and place the
+        // IME in the non-app layer (see {@link AboveAppWindowContainers#assignChildLayers}).
+        //
+        // In the case where we have no IME target we assign it where it's base layer would
+        // place it in the AboveAppWindowContainers.
+        if (imeTarget != null && !imeTarget.inSplitScreenWindowingMode()
+                && (imeTarget.getSurfaceControl() != null)) {
             t.setRelativeLayer(mImeWindowsContainers.getSurfaceControl(),
                     imeTarget.getSurfaceControl(),
                     // TODO: We need to use an extra level on the app surface to ensure
                     // this is always above SurfaceView but always below attached window.
                     1);
+            needAssignIme = false;
         }
 
         // Above we have assigned layers to our children, now we ask them to assign
         // layers to their children.
         mBelowAppWindowsContainers.assignChildLayers(t);
         mTaskStackContainers.assignChildLayers(t);
-        mAboveAppWindowsContainers.assignChildLayers(t);
+        mAboveAppWindowsContainers.assignChildLayers(t,
+                needAssignIme == true ? mImeWindowsContainers : null);
         mImeWindowsContainers.assignChildLayers(t);
     }
 
diff --git a/core/java/android/view/DisplayFrames.java b/services/core/java/com/android/server/wm/DisplayFrames.java
similarity index 98%
rename from core/java/android/view/DisplayFrames.java
rename to services/core/java/com/android/server/wm/DisplayFrames.java
index e6861d8..0249713 100644
--- a/core/java/android/view/DisplayFrames.java
+++ b/services/core/java/com/android/server/wm/DisplayFrames.java
@@ -11,10 +11,10 @@
  * 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
+ * limitations under the License.
  */
 
-package android.view;
+package com.android.server.wm;
 
 import static android.view.Surface.ROTATION_180;
 import static android.view.Surface.ROTATION_270;
@@ -23,6 +23,7 @@
 
 import android.graphics.Rect;
 import android.util.proto.ProtoOutputStream;
+import android.view.DisplayInfo;
 
 import java.io.PrintWriter;
 
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 8308417..a37598e 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -655,8 +655,8 @@
     }
 
     private boolean isWithinDisplay(Task task) {
-        task.mStack.getBounds(mTmpRect);
-        mDisplayContent.getLogicalDisplayRect(mTmpRect2);
+        task.getBounds(mTmpRect);
+        mDisplayContent.getBounds(mTmpRect2);
         return mTmpRect.intersect(mTmpRect2);
     }
 
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index 4567e10..65951dc 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -36,9 +36,10 @@
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 import android.view.View;
-import android.view.WindowManagerInternal.IDragDropCallback;
+
 import com.android.internal.util.Preconditions;
 import com.android.server.input.InputWindowHandle;
+import com.android.server.wm.WindowManagerInternal.IDragDropCallback;
 
 /**
  * Managing drag and drop operations initiated by View#startDragAndDrop.
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index e81d366..112e62f 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -645,15 +645,15 @@
             try (final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction()) {
                 transaction.setPosition(
                         mSurfaceControl,
-                        (float) mAnimator.getAnimatedValue(ANIMATED_PROPERTY_X),
-                        (float) mAnimator.getAnimatedValue(ANIMATED_PROPERTY_Y));
+                        (float) animation.getAnimatedValue(ANIMATED_PROPERTY_X),
+                        (float) animation.getAnimatedValue(ANIMATED_PROPERTY_Y));
                 transaction.setAlpha(
                         mSurfaceControl,
-                        (float) mAnimator.getAnimatedValue(ANIMATED_PROPERTY_ALPHA));
+                        (float) animation.getAnimatedValue(ANIMATED_PROPERTY_ALPHA));
                 transaction.setMatrix(
                         mSurfaceControl,
-                        (float) mAnimator.getAnimatedValue(ANIMATED_PROPERTY_SCALE), 0,
-                        0, (float) mAnimator.getAnimatedValue(ANIMATED_PROPERTY_SCALE));
+                        (float) animation.getAnimatedValue(ANIMATED_PROPERTY_SCALE), 0,
+                        0, (float) animation.getAnimatedValue(ANIMATED_PROPERTY_SCALE));
                 transaction.apply();
             }
         }
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index a766097..7e29a3a 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -47,11 +47,11 @@
 import android.view.InputEventReceiver;
 import android.view.KeyEvent;
 import android.view.WindowManager;
-import android.view.WindowManagerPolicy;
 
 import com.android.server.input.InputApplicationHandle;
 import com.android.server.input.InputManagerService;
 import com.android.server.input.InputWindowHandle;
+import com.android.server.policy.WindowManagerPolicy;
 
 import java.io.PrintWriter;
 import java.util.Arrays;
@@ -661,8 +661,8 @@
             if (w.inPinnedWindowingMode()) {
                 if (mAddPipInputConsumerHandle
                         && (inputWindowHandle.layer <= pipInputConsumer.mWindowHandle.layer)) {
-                    // Update the bounds of the Pip input consumer to match the Pinned stack
-                    w.getStack().getBounds(pipTouchableBounds);
+                    // Update the bounds of the Pip input consumer to match the window bounds.
+                    w.getBounds(pipTouchableBounds);
                     pipInputConsumer.mWindowHandle.touchableRegion.set(pipTouchableBounds);
                     addInputWindowHandle(pipInputConsumer.mWindowHandle);
                     mAddPipInputConsumerHandle = false;
diff --git a/services/core/java/com/android/server/wm/KeyguardDisableHandler.java b/services/core/java/com/android/server/wm/KeyguardDisableHandler.java
index 2eb186b..4a20f1a 100644
--- a/services/core/java/com/android/server/wm/KeyguardDisableHandler.java
+++ b/services/core/java/com/android/server/wm/KeyguardDisableHandler.java
@@ -29,7 +29,8 @@
 import android.os.TokenWatcher;
 import android.util.Log;
 import android.util.Pair;
-import android.view.WindowManagerPolicy;
+
+import com.android.server.policy.WindowManagerPolicy;
 
 public class KeyguardDisableHandler extends Handler {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "KeyguardDisableHandler" : TAG_WM;
diff --git a/services/core/java/com/android/server/wm/PinnedStackWindowController.java b/services/core/java/com/android/server/wm/PinnedStackWindowController.java
index 41f076d..b021a72 100644
--- a/services/core/java/com/android/server/wm/PinnedStackWindowController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackWindowController.java
@@ -106,7 +106,7 @@
                 } else {
                     // Otherwise, use the display bounds
                     toBounds = new Rect();
-                    mContainer.getDisplayContent().getLogicalDisplayRect(toBounds);
+                    mContainer.getDisplayContent().getBounds(toBounds);
                 }
             } else if (fromFullscreen) {
                 schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_END;
diff --git a/services/core/java/com/android/server/wm/PointerEventDispatcher.java b/services/core/java/com/android/server/wm/PointerEventDispatcher.java
index 484987e..ab8b8d4 100644
--- a/services/core/java/com/android/server/wm/PointerEventDispatcher.java
+++ b/services/core/java/com/android/server/wm/PointerEventDispatcher.java
@@ -21,7 +21,7 @@
 import android.view.InputEvent;
 import android.view.InputEventReceiver;
 import android.view.MotionEvent;
-import android.view.WindowManagerPolicy.PointerEventListener;
+import android.view.WindowManagerPolicyConstants.PointerEventListener;
 
 import com.android.server.UiThread;
 
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 43dfccc..4008811 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -59,10 +59,10 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE;
 import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
 import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEEP_SCREEN_ON;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 70bf15c..5a39de5 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -28,7 +28,6 @@
 
 import android.content.Context;
 import android.graphics.Matrix;
-import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
@@ -230,7 +229,7 @@
         mService = service;
         mContext = context;
         mDisplayContent = displayContent;
-        displayContent.getLogicalDisplayRect(mOriginalDisplayRect);
+        displayContent.getBounds(mOriginalDisplayRect);
 
         // Screenshot does NOT include rotation!
         final Display display = displayContent.getDisplay();
@@ -312,7 +311,7 @@
             float x = mTmpFloats[Matrix.MTRANS_X];
             float y = mTmpFloats[Matrix.MTRANS_Y];
             if (mForceDefaultOrientation) {
-                mDisplayContent.getLogicalDisplayRect(mCurrentDisplayRect);
+                mDisplayContent.getBounds(mCurrentDisplayRect);
                 x -= mCurrentDisplayRect.left;
                 y -= mCurrentDisplayRect.top;
             }
diff --git a/services/core/java/com/android/server/wm/SnapshotStartingData.java b/services/core/java/com/android/server/wm/SnapshotStartingData.java
index 35f35db..c9e43c5 100644
--- a/services/core/java/com/android/server/wm/SnapshotStartingData.java
+++ b/services/core/java/com/android/server/wm/SnapshotStartingData.java
@@ -17,8 +17,8 @@
 package com.android.server.wm;
 
 import android.app.ActivityManager.TaskSnapshot;
-import android.graphics.GraphicBuffer;
-import android.view.WindowManagerPolicy.StartingSurface;
+
+import com.android.server.policy.WindowManagerPolicy.StartingSurface;
 
 /**
  * Represents starting data for snapshot starting windows.
diff --git a/services/core/java/com/android/server/wm/SplashScreenStartingData.java b/services/core/java/com/android/server/wm/SplashScreenStartingData.java
index 4b14f86..f52ce38 100644
--- a/services/core/java/com/android/server/wm/SplashScreenStartingData.java
+++ b/services/core/java/com/android/server/wm/SplashScreenStartingData.java
@@ -18,7 +18,8 @@
 
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
-import android.view.WindowManagerPolicy.StartingSurface;
+
+import com.android.server.policy.WindowManagerPolicy.StartingSurface;
 
 /**
  * Represents starting data for splash screens, i.e. "traditional" starting windows.
diff --git a/services/core/java/com/android/server/wm/StackWindowController.java b/services/core/java/com/android/server/wm/StackWindowController.java
index 95c1d53..c2a4be5 100644
--- a/services/core/java/com/android/server/wm/StackWindowController.java
+++ b/services/core/java/com/android/server/wm/StackWindowController.java
@@ -111,8 +111,7 @@
         }
     }
 
-    public void positionChildAt(TaskWindowContainerController child, int position, Rect bounds,
-            Configuration overrideConfig) {
+    public void positionChildAt(TaskWindowContainerController child, int position) {
         synchronized (mWindowMap) {
             if (DEBUG_STACK) Slog.i(TAG_WM, "positionChildAt: positioning task=" + child
                     + " at " + position);
@@ -126,7 +125,7 @@
                         "positionChildAt: could not find stack for task=" + mContainer);
                 return;
             }
-            child.mContainer.positionAt(position, bounds, overrideConfig);
+            child.mContainer.positionAt(position);
             mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
         }
     }
@@ -178,24 +177,22 @@
      * Re-sizes a stack and its containing tasks.
      *
      * @param bounds New stack bounds. Passing in null sets the bounds to fullscreen.
-     * @param configs Configurations for tasks in the resized stack, keyed by task id.
      * @param taskBounds Bounds for tasks in the resized stack, keyed by task id.
-     * @return True if the stack is now fullscreen.
+     * @param taskTempInsetBounds Inset bounds for individual tasks, keyed by task id.
      */
-    public boolean resize(Rect bounds, SparseArray<Configuration> configs,
-            SparseArray<Rect> taskBounds, SparseArray<Rect> taskTempInsetBounds) {
+    public void resize(Rect bounds, SparseArray<Rect> taskBounds,
+            SparseArray<Rect> taskTempInsetBounds) {
         synchronized (mWindowMap) {
             if (mContainer == null) {
                 throw new IllegalArgumentException("resizeStack: stack " + this + " not found.");
             }
             // We might trigger a configuration change. Save the current task bounds for freezing.
             mContainer.prepareFreezingTaskBounds();
-            if (mContainer.setBounds(bounds, configs, taskBounds, taskTempInsetBounds)
+            if (mContainer.setBounds(bounds, taskBounds, taskTempInsetBounds)
                     && mContainer.isVisible()) {
                 mContainer.getDisplayContent().setLayoutNeeded();
                 mService.mWindowPlacerLocked.performSurfacePlacement();
             }
-            return mContainer.getRawFullscreen();
         }
     }
 
@@ -227,7 +224,7 @@
 
     public void getRawBounds(Rect outBounds) {
         synchronized (mWindowMap) {
-            if (mContainer.getRawFullscreen()) {
+            if (mContainer.matchParentBounds()) {
                 outBounds.setEmpty();
             } else {
                 mContainer.getRawBounds(outBounds);
@@ -275,6 +272,7 @@
 
             final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds();
 
+            config.windowConfiguration.setBounds(bounds);
             config.windowConfiguration.setAppBounds(!bounds.isEmpty() ? bounds : null);
             boolean intersectParentBounds = false;
 
diff --git a/services/core/java/com/android/server/wm/StartingData.java b/services/core/java/com/android/server/wm/StartingData.java
index 8c564bb..eb5011f 100644
--- a/services/core/java/com/android/server/wm/StartingData.java
+++ b/services/core/java/com/android/server/wm/StartingData.java
@@ -16,7 +16,7 @@
 
 package com.android.server.wm;
 
-import android.view.WindowManagerPolicy.StartingSurface;
+import com.android.server.policy.WindowManagerPolicy.StartingSurface;
 
 /**
  * Represents the model about how a starting window should be constructed.
diff --git a/services/core/java/com/android/server/wm/SurfaceControlWithBackground.java b/services/core/java/com/android/server/wm/SurfaceControlWithBackground.java
index a5080d5..7c5bd43 100644
--- a/services/core/java/com/android/server/wm/SurfaceControlWithBackground.java
+++ b/services/core/java/com/android/server/wm/SurfaceControlWithBackground.java
@@ -16,7 +16,13 @@
 
 package com.android.server.wm;
 
-import android.graphics.PixelFormat;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+
+import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
+import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_LEFT;
+import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_RIGHT;
+
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.IBinder;
@@ -24,13 +30,6 @@
 import android.view.Surface;
 import android.view.Surface.OutOfResourcesException;
 import android.view.SurfaceControl;
-import android.view.SurfaceSession;
-
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManagerPolicy.NAV_BAR_BOTTOM;
-import static android.view.WindowManagerPolicy.NAV_BAR_LEFT;
-import static android.view.WindowManagerPolicy.NAV_BAR_RIGHT;
 
 /**
  * SurfaceControl extension that has black background behind navigation bar area for fullscreen
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index f70845e..8aa129a 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -53,12 +53,6 @@
 
 class Task extends WindowContainer<AppWindowToken> {
     static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_WM;
-    // Return value from {@link setBounds} indicating no change was made to the Task bounds.
-    private static final int BOUNDS_CHANGE_NONE = 0;
-    // Return value from {@link setBounds} indicating the position of the Task bounds changed.
-    private static final int BOUNDS_CHANGE_POSITION = 1;
-    // Return value from {@link setBounds} indicating the size of the Task bounds changed.
-    private static final int BOUNDS_CHANGE_SIZE = 1 << 1;
 
     // TODO: Track parent marks like this in WindowContainer.
     TaskStack mStack;
@@ -67,8 +61,6 @@
     private boolean mDeferRemoval = false;
     final WindowManagerService mService;
 
-    // Content limits relative to the DisplayContent this sits in.
-    private Rect mBounds = new Rect();
     final Rect mPreparedFrozenBounds = new Rect();
     final Configuration mPreparedFrozenMergedConfig = new Configuration();
 
@@ -78,13 +70,12 @@
     // Device rotation as of the last time {@link #mBounds} was set.
     private int mRotation;
 
-    // Whether mBounds is fullscreen
-    private boolean mFillsParent = true;
-
     // For comparison with DisplayContent bounds.
     private Rect mTmpRect = new Rect();
     // For handling display rotations.
     private Rect mTmpRect2 = new Rect();
+    // For retrieving dim bounds
+    private Rect mTmpRect3 = new Rect();
 
     // Resize mode of the task. See {@link ActivityInfo#resizeMode}
     private int mResizeMode;
@@ -108,8 +99,8 @@
     private Dimmer mDimmer = new Dimmer(this);
     private final Rect mTmpDimBoundsRect = new Rect();
 
-    Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
-            int resizeMode, boolean supportsPictureInPicture, TaskDescription taskDescription,
+    Task(int taskId, TaskStack stack, int userId, WindowManagerService service, int resizeMode,
+            boolean supportsPictureInPicture, TaskDescription taskDescription,
             TaskWindowContainerController controller) {
         mTaskId = taskId;
         mStack = stack;
@@ -118,7 +109,7 @@
         mResizeMode = resizeMode;
         mSupportsPictureInPicture = supportsPictureInPicture;
         setController(controller);
-        setBounds(bounds, getOverrideConfiguration());
+        setBounds(getOverrideBounds());
         mTaskDescription = taskDescription;
 
         // Tasks have no set orientation value (including SCREEN_ORIENTATION_UNSPECIFIED).
@@ -227,9 +218,8 @@
     }
 
     /** @see com.android.server.am.ActivityManagerService#positionTaskInStack(int, int, int). */
-    void positionAt(int position, Rect bounds, Configuration overrideConfig) {
+    void positionAt(int position) {
         mStack.positionChildAt(position, this, false /* includingParents */);
-        resizeLocked(bounds, overrideConfig, false /* force */);
     }
 
     @Override
@@ -271,48 +261,37 @@
         }
     }
 
-    /** Set the task bounds. Passing in null sets the bounds to fullscreen. */
-    // TODO: There is probably not a need to pass in overrideConfig anymore since any change to it
-    // will be automatically propagated from the AM. Also, mBound is going to be in
-    // WindowConfiguration long term.
-    private int setBounds(Rect bounds, Configuration overrideConfig) {
-        if (overrideConfig == null) {
-            overrideConfig = EMPTY;
+    public int setBounds(Rect bounds, boolean forceResize) {
+        final int boundsChanged = setBounds(bounds);
+
+        if (forceResize && (boundsChanged & BOUNDS_CHANGE_SIZE) != BOUNDS_CHANGE_SIZE) {
+            onResize();
+            return BOUNDS_CHANGE_SIZE | boundsChanged;
         }
 
-        boolean oldFullscreen = mFillsParent;
+        return boundsChanged;
+    }
+
+    /** Set the task bounds. Passing in null sets the bounds to fullscreen. */
+    @Override
+    public int setBounds(Rect bounds) {
         int rotation = Surface.ROTATION_0;
         final DisplayContent displayContent = mStack.getDisplayContent();
         if (displayContent != null) {
-            displayContent.getLogicalDisplayRect(mTmpRect);
             rotation = displayContent.getDisplayInfo().rotation;
-            mFillsParent = bounds == null;
-            if (mFillsParent) {
-                bounds = mTmpRect;
-            }
-        }
-
-        if (bounds == null) {
+        } else if (bounds == null) {
             // Can't set to fullscreen if we don't have a display to get bounds from...
             return BOUNDS_CHANGE_NONE;
         }
-        if (mBounds.equals(bounds) && oldFullscreen == mFillsParent && mRotation == rotation) {
+
+        if (equivalentOverrideBounds(bounds)) {
             return BOUNDS_CHANGE_NONE;
         }
 
-        int boundsChange = BOUNDS_CHANGE_NONE;
-        if (mBounds.left != bounds.left || mBounds.top != bounds.top) {
-            boundsChange |= BOUNDS_CHANGE_POSITION;
-        }
-        if (mBounds.width() != bounds.width() || mBounds.height() != bounds.height()) {
-            boundsChange |= BOUNDS_CHANGE_SIZE;
-        }
-
-        mBounds.set(bounds);
+        final int boundsChange = super.setBounds(bounds);
 
         mRotation = rotation;
 
-        onOverrideConfigurationChanged(overrideConfig);
         return boundsChange;
     }
 
@@ -360,28 +339,12 @@
         return isResizeable();
     }
 
-    boolean resizeLocked(Rect bounds, Configuration overrideConfig, boolean forced) {
-        int boundsChanged = setBounds(bounds, overrideConfig);
-        if (forced) {
-            boundsChanged |= BOUNDS_CHANGE_SIZE;
-        }
-        if (boundsChanged == BOUNDS_CHANGE_NONE) {
-            return false;
-        }
-        if ((boundsChanged & BOUNDS_CHANGE_SIZE) == BOUNDS_CHANGE_SIZE) {
-            onResize();
-        } else {
-            onMovedByResize();
-        }
-        return true;
-    }
-
     /**
      * Prepares the task bounds to be frozen with the current size. See
      * {@link AppWindowToken#freezeBounds}.
      */
     void prepareFreezingBounds() {
-        mPreparedFrozenBounds.set(mBounds);
+        mPreparedFrozenBounds.set(getBounds());
         mPreparedFrozenMergedConfig.setTo(getConfiguration());
     }
 
@@ -407,30 +370,30 @@
             mTmpRect2.offsetTo(adjustedBounds.left, adjustedBounds.top);
         }
         setTempInsetBounds(tempInsetBounds);
-        resizeLocked(mTmpRect2, getOverrideConfiguration(), false /* forced */);
+        setBounds(mTmpRect2, false /* forced */);
     }
 
     /** Return true if the current bound can get outputted to the rest of the system as-is. */
     private boolean useCurrentBounds() {
         final DisplayContent displayContent = getDisplayContent();
-        return mFillsParent
+        return matchParentBounds()
                 || !inSplitScreenSecondaryWindowingMode()
                 || displayContent == null
                 || displayContent.getSplitScreenPrimaryStackIgnoringVisibility() != null;
     }
 
-    /** Original bounds of the task if applicable, otherwise fullscreen rect. */
-    void getBounds(Rect out) {
+    @Override
+    public void getBounds(Rect out) {
         if (useCurrentBounds()) {
             // No need to adjust the output bounds if fullscreen or the docked stack is visible
             // since it is already what we want to represent to the rest of the system.
-            out.set(mBounds);
+            super.getBounds(out);
             return;
         }
 
         // The bounds has been adjusted to accommodate for a docked stack, but the docked stack is
         // not currently visible. Go ahead a represent it as fullscreen to the rest of the system.
-        mStack.getDisplayContent().getLogicalDisplayRect(out);
+        mStack.getDisplayContent().getBounds(out);
     }
 
     /**
@@ -490,7 +453,7 @@
                 return;
             }
 
-            if (!mFillsParent) {
+            if (!matchParentBounds()) {
                 // When minimizing the docked stack when going home, we don't adjust the task bounds
                 // so we need to intersect the task bounds with the stack bounds here.
                 //
@@ -501,11 +464,11 @@
                     mStack.getBounds(out);
                 } else {
                     mStack.getBounds(mTmpRect);
-                    mTmpRect.intersect(mBounds);
+                    mTmpRect.intersect(getBounds());
                 }
                 out.set(mTmpRect);
             } else {
-                out.set(mBounds);
+                out.set(getBounds());
             }
             return;
         }
@@ -513,7 +476,7 @@
         // The bounds has been adjusted to accommodate for a docked stack, but the docked stack is
         // not currently visible. Go ahead a represent it as fullscreen to the rest of the system.
         if (displayContent != null) {
-            displayContent.getLogicalDisplayRect(out);
+            displayContent.getBounds(out);
         }
     }
 
@@ -541,10 +504,10 @@
         if (displayContent == null) {
             return;
         }
-        if (mFillsParent) {
+        if (matchParentBounds()) {
             // TODO: Yeah...not sure if this works with WindowConfiguration, but shouldn't be a
             // problem once we move mBounds into WindowConfiguration.
-            setBounds(null, getOverrideConfiguration());
+            setBounds(null);
             return;
         }
         final int newRotation = displayContent.getDisplayInfo().rotation;
@@ -557,18 +520,18 @@
         //   task bounds so it stays in the same place.
         // - Rotate the bounds and notify activity manager if the task can be resized independently
         //   from its stack. The stack will take care of task rotation for the other case.
-        mTmpRect2.set(mBounds);
+        mTmpRect2.set(getBounds());
 
         if (!getWindowConfiguration().canResizeTask()) {
-            setBounds(mTmpRect2, getOverrideConfiguration());
+            setBounds(mTmpRect2);
             return;
         }
 
         displayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
-        if (setBounds(mTmpRect2, getOverrideConfiguration()) != BOUNDS_CHANGE_NONE) {
+        if (setBounds(mTmpRect2) != BOUNDS_CHANGE_NONE) {
             final TaskWindowContainerController controller = getController();
             if (controller != null) {
-                controller.requestResize(mBounds, RESIZE_MODE_SYSTEM_SCREEN_ROTATION);
+                controller.requestResize(getBounds(), RESIZE_MODE_SYSTEM_SCREEN_ROTATION);
             }
         }
     }
@@ -632,7 +595,7 @@
 
     boolean isFullscreen() {
         if (useCurrentBounds()) {
-            return mFillsParent;
+            return matchParentBounds();
         }
         // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
         // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
@@ -661,7 +624,7 @@
 
     @Override
     boolean fillsParent() {
-        return mFillsParent || !getWindowConfiguration().canResizeTask();
+        return matchParentBounds() || !getWindowConfiguration().canResizeTask();
     }
 
     @Override
@@ -711,8 +674,8 @@
             final AppWindowToken appWindowToken = mChildren.get(i);
             appWindowToken.writeToProto(proto, APP_WINDOW_TOKENS, trim);
         }
-        proto.write(FILLS_PARENT, mFillsParent);
-        mBounds.writeToProto(proto, BOUNDS);
+        proto.write(FILLS_PARENT, matchParentBounds());
+        getBounds().writeToProto(proto, BOUNDS);
         mTempInsetBounds.writeToProto(proto, TEMP_INSET_BOUNDS);
         proto.end(token);
     }
@@ -721,8 +684,7 @@
         final String doublePrefix = prefix + "  ";
 
         pw.println(prefix + "taskId=" + mTaskId);
-        pw.println(doublePrefix + "mFillsParent=" + mFillsParent);
-        pw.println(doublePrefix + "mBounds=" + mBounds.toShortString());
+        pw.println(doublePrefix + "mBounds=" + getBounds().toShortString());
         pw.println(doublePrefix + "mdr=" + mDeferRemoval);
         pw.println(doublePrefix + "appTokens=" + mChildren);
         pw.println(doublePrefix + "mTempInsetBounds=" + mTempInsetBounds.toShortString());
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 5d4ba09..87d0a40 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -382,6 +382,27 @@
         mStartOrientationWasLandscape = startBounds.width() >= startBounds.height();
         mWindowOriginalBounds.set(startBounds);
 
+        // Notify the app that resizing has started, even though we haven't received any new
+        // bounds yet. This will guarantee that the app starts the backdrop renderer before
+        // configuration changes which could cause an activity restart.
+        if (mResizing) {
+            synchronized (mService.mWindowMap) {
+                notifyMoveLocked(startX, startY);
+            }
+
+            // Perform the resize on the WMS handler thread when we don't have the WMS lock held
+            // to ensure that we don't deadlock WMS and AMS. Note that WindowPositionerEventReceiver
+            // callbacks are delivered on the same handler so this initial resize is always
+            // guaranteed to happen before subsequent drag resizes.
+            mService.mH.post(() -> {
+                try {
+                    mService.mActivityManager.resizeTask(
+                            mTask.mTaskId, startBounds, RESIZE_MODE_USER_FORCED);
+                } catch (RemoteException e) {
+                }
+            });
+        }
+
         // Make sure we always have valid drag bounds even if the drag ends before any move events
         // have been handled.
         mWindowDragBounds.set(startBounds);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 54ef065..e644417 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -37,14 +37,14 @@
 import android.view.RenderNode;
 import android.view.ThreadedRenderer;
 import android.view.WindowManager.LayoutParams;
-import android.view.WindowManagerPolicy.ScreenOffListener;
-import android.view.WindowManagerPolicy.StartingSurface;
-
-import com.google.android.collect.Sets;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.policy.WindowManagerPolicy.ScreenOffListener;
+import com.android.server.policy.WindowManagerPolicy.StartingSurface;
 import com.android.server.wm.TaskSnapshotSurface.SystemBarBackgroundPainter;
 
+import com.google.android.collect.Sets;
+
 import java.io.PrintWriter;
 
 /**
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index 3ce090a..41915a3 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -18,9 +18,7 @@
 
 import static android.graphics.Color.WHITE;
 import static android.graphics.Color.alpha;
-import static android.view.SurfaceControl.HIDDEN;
 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
 import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
 import static android.view.WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
 import static android.view.WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE;
@@ -67,12 +65,12 @@
 import android.view.ViewGroup.LayoutParams;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
-import android.view.WindowManagerPolicy.StartingSurface;
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.policy.DecorView;
 import com.android.internal.view.BaseIWindow;
+import com.android.server.policy.WindowManagerPolicy.StartingSurface;
 
 /**
  * This class represents a starting window that shows a snapshot.
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 9186cf3..4a3a3fc 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -31,12 +31,11 @@
 import static android.view.WindowManager.DOCKED_LEFT;
 import static android.view.WindowManager.DOCKED_RIGHT;
 import static android.view.WindowManager.DOCKED_TOP;
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.WindowManagerService.LAYER_OFFSET_DIM;
 import static com.android.server.wm.proto.StackProto.ANIMATION_BACKGROUND_SURFACE_IS_DIMMING;
 import static com.android.server.wm.proto.StackProto.BOUNDS;
 import static com.android.server.wm.proto.StackProto.FILLS_PARENT;
@@ -88,9 +87,6 @@
     private Rect mTmpRect2 = new Rect();
     private Rect mTmpRect3 = new Rect();
 
-    /** Content limits relative to the DisplayContent this sits in. */
-    private Rect mBounds = new Rect();
-
     /** Stack bounds adjusted to screen content area (taking into account IM windows, etc.) */
     private final Rect mAdjustedBounds = new Rect();
 
@@ -100,9 +96,6 @@
      */
     private final Rect mFullyAdjustedImeBounds = new Rect();
 
-    /** Whether mBounds is fullscreen */
-    private boolean mFillsParent = true;
-
     // Device rotation as of the last time {@link #mBounds} was set.
     private int mRotation;
 
@@ -180,27 +173,20 @@
     /**
      * Set the bounds of the stack and its containing tasks.
      * @param stackBounds New stack bounds. Passing in null sets the bounds to fullscreen.
-     * @param configs Configuration for individual tasks, keyed by task id.
      * @param taskBounds Bounds for individual tasks, keyed by task id.
+     * @param taskTempInsetBounds Inset bounds for individual tasks, keyed by task id.
      * @return True if the stack bounds was changed.
      * */
     boolean setBounds(
-            Rect stackBounds, SparseArray<Configuration> configs, SparseArray<Rect> taskBounds,
-            SparseArray<Rect> taskTempInsetBounds) {
+            Rect stackBounds, SparseArray<Rect> taskBounds, SparseArray<Rect> taskTempInsetBounds) {
         setBounds(stackBounds);
 
         // Update bounds of containing tasks.
         for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; --taskNdx) {
             final Task task = mChildren.get(taskNdx);
-            Configuration config = configs.get(task.mTaskId);
-            if (config != null) {
-                Rect bounds = taskBounds.get(task.mTaskId);
-                task.resizeLocked(bounds, config, false /* forced */);
-                task.setTempInsetBounds(taskTempInsetBounds != null ?
-                        taskTempInsetBounds.get(task.mTaskId) : null);
-            } else {
-                Slog.wtf(TAG_WM, "No config for task: " + task + ", is there a mismatch with AM?");
-            }
+            task.setBounds(taskBounds.get(task.mTaskId), false /* forced */);
+            task.setTempInsetBounds(taskTempInsetBounds != null ?
+                    taskTempInsetBounds.get(task.mTaskId) : null);
         }
         return true;
     }
@@ -227,20 +213,20 @@
         final boolean adjusted = !mAdjustedBounds.isEmpty();
         Rect insetBounds = null;
         if (adjusted && isAdjustedForMinimizedDockedStack()) {
-            insetBounds = mBounds;
+            insetBounds = getRawBounds();
         } else if (adjusted && mAdjustedForIme) {
             if (mImeGoingAway) {
-                insetBounds = mBounds;
+                insetBounds = getRawBounds();
             } else {
                 insetBounds = mFullyAdjustedImeBounds;
             }
         }
-        alignTasksToAdjustedBounds(adjusted ? mAdjustedBounds : mBounds, insetBounds);
+        alignTasksToAdjustedBounds(adjusted ? mAdjustedBounds : getRawBounds(), insetBounds);
         mDisplayContent.setLayoutNeeded();
     }
 
     private void alignTasksToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds) {
-        if (mFillsParent) {
+        if (matchParentBounds()) {
             return;
         }
 
@@ -253,13 +239,15 @@
         }
     }
 
-    private void setAnimationBackgroundBounds(Rect bounds) {
+    private void updateAnimationBackgroundBounds() {
         if (mAnimationBackgroundSurface == null) {
             return;
         }
+        getRawBounds(mTmpRect);
         // TODO: Should be in relative coordinates.
-        getPendingTransaction().setSize(mAnimationBackgroundSurface, bounds.width(), bounds.height())
-                .setPosition(mAnimationBackgroundSurface, bounds.left, bounds.top);
+        getPendingTransaction().setSize(mAnimationBackgroundSurface, mTmpRect.width(),
+                mTmpRect.height()).setPosition(mAnimationBackgroundSurface, mTmpRect.left,
+                mTmpRect.top);
         scheduleAnimation();
     }
 
@@ -283,50 +271,53 @@
         scheduleAnimation();
     }
 
-    private boolean setBounds(Rect bounds) {
-        boolean oldFullscreen = mFillsParent;
+    @Override
+    public int setBounds(Rect bounds) {
+        return setBounds(getOverrideBounds(), bounds);
+    }
+
+    private int setBounds(Rect existing, Rect bounds) {
         int rotation = Surface.ROTATION_0;
         int density = DENSITY_DPI_UNDEFINED;
         if (mDisplayContent != null) {
-            mDisplayContent.getLogicalDisplayRect(mTmpRect);
+            mDisplayContent.getBounds(mTmpRect);
             rotation = mDisplayContent.getDisplayInfo().rotation;
             density = mDisplayContent.getDisplayInfo().logicalDensityDpi;
-            mFillsParent = bounds == null;
-            if (mFillsParent) {
-                bounds = mTmpRect;
-            }
         }
 
-        if (bounds == null) {
-            // Can't set to fullscreen if we don't have a display to get bounds from...
-            return false;
-        }
-        if (mBounds.equals(bounds) && oldFullscreen == mFillsParent && mRotation == rotation) {
-            return false;
+        if (equivalentBounds(existing, bounds) && mRotation == rotation) {
+            return BOUNDS_CHANGE_NONE;
         }
 
-        setAnimationBackgroundBounds(bounds);
+        final int result = super.setBounds(bounds);
 
-        mBounds.set(bounds);
+        if (mDisplayContent != null) {
+            updateAnimationBackgroundBounds();
+        }
+
         mRotation = rotation;
         mDensity = density;
 
         updateAdjustedBounds();
 
-        return true;
+        return result;
     }
 
     /** Bounds of the stack without adjusting for other factors in the system like visibility
      * of docked stack.
-     * Most callers should be using {@link #getBounds} as it take into consideration other system
-     * factors. */
+     * Most callers should be using {@link ConfigurationContainer#getOverrideBounds} as it take into
+     * consideration other system factors. */
     void getRawBounds(Rect out) {
-        out.set(mBounds);
+        out.set(getRawBounds());
+    }
+
+    Rect getRawBounds() {
+        return super.getBounds();
     }
 
     /** Return true if the current bound can get outputted to the rest of the system as-is. */
     private boolean useCurrentBounds() {
-        if (mFillsParent
+        if (matchParentBounds()
                 || !inSplitScreenSecondaryWindowingMode()
                 || mDisplayContent == null
                 || mDisplayContent.getSplitScreenPrimaryStack() != null) {
@@ -335,24 +326,29 @@
         return false;
     }
 
-    public void getBounds(Rect out) {
+    @Override
+    public void getBounds(Rect bounds) {
+        bounds.set(getBounds());
+    }
+
+    @Override
+    public Rect getBounds() {
         if (useCurrentBounds()) {
             // If we're currently adjusting for IME or minimized docked stack, we use the adjusted
             // bounds; otherwise, no need to adjust the output bounds if fullscreen or the docked
             // stack is visible since it is already what we want to represent to the rest of the
             // system.
             if (!mAdjustedBounds.isEmpty()) {
-                out.set(mAdjustedBounds);
+                return mAdjustedBounds;
             } else {
-                out.set(mBounds);
+                return super.getBounds();
             }
-            return;
         }
 
         // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
         // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
         // system.
-        mDisplayContent.getLogicalDisplayRect(out);
+        return mDisplayContent.getBounds();
     }
 
     /**
@@ -373,7 +369,7 @@
             mBoundsAnimationSourceHintBounds.setEmpty();
         }
 
-        mPreAnimationBounds.set(mBounds);
+        mPreAnimationBounds.set(getRawBounds());
     }
 
     /**
@@ -418,12 +414,12 @@
         if (bounds != null) {
             setBounds(bounds);
             return;
-        } else if (mFillsParent) {
+        } else if (matchParentBounds()) {
             setBounds(null);
             return;
         }
 
-        mTmpRect2.set(mBounds);
+        mTmpRect2.set(getRawBounds());
         final int newRotation = mDisplayContent.getDisplayInfo().rotation;
         final int newDensity = mDisplayContent.getDisplayInfo().logicalDensityDpi;
         if (mRotation == newRotation && mDensity == newDensity) {
@@ -466,14 +462,14 @@
             return false;
         }
 
-        if (mFillsParent) {
+        if (matchParentBounds()) {
             // Update stack bounds again since rotation changed since updateDisplayInfo().
             setBounds(null);
             // Return false since we don't need the client to resize.
             return false;
         }
 
-        mTmpRect2.set(mBounds);
+        mTmpRect2.set(getRawBounds());
         mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
         if (inSplitScreenPrimaryWindowingMode()) {
             repositionPrimarySplitScreenStackAfterRotation(mTmpRect2);
@@ -510,7 +506,7 @@
         if (mDisplayContent.getDockedDividerController().canPrimaryStackDockTo(dockSide)) {
             return;
         }
-        mDisplayContent.getLogicalDisplayRect(mTmpRect);
+        mDisplayContent.getBounds(mTmpRect);
         dockSide = DockedDividerUtils.invertDockSide(dockSide);
         switch (dockSide) {
             case DOCKED_LEFT:
@@ -755,7 +751,7 @@
             // not fullscreen. If it's fullscreen, it means that we are in the transition of
             // dismissing it, so we must not resize this stack.
             bounds = new Rect();
-            mDisplayContent.getLogicalDisplayRect(mTmpRect);
+            mDisplayContent.getBounds(mTmpRect);
             mTmpRect2.setEmpty();
             if (splitScreenStack != null) {
                 splitScreenStack.getRawBounds(mTmpRect2);
@@ -818,7 +814,7 @@
         }
 
         if (!inSplitScreenWindowingMode() || mDisplayContent == null) {
-            outStackBounds.set(mBounds);
+            outStackBounds.set(getRawBounds());
             return;
         }
 
@@ -833,7 +829,7 @@
             // The docked stack is being dismissed, but we caught before it finished being
             // dismissed. In that case we want to treat it as if it is not occupying any space and
             // let others occupy the whole display.
-            mDisplayContent.getLogicalDisplayRect(outStackBounds);
+            mDisplayContent.getBounds(outStackBounds);
             return;
         }
 
@@ -841,11 +837,11 @@
         if (dockedSide == DOCKED_INVALID) {
             // Not sure how you got here...Only thing we can do is return current bounds.
             Slog.e(TAG_WM, "Failed to get valid docked side for docked stack=" + dockedStack);
-            outStackBounds.set(mBounds);
+            outStackBounds.set(getRawBounds());
             return;
         }
 
-        mDisplayContent.getLogicalDisplayRect(mTmpRect);
+        mDisplayContent.getBounds(mTmpRect);
         dockedStack.getRawBounds(mTmpRect2);
         final boolean dockedOnTopOrLeft = dockedSide == DOCKED_TOP || dockedSide == DOCKED_LEFT;
         getStackDockedModeBounds(mTmpRect, outStackBounds, mTmpRect2,
@@ -1146,14 +1142,14 @@
             // occluded by IME. We shift its bottom up by the height of the IME, but
             // leaves at least 30% of the top stack visible.
             final int minTopStackBottom =
-                    getMinTopStackBottom(displayContentRect, mBounds.bottom);
+                    getMinTopStackBottom(displayContentRect, getRawBounds().bottom);
             final int bottom = Math.max(
-                    mBounds.bottom - yOffset + dividerWidth - dividerWidthInactive,
+                    getRawBounds().bottom - yOffset + dividerWidth - dividerWidthInactive,
                     minTopStackBottom);
-            mTmpAdjustedBounds.set(mBounds);
-            mTmpAdjustedBounds.bottom =
-                    (int) (mAdjustImeAmount * bottom + (1 - mAdjustImeAmount) * mBounds.bottom);
-            mFullyAdjustedImeBounds.set(mBounds);
+            mTmpAdjustedBounds.set(getRawBounds());
+            mTmpAdjustedBounds.bottom = (int) (mAdjustImeAmount * bottom + (1 - mAdjustImeAmount)
+                    * getRawBounds().bottom);
+            mFullyAdjustedImeBounds.set(getRawBounds());
         } else {
             // When the stack is on bottom and has no focus, it's only adjusted for divider width.
             final int dividerWidthDelta = dividerWidthInactive - dividerWidth;
@@ -1163,22 +1159,24 @@
             // We try to move it up by the height of the IME window, but only to the extent
             // that leaves at least 30% of the top stack visible.
             // 'top' is where the top of bottom stack will move to in this case.
-            final int topBeforeImeAdjust = mBounds.top - dividerWidth + dividerWidthInactive;
+            final int topBeforeImeAdjust =
+                    getRawBounds().top - dividerWidth + dividerWidthInactive;
             final int minTopStackBottom =
-                    getMinTopStackBottom(displayContentRect, mBounds.top - dividerWidth);
+                    getMinTopStackBottom(displayContentRect,
+                            getRawBounds().top - dividerWidth);
             final int top = Math.max(
-                    mBounds.top - yOffset, minTopStackBottom + dividerWidthInactive);
+                    getRawBounds().top - yOffset, minTopStackBottom + dividerWidthInactive);
 
-            mTmpAdjustedBounds.set(mBounds);
+            mTmpAdjustedBounds.set(getRawBounds());
             // Account for the adjustment for IME and divider width separately.
             // (top - topBeforeImeAdjust) is the amount of movement due to IME only,
             // and dividerWidthDelta is due to divider width change only.
-            mTmpAdjustedBounds.top = mBounds.top +
+            mTmpAdjustedBounds.top = getRawBounds().top +
                     (int) (mAdjustImeAmount * (top - topBeforeImeAdjust) +
                             mAdjustDividerAmount * dividerWidthDelta);
-            mFullyAdjustedImeBounds.set(mBounds);
+            mFullyAdjustedImeBounds.set(getRawBounds());
             mFullyAdjustedImeBounds.top = top;
-            mFullyAdjustedImeBounds.bottom = top + mBounds.height();
+            mFullyAdjustedImeBounds.bottom = top + getRawBounds().height();
         }
         return true;
     }
@@ -1192,21 +1190,21 @@
         if (dockSide == DOCKED_TOP) {
             mService.getStableInsetsLocked(DEFAULT_DISPLAY, mTmpRect);
             int topInset = mTmpRect.top;
-            mTmpAdjustedBounds.set(mBounds);
-            mTmpAdjustedBounds.bottom =
-                    (int) (minimizeAmount * topInset + (1 - minimizeAmount) * mBounds.bottom);
+            mTmpAdjustedBounds.set(getRawBounds());
+            mTmpAdjustedBounds.bottom = (int) (minimizeAmount * topInset + (1 - minimizeAmount)
+                    * getRawBounds().bottom);
         } else if (dockSide == DOCKED_LEFT) {
-            mTmpAdjustedBounds.set(mBounds);
-            final int width = mBounds.width();
+            mTmpAdjustedBounds.set(getRawBounds());
+            final int width = getRawBounds().width();
             mTmpAdjustedBounds.right =
                     (int) (minimizeAmount * mDockedStackMinimizeThickness
-                            + (1 - minimizeAmount) * mBounds.right);
+                            + (1 - minimizeAmount) * getRawBounds().right);
             mTmpAdjustedBounds.left = mTmpAdjustedBounds.right - width;
         } else if (dockSide == DOCKED_RIGHT) {
-            mTmpAdjustedBounds.set(mBounds);
-            mTmpAdjustedBounds.left =
-                    (int) (minimizeAmount * (mBounds.right - mDockedStackMinimizeThickness)
-                            + (1 - minimizeAmount) * mBounds.left);
+            mTmpAdjustedBounds.set(getRawBounds());
+            mTmpAdjustedBounds.left = (int) (minimizeAmount *
+                    (getRawBounds().right - mDockedStackMinimizeThickness)
+                            + (1 - minimizeAmount) * getRawBounds().left);
         }
         return true;
     }
@@ -1228,9 +1226,9 @@
         if (dockSide == DOCKED_TOP) {
             mService.getStableInsetsLocked(DEFAULT_DISPLAY, mTmpRect);
             int topInset = mTmpRect.top;
-            return mBounds.bottom - topInset;
+            return getRawBounds().bottom - topInset;
         } else if (dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT) {
-            return mBounds.width() - mDockedStackMinimizeThickness;
+            return getRawBounds().width() - mDockedStackMinimizeThickness;
         } else {
             return 0;
         }
@@ -1264,11 +1262,12 @@
             return;
         }
 
-        final Rect insetBounds = mImeGoingAway ? mBounds : mFullyAdjustedImeBounds;
+        final Rect insetBounds = mImeGoingAway ? getRawBounds() : mFullyAdjustedImeBounds;
         task.alignToAdjustedBounds(mAdjustedBounds, insetBounds, getDockSide() == DOCKED_TOP);
         mDisplayContent.setLayoutNeeded();
     }
 
+
     boolean isAdjustedForMinimizedDockedStack() {
         return mMinimizeAmount != 0f;
     }
@@ -1282,8 +1281,8 @@
         for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; taskNdx--) {
             mChildren.get(taskNdx).writeToProto(proto, TASKS, trim);
         }
-        proto.write(FILLS_PARENT, mFillsParent);
-        mBounds.writeToProto(proto, BOUNDS);
+        proto.write(FILLS_PARENT, matchParentBounds());
+        getRawBounds().writeToProto(proto, BOUNDS);
         proto.write(ANIMATION_BACKGROUND_SURFACE_IS_DIMMING, mAnimationBackgroundSurfaceIsShown);
         proto.end(token);
     }
@@ -1291,8 +1290,7 @@
     public void dump(String prefix, PrintWriter pw) {
         pw.println(prefix + "mStackId=" + mStackId);
         pw.println(prefix + "mDeferRemoval=" + mDeferRemoval);
-        pw.println(prefix + "mFillsParent=" + mFillsParent);
-        pw.println(prefix + "mBounds=" + mBounds.toShortString());
+        pw.println(prefix + "mBounds=" + getRawBounds().toShortString());
         if (mMinimizeAmount != 0f) {
             pw.println(prefix + "mMinimizeAmount=" + mMinimizeAmount);
         }
@@ -1323,18 +1321,10 @@
         }
     }
 
-    /** Fullscreen status of the stack without adjusting for other factors in the system like
-     * visibility of docked stack.
-     * Most callers should be using {@link #fillsParent} as it take into consideration other
-     * system factors. */
-    boolean getRawFullscreen() {
-        return mFillsParent;
-    }
-
     @Override
     boolean fillsParent() {
         if (useCurrentBounds()) {
-            return mFillsParent;
+            return matchParentBounds();
         }
         // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
         // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
@@ -1360,7 +1350,7 @@
      * information which side of the screen was the dock anchored.
      */
     int getDockSide() {
-        return getDockSide(mBounds);
+        return getDockSide(getRawBounds());
     }
 
     private int getDockSide(Rect bounds) {
@@ -1370,7 +1360,7 @@
         if (mDisplayContent == null) {
             return DOCKED_INVALID;
         }
-        mDisplayContent.getLogicalDisplayRect(mTmpRect);
+        mDisplayContent.getBounds(mTmpRect);
         final int orientation = mDisplayContent.getConfiguration().orientation;
         return getDockSideUnchecked(bounds, mTmpRect, orientation);
     }
@@ -1490,7 +1480,7 @@
              */
 
             if (task.isActivityTypeHome() && isMinimizedDockAndHomeStackResizable()) {
-                mDisplayContent.getLogicalDisplayRect(mTmpRect);
+                mDisplayContent.getBounds(mTmpRect);
             } else {
                 task.getDimBounds(mTmpRect);
             }
diff --git a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
index 42a2d9d..84ad576 100644
--- a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
@@ -20,7 +20,7 @@
 import android.graphics.Region;
 import android.hardware.input.InputManager;
 import android.view.MotionEvent;
-import android.view.WindowManagerPolicy.PointerEventListener;
+import android.view.WindowManagerPolicyConstants.PointerEventListener;
 
 import com.android.server.wm.WindowManagerService.H;
 
diff --git a/services/core/java/com/android/server/wm/TaskWindowContainerController.java b/services/core/java/com/android/server/wm/TaskWindowContainerController.java
index b3bb0b7..5caae32 100644
--- a/services/core/java/com/android/server/wm/TaskWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/TaskWindowContainerController.java
@@ -18,7 +18,6 @@
 
 import android.app.ActivityManager.TaskDescription;
 import android.app.ActivityManager.TaskSnapshot;
-import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Handler;
 import android.os.Looper;
@@ -30,6 +29,7 @@
 import java.lang.ref.WeakReference;
 
 import static com.android.server.EventLogTags.WM_TASK_CREATED;
+import static com.android.server.wm.ConfigurationContainer.BOUNDS_CHANGE_NONE;
 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
 import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
@@ -75,7 +75,7 @@
                         + stackController);
             }
             EventLog.writeEvent(WM_TASK_CREATED, taskId, stack.mStackId);
-            final Task task = createTask(taskId, stack, userId, bounds, resizeMode,
+            final Task task = createTask(taskId, stack, userId, resizeMode,
                     supportsPictureInPicture, taskDescription);
             final int position = toTop ? POSITION_TOP : POSITION_BOTTOM;
             // We only want to move the parents to the parents if we are creating this task at the
@@ -85,10 +85,10 @@
     }
 
     @VisibleForTesting
-    Task createTask(int taskId, TaskStack stack, int userId, Rect bounds, int resizeMode,
+    Task createTask(int taskId, TaskStack stack, int userId, int resizeMode,
             boolean supportsPictureInPicture, TaskDescription taskDescription) {
-        return new Task(taskId, stack, userId, mService, bounds, resizeMode,
-                supportsPictureInPicture, taskDescription, this);
+        return new Task(taskId, stack, userId, mService, resizeMode, supportsPictureInPicture,
+                taskDescription, this);
     }
 
     @Override
@@ -151,14 +151,14 @@
         }
     }
 
-    public void resize(Rect bounds, Configuration overrideConfig, boolean relayout,
-            boolean forced) {
+    public void resize(boolean relayout, boolean forced) {
         synchronized (mWindowMap) {
             if (mContainer == null) {
                 throw new IllegalArgumentException("resizeTask: taskId " + mTaskId + " not found.");
             }
 
-            if (mContainer.resizeLocked(bounds, overrideConfig, forced) && relayout) {
+            if (mContainer.setBounds(mContainer.getOverrideBounds(), forced) != BOUNDS_CHANGE_NONE
+                    && relayout) {
                 mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
             }
         }
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 629cc86..3ae4549 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -23,8 +23,8 @@
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 20bade67..7c56f00 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -30,10 +30,9 @@
 import android.util.SparseArray;
 import android.util.TimeUtils;
 import android.view.Choreographer;
-import android.view.SurfaceControl;
-import android.view.WindowManagerPolicy;
 
 import com.android.server.AnimationThread;
+import com.android.server.policy.WindowManagerPolicy;
 
 import java.io.PrintWriter;
 
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index a5e6288..6467582 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -318,11 +318,24 @@
      * @see #mFullConfiguration
      */
     @Override
-    final public void onOverrideConfigurationChanged(Configuration overrideConfiguration) {
+    public void onOverrideConfigurationChanged(Configuration overrideConfiguration) {
+        // We must diff before the configuration is applied so that we can capture the change
+        // against the existing bounds.
+        final int diff = diffOverrideBounds(overrideConfiguration.windowConfiguration.getBounds());
         super.onOverrideConfigurationChanged(overrideConfiguration);
         if (mParent != null) {
             mParent.onDescendantOverrideConfigurationChanged();
         }
+
+        if (diff == BOUNDS_CHANGE_NONE) {
+            return;
+        }
+
+        if ((diff & BOUNDS_CHANGE_SIZE) == BOUNDS_CHANGE_SIZE) {
+            onResize();
+        } else {
+            onMovedByResize();
+        }
     }
 
     /**
@@ -718,29 +731,8 @@
         final WindowContainer p = getParent();
         // Give the parent a chance to set properties. In hierarchy v1 we rely
         // on this to set full-screen dimensions on all our Surface-less Layers.
-        final SurfaceControl.Builder b = p.makeChildSurface(child);
-        if (child != null && child.isScreenOverlay()) {
-            // If it's a screen overlay it's been promoted in the hierarchy (wrt to the
-            // WindowContainer hierarchy vs the SurfaceControl hierarchy)
-            // and we shouldn't set ourselves as the parent.
-            return b;
-        } else {
-            return b.setParent(mSurfaceControl);
-        }
-    }
-
-    /**
-     * There are various layers which require promotion from the WindowContainer
-     * hierarchy to the Overlay layer described in {@link DisplayContent}. See {@link WindowState}
-     * for the particular usage.
-     *
-     * TODO: Perhaps this should be eliminated, either through modifying
-     * the window container hierarchy or through modifying the way we express these overlay
-     * Surfaces (for example, the Magnification Overlay could be implemented like the Strict-mode
-     * Flash and not actually use a WindowState).
-     */
-    boolean isScreenOverlay() {
-        return false;
+        return p.makeChildSurface(child)
+                .setParent(mSurfaceControl);
     }
 
     /**
diff --git a/core/java/android/view/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
similarity index 97%
rename from core/java/android/view/WindowManagerInternal.java
rename to services/core/java/com/android/server/wm/WindowManagerInternal.java
index d07b2ac..036f7b0 100644
--- a/core/java/android/view/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.view;
+package com.android.server.wm;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -23,8 +23,14 @@
 import android.graphics.Region;
 import android.hardware.display.DisplayManagerInternal;
 import android.os.IBinder;
+import android.view.IInputFilter;
+import android.view.IWindow;
+import android.view.MagnificationSpec;
+import android.view.WindowInfo;
 import android.view.animation.Animation;
 
+import com.android.server.policy.WindowManagerPolicy;
+
 import java.util.List;
 
 /**
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index e123bef..1cd4080 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -65,10 +65,10 @@
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
 import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static com.android.server.LockGuard.INDEX_WINDOW;
 import static com.android.server.LockGuard.installLock;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
 import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_END;
 import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START;
@@ -126,7 +126,6 @@
 import android.app.IActivityManager;
 import android.app.IAssistDataReceiver;
 import android.content.BroadcastReceiver;
-import android.content.ClipData;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
@@ -219,10 +218,7 @@
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
 import android.view.WindowManagerGlobal;
-import android.view.WindowManagerInternal;
-import android.view.WindowManagerPolicy;
-import android.view.WindowManagerPolicy.PointerEventListener;
-import android.view.WindowManagerPolicy.ScreenOffListener;
+import android.view.WindowManagerPolicyConstants.PointerEventListener;
 import android.view.animation.Animation;
 import android.view.inputmethod.InputMethodManagerInternal;
 
@@ -245,7 +241,8 @@
 import com.android.server.UiThread;
 import com.android.server.Watchdog;
 import com.android.server.input.InputManagerService;
-import android.view.DisplayFrames;
+import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.policy.WindowManagerPolicy.ScreenOffListener;
 import com.android.server.power.ShutdownThread;
 import com.android.server.utils.PriorityDump;
 
@@ -5519,7 +5516,7 @@
     }
 
     void reconfigureDisplayLocked(@NonNull DisplayContent displayContent) {
-        if (!mDisplayReady) {
+        if (!displayContent.isReady()) {
             return;
         }
         displayContent.configureDisplayPolicy();
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index 4b98d9d..2358695 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -16,6 +16,8 @@
 
 package com.android.server.wm;
 
+import static android.os.Build.IS_USER;
+
 import android.os.ShellCommand;
 
 import java.io.PrintWriter;
@@ -50,8 +52,10 @@
         pw.println("  help");
         pw.println("    Print this help text.");
         pw.println();
-        pw.println("  tracing (start | stop)");
-        pw.println("    start or stop window tracing");
-        pw.println();
+        if (!IS_USER){
+            pw.println("  tracing (start | stop)");
+            pw.println("    start or stop window tracing");
+            pw.println();
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 730ec37..a2323a4 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -58,6 +58,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
@@ -66,10 +67,10 @@
 import static android.view.WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_FREEFORM;
 import static android.view.WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME;
 import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-import static android.view.WindowManagerPolicy.TRANSIT_ENTER;
-import static android.view.WindowManagerPolicy.TRANSIT_EXIT;
-import static android.view.WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.policy.WindowManagerPolicy.TRANSIT_ENTER;
+import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT;
+import static com.android.server.policy.WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
@@ -158,10 +159,10 @@
 import android.view.ViewTreeObserver;
 import android.view.WindowInfo;
 import android.view.WindowManager;
-import android.view.WindowManagerPolicy;
 
 import com.android.internal.util.ToBooleanFunction;
 import com.android.server.input.InputWindowHandle;
+import com.android.server.policy.WindowManagerPolicy;
 
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
@@ -814,7 +815,7 @@
             layoutXDiff = 0;
             layoutYDiff = 0;
         } else {
-            getContainerBounds(mContainingFrame);
+            getBounds(mContainingFrame);
             if (mAppToken != null && !mAppToken.mFrozenBounds.isEmpty()) {
 
                 // If the bounds are frozen, we still want to translate the window freely and only
@@ -972,7 +973,7 @@
             mContentInsets.setEmpty();
             mVisibleInsets.setEmpty();
         } else {
-            getDisplayContent().getLogicalDisplayRect(mTmpRect);
+            getDisplayContent().getBounds(mTmpRect);
             // Override right and/or bottom insets in case if the frame doesn't fit the screen in
             // non-fullscreen mode.
             boolean overrideRightInset = !windowsAreFloating && !inFullscreenContainer
@@ -1044,6 +1045,18 @@
                 + " of=" + mOutsets.toShortString());
     }
 
+    // TODO: Look into whether this override is still necessary.
+    @Override
+    public Rect getBounds() {
+        if (isInMultiWindowMode()) {
+            return getTask().getBounds();
+        } else if (mAppToken != null){
+            return mAppToken.getBounds();
+        } else {
+            return super.getBounds();
+        }
+    }
+
     @Override
     public Rect getFrameLw() {
         return mFrame;
@@ -2445,7 +2458,7 @@
         mPolicyVisibility = true;
         mPolicyVisibilityAfterAnim = true;
         if (doAnimation) {
-            mWinAnimator.applyAnimationLocked(WindowManagerPolicy.TRANSIT_ENTER, true);
+            mWinAnimator.applyAnimationLocked(TRANSIT_ENTER, true);
         }
         if (requestAnim) {
             mService.scheduleAnimationLocked();
@@ -2473,7 +2486,7 @@
             return false;
         }
         if (doAnimation) {
-            mWinAnimator.applyAnimationLocked(WindowManagerPolicy.TRANSIT_EXIT, false);
+            mWinAnimator.applyAnimationLocked(TRANSIT_EXIT, false);
             if (mWinAnimator.mAnimation == null) {
                 doAnimation = false;
             }
@@ -2951,33 +2964,12 @@
 
     /** Is this window in a container that takes up the entire screen space? */
     private boolean inFullscreenContainer() {
-        if (mAppToken == null) {
-            return true;
-        }
-        if (mAppToken.hasBounds()) {
-            return false;
-        }
-        return !isInMultiWindowMode();
+        return mAppToken == null || (mAppToken.matchParentBounds() && !isInMultiWindowMode());
     }
 
     /** @return true when the window is in fullscreen task, but has non-fullscreen bounds set. */
     boolean isLetterboxedAppWindow() {
-        final Task task = getTask();
-        final boolean taskIsFullscreen = task != null && task.isFullscreen();
-        final boolean appWindowIsFullscreen = mAppToken != null && !mAppToken.hasBounds();
-
-        return taskIsFullscreen && !appWindowIsFullscreen;
-    }
-
-    /** Returns the appropriate bounds to use for computing frames. */
-    private void getContainerBounds(Rect outBounds) {
-        if (isInMultiWindowMode()) {
-            getTask().getBounds(outBounds);
-        } else if (mAppToken != null){
-            mAppToken.getBounds(outBounds);
-        } else {
-            outBounds.setEmpty();
-        }
+        return !isInMultiWindowMode() && mAppToken != null && !mAppToken.matchParentBounds();
     }
 
     boolean isDragResizeChanged() {
@@ -4119,9 +4111,6 @@
             policyCrop.intersect(-mCompatFrame.left, -mCompatFrame.top,
                     displayInfo.logicalWidth - mCompatFrame.left,
                     displayInfo.logicalHeight - mCompatFrame.top);
-        } else if (mLayer >= mService.mSystemDecorLayer) {
-            // Above the decor layer is easy, just use the entire window
-            policyCrop.set(0, 0, mCompatFrame.width(), mCompatFrame.height());
         } else if (mDecorFrame.isEmpty()) {
             // Windows without policy decor aren't cropped.
             policyCrop.set(0, 0, mCompatFrame.width(), mCompatFrame.height());
@@ -4355,27 +4344,19 @@
     @Override
     boolean shouldMagnify() {
         if (mAttrs.type == TYPE_INPUT_METHOD ||
-                mAttrs.type == TYPE_INPUT_METHOD_DIALOG) {
-            return false;
-        } else if (isScreenOverlay()) {
+                mAttrs.type == TYPE_INPUT_METHOD_DIALOG ||
+                mAttrs.type == TYPE_MAGNIFICATION_OVERLAY ||
+                mAttrs.type == TYPE_NAVIGATION_BAR ||
+                // It's tempting to wonder: Have we forgotten the rounded corners overlay?
+                // worry not: it's a fake TYPE_NAVIGATION_BAR_PANEL
+                mAttrs.type == TYPE_NAVIGATION_BAR_PANEL ||
+                mAttrs.type == TYPE_STATUS_BAR) {
             return false;
         }
         return true;
     }
 
     @Override
-    boolean isScreenOverlay() {
-        // It's tempting to wonder: Have we forgotten the rounded corners overlay?
-        // worry not: it's a fake TYPE_NAVIGATION_BAR.
-        if (mAttrs.type == TYPE_MAGNIFICATION_OVERLAY ||
-                mAttrs.type == TYPE_NAVIGATION_BAR ||
-                mAttrs.type == TYPE_STATUS_BAR) {
-            return true;
-        }
-        return false;
-    }
-
-    @Override
     SurfaceSession getSession() {
         if (mSession.mSurfaceSession != null) {
             return mSession.mSurfaceSession;
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 840cc40..d2b3748 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -64,12 +64,13 @@
 import android.view.SurfaceControl;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
-import android.view.WindowManagerPolicy;
 import android.view.animation.Animation;
 import android.view.animation.AnimationSet;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Transformation;
 
+import com.android.server.policy.WindowManagerPolicy;
+
 import java.io.PrintWriter;
 import java.io.FileDescriptor;
 
@@ -1970,7 +1971,7 @@
         final float width = w.mFrame.width();
         final float height = w.mFrame.height();
 
-        mService.getDefaultDisplayContentLocked().getLogicalDisplayRect(displayRect);
+        mService.getDefaultDisplayContentLocked().getBounds(displayRect);
         final float displayWidth = displayRect.width();
         final float displayHeight = displayRect.height();
 
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 5081868..169d0a3 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -20,8 +20,8 @@
 import static android.app.ActivityManagerInternal.APP_TRANSITION_SNAPSHOT;
 import static android.app.ActivityManagerInternal.APP_TRANSITION_SPLASH_SCREEN;
 import static android.app.ActivityManagerInternal.APP_TRANSITION_WINDOWS_DRAWN;
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
 import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_CLOSE;
 import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_OPEN;
 import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java
index 6aa5101..c858b19 100644
--- a/services/core/java/com/android/server/wm/WindowTracing.java
+++ b/services/core/java/com/android/server/wm/WindowTracing.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.os.Build.IS_USER;
 import static com.android.server.wm.proto.WindowManagerTraceFileProto.ENTRY;
 import static com.android.server.wm.proto.WindowManagerTraceFileProto.MAGIC_NUMBER;
 import static com.android.server.wm.proto.WindowManagerTraceFileProto.MAGIC_NUMBER_H;
@@ -62,6 +63,10 @@
     }
 
     void startTrace(PrintWriter pw) throws IOException {
+        if (IS_USER){
+            logAndPrintln(pw, "Error: Tracing is not supported on user builds.");
+            return;
+        }
         synchronized (mLock) {
             logAndPrintln(pw, "Start tracing to " + mTraceFile + ".");
             mWriteQueue.clear();
@@ -83,6 +88,10 @@
     }
 
     void stopTrace(PrintWriter pw) {
+        if (IS_USER){
+            logAndPrintln(pw, "Error: Tracing is not supported on user builds.");
+            return;
+        }
         synchronized (mLock) {
             logAndPrintln(pw, "Stop tracing to " + mTraceFile + ". Waiting for traces to flush.");
             mEnabled = mEnabledLockFree = false;
@@ -150,7 +159,9 @@
     static WindowTracing createDefaultAndStartLooper(Context context) {
         File file = new File("/data/misc/wmtrace/wm_trace.pb");
         WindowTracing windowTracing = new WindowTracing(file);
-        new Thread(windowTracing::loop, "window_tracing").start();
+        if (!IS_USER){
+            new Thread(windowTracing::loop, "window_tracing").start();
+        }
         return windowTracing;
     }
 
diff --git a/services/core/jni/com_android_server_UsbDescriptorParser.cpp b/services/core/jni/com_android_server_UsbDescriptorParser.cpp
index df85e31..35e65bc 100644
--- a/services/core/jni/com_android_server_UsbDescriptorParser.cpp
+++ b/services/core/jni/com_android_server_UsbDescriptorParser.cpp
@@ -17,16 +17,18 @@
 #define LOG_TAG "UsbHostManagerJNI"
 #include "utils/Log.h"
 
+#include <stdlib.h>
+
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
 
 #include <usbhost/usbhost.h>
 
-#define MAX_DESCRIPTORS_LENGTH 16384
+#define MAX_DESCRIPTORS_LENGTH 4096
 
 // com.android.server.usb.descriptors
 extern "C" {
-jbyteArray JNICALL Java_com_android_server_usb_descriptors_UsbDescriptorParser_getRawDescriptors(
+jbyteArray JNICALL Java_com_android_server_usb_descriptors_UsbDescriptorParser_getRawDescriptors_1native(
         JNIEnv* env, jobject thiz, jstring deviceAddr) {
     const char *deviceAddrStr = env->GetStringUTFChars(deviceAddr, NULL);
     struct usb_device* device = usb_device_open(deviceAddrStr);
@@ -39,6 +41,7 @@
 
     int fd = usb_device_get_fd(device);
     if (fd < 0) {
+        usb_device_close(device);
         return NULL;
     }
 
@@ -46,17 +49,48 @@
     jbyte buffer[MAX_DESCRIPTORS_LENGTH];
     lseek(fd, 0, SEEK_SET);
     int numBytes = read(fd, buffer, sizeof(buffer));
-
+    jbyteArray ret = NULL;
     usb_device_close(device);
 
-    jbyteArray ret = NULL;
-    if (numBytes != 0) {
+    if (numBytes > 0) {
         ret = env->NewByteArray(numBytes);
         env->SetByteArrayRegion(ret, 0, numBytes, buffer);
+    } else {
+        ALOGE("error reading descriptors\n");
     }
+
     return ret;
 }
 
+jstring JNICALL Java_com_android_server_usb_descriptors_UsbDescriptorParser_getDescriptorString_1native(
+        JNIEnv* env, jobject thiz, jstring deviceAddr, jint stringId) {
+
+    const char *deviceAddrStr = env->GetStringUTFChars(deviceAddr, NULL);
+    struct usb_device* device = usb_device_open(deviceAddrStr);
+    env->ReleaseStringUTFChars(deviceAddr, deviceAddrStr);
+
+    if (!device) {
+        ALOGE("usb_device_open failed");
+        return NULL;
+    }
+
+    int fd = usb_device_get_fd(device);
+    if (fd < 0) {
+        ALOGE("usb_device_get_fd failed");
+        usb_device_close(device);
+        return NULL;
+    }
+
+    char* c_str = usb_device_get_string(device, stringId, 0 /*timeout*/);
+
+    jstring j_str = env->NewStringUTF(c_str);
+
+    free(c_str);
+    usb_device_close(device);
+
+    return j_str;
+}
+
 } // extern "C"
 
 
diff --git a/services/core/jni/com_android_server_UsbHostManager.cpp b/services/core/jni/com_android_server_UsbHostManager.cpp
index 88ae824..11f508b 100644
--- a/services/core/jni/com_android_server_UsbHostManager.cpp
+++ b/services/core/jni/com_android_server_UsbHostManager.cpp
@@ -22,8 +22,6 @@
 #include "android_runtime/AndroidRuntime.h"
 #include "android_runtime/Log.h"
 
-#include <usbhost/usbhost.h>
-
 #include <stdio.h>
 #include <asm/byteorder.h>
 #include <sys/types.h>
@@ -31,22 +29,20 @@
 #include <fcntl.h>
 #include <sys/ioctl.h>
 
+#include <usbhost/usbhost.h>
+
+#define MAX_DESCRIPTORS_LENGTH 4096
+
 namespace android
 {
 
-static const int USB_CONTROL_TRANSFER_TIMEOUT_MS = 200;
-
 static struct parcel_file_descriptor_offsets_t
 {
     jclass mClass;
     jmethodID mConstructor;
 } gParcelFileDescriptorOffsets;
 
-static jmethodID method_beginUsbDeviceAdded;
-static jmethodID method_addUsbConfiguration;
-static jmethodID method_addUsbInterface;
-static jmethodID method_addUsbEndpoint;
-static jmethodID method_endUsbDeviceAdded;
+static jmethodID method_usbDeviceAdded;
 static jmethodID method_usbDeviceRemoved;
 
 static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
@@ -57,101 +53,63 @@
     }
 }
 
-static int usb_device_added(const char *devname, void* client_data) {
-    struct usb_descriptor_header* desc;
-    struct usb_descriptor_iter iter;
-
-    struct usb_device *device = usb_device_open(devname);
+static int usb_device_added(const char *devAddress, void* clientData) {
+    struct usb_device *device = usb_device_open(devAddress);
     if (!device) {
         ALOGE("usb_device_open failed\n");
         return 0;
     }
 
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    jobject thiz = (jobject)client_data;
     const usb_device_descriptor* deviceDesc = usb_device_get_device_descriptor(device);
+    int classID = deviceDesc->bDeviceClass;
+    int subClassID = deviceDesc->bDeviceSubClass;
 
-    char *manufacturer = usb_device_get_manufacturer_name(device,
-            USB_CONTROL_TRANSFER_TIMEOUT_MS);
-    char *product = usb_device_get_product_name(device,
-            USB_CONTROL_TRANSFER_TIMEOUT_MS);
-    int version = usb_device_get_version(device);
-    char *serial = usb_device_get_serial(device,
-            USB_CONTROL_TRANSFER_TIMEOUT_MS);
-
-    jstring deviceName = env->NewStringUTF(devname);
-    jstring manufacturerName = AndroidRuntime::NewStringLatin1(env, manufacturer);
-    jstring productName = AndroidRuntime::NewStringLatin1(env, product);
-    jstring serialNumber = AndroidRuntime::NewStringLatin1(env, serial);
-
-    jboolean result = env->CallBooleanMethod(thiz, method_beginUsbDeviceAdded,
-            deviceName, usb_device_get_vendor_id(device), usb_device_get_product_id(device),
-            deviceDesc->bDeviceClass, deviceDesc->bDeviceSubClass, deviceDesc->bDeviceProtocol,
-            manufacturerName, productName, version, serialNumber);
-
-    env->DeleteLocalRef(serialNumber);
-    env->DeleteLocalRef(productName);
-    env->DeleteLocalRef(manufacturerName);
-    env->DeleteLocalRef(deviceName);
-    free(manufacturer);
-    free(product);
-    free(serial);
-
-    if (!result) goto fail;
-
-    usb_descriptor_iter_init(device, &iter);
-
-    while ((desc = usb_descriptor_iter_next(&iter)) != NULL) {
-        if (desc->bDescriptorType == USB_DT_CONFIG) {
-            struct usb_config_descriptor *config = (struct usb_config_descriptor *)desc;
-            char *name = usb_device_get_string(device, config->iConfiguration,
-                    USB_CONTROL_TRANSFER_TIMEOUT_MS);
-            jstring configName = AndroidRuntime::NewStringLatin1(env, name);
-
-            env->CallVoidMethod(thiz, method_addUsbConfiguration,
-                    config->bConfigurationValue, configName, config->bmAttributes,
-                    config->bMaxPower);
-
-            env->DeleteLocalRef(configName);
-            free(name);
-        } else if (desc->bDescriptorType == USB_DT_INTERFACE) {
-            struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)desc;
-            char *name = usb_device_get_string(device, interface->iInterface,
-                    USB_CONTROL_TRANSFER_TIMEOUT_MS);
-            jstring interfaceName = AndroidRuntime::NewStringLatin1(env, name);
-
-            env->CallVoidMethod(thiz, method_addUsbInterface,
-                    interface->bInterfaceNumber, interfaceName, interface->bAlternateSetting,
-                    interface->bInterfaceClass, interface->bInterfaceSubClass,
-                    interface->bInterfaceProtocol);
-
-            env->DeleteLocalRef(interfaceName);
-            free(name);
-        } else if (desc->bDescriptorType == USB_DT_ENDPOINT) {
-            struct usb_endpoint_descriptor *endpoint = (struct usb_endpoint_descriptor *)desc;
-
-            env->CallVoidMethod(thiz, method_addUsbEndpoint,
-                    endpoint->bEndpointAddress, endpoint->bmAttributes,
-                    __le16_to_cpu(endpoint->wMaxPacketSize), endpoint->bInterval);
-        }
+    // get the raw descriptors
+    int fd = usb_device_get_fd(device);
+    if (fd < 0) {
+        ALOGE("usb_device_get_fd failed\n");
+        usb_device_close(device);
+        // TODO return an error code here?
+        return 0;
     }
 
-    env->CallVoidMethod(thiz, method_endUsbDeviceAdded);
+    // from android_hardware_UsbDeviceConnection_get_desc()
+    jbyte rawdescriptors[MAX_DESCRIPTORS_LENGTH];
+    lseek(fd, 0, SEEK_SET);
+    int numBytes = read(fd, rawdescriptors, sizeof(rawdescriptors));
 
-fail:
     usb_device_close(device);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+
+    if (numBytes > 0) {
+        JNIEnv* env = AndroidRuntime::getJNIEnv();
+        jobject thiz = (jobject)clientData;
+        jstring deviceAddress = env->NewStringUTF(devAddress);
+
+        jbyteArray descriptorsArray = env->NewByteArray(numBytes);
+        env->SetByteArrayRegion(descriptorsArray, 0, numBytes, rawdescriptors);
+
+        env->CallBooleanMethod(thiz, method_usbDeviceAdded,
+                deviceAddress, classID, subClassID, descriptorsArray);
+
+        env->DeleteLocalRef(descriptorsArray);
+        env->DeleteLocalRef(deviceAddress);
+
+        checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    } else {
+        // TODO return an error code here?
+        ALOGE("error reading descriptors\n");
+    }
 
     return 0;
 }
 
-static int usb_device_removed(const char *devname, void* client_data) {
+static int usb_device_removed(const char *devAddress, void* clientData) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
-    jobject thiz = (jobject)client_data;
+    jobject thiz = (jobject)clientData;
 
-    jstring deviceName = env->NewStringUTF(devname);
-    env->CallVoidMethod(thiz, method_usbDeviceRemoved, deviceName);
-    env->DeleteLocalRef(deviceName);
+    jstring deviceAddress = env->NewStringUTF(devAddress);
+    env->CallVoidMethod(thiz, method_usbDeviceRemoved, deviceAddress);
+    env->DeleteLocalRef(deviceAddress);
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
     return 0;
 }
@@ -168,11 +126,11 @@
 }
 
 static jobject android_server_UsbHostManager_openDevice(JNIEnv *env, jobject /* thiz */,
-                                                        jstring deviceName)
+                                                        jstring deviceAddress)
 {
-    const char *deviceNameStr = env->GetStringUTFChars(deviceName, NULL);
-    struct usb_device* device = usb_device_open(deviceNameStr);
-    env->ReleaseStringUTFChars(deviceName, deviceNameStr);
+    const char *deviceAddressStr = env->GetStringUTFChars(deviceAddress, NULL);
+    struct usb_device* device = usb_device_open(deviceAddressStr);
+    env->ReleaseStringUTFChars(deviceAddress, deviceAddressStr);
 
     if (!device)
         return NULL;
@@ -206,34 +164,12 @@
         ALOGE("Can't find com/android/server/usb/UsbHostManager");
         return -1;
     }
-    method_beginUsbDeviceAdded = env->GetMethodID(clazz, "beginUsbDeviceAdded",
-            "(Ljava/lang/String;IIIIILjava/lang/String;Ljava/lang/String;ILjava/lang/String;)Z");
-    if (method_beginUsbDeviceAdded == NULL) {
+    method_usbDeviceAdded =
+            env->GetMethodID(clazz, "usbDeviceAdded", "(Ljava/lang/String;II[B)Z");
+    if (method_usbDeviceAdded == NULL) {
         ALOGE("Can't find beginUsbDeviceAdded");
         return -1;
     }
-    method_addUsbConfiguration = env->GetMethodID(clazz, "addUsbConfiguration",
-            "(ILjava/lang/String;II)V");
-    if (method_addUsbConfiguration == NULL) {
-        ALOGE("Can't find addUsbConfiguration");
-        return -1;
-    }
-    method_addUsbInterface = env->GetMethodID(clazz, "addUsbInterface",
-            "(ILjava/lang/String;IIII)V");
-    if (method_addUsbInterface == NULL) {
-        ALOGE("Can't find addUsbInterface");
-        return -1;
-    }
-    method_addUsbEndpoint = env->GetMethodID(clazz, "addUsbEndpoint", "(IIII)V");
-    if (method_addUsbEndpoint == NULL) {
-        ALOGE("Can't find addUsbEndpoint");
-        return -1;
-    }
-    method_endUsbDeviceAdded = env->GetMethodID(clazz, "endUsbDeviceAdded", "()V");
-    if (method_endUsbDeviceAdded == NULL) {
-        ALOGE("Can't find endUsbDeviceAdded");
-        return -1;
-    }
     method_usbDeviceRemoved = env->GetMethodID(clazz, "usbDeviceRemoved",
             "(Ljava/lang/String;)V");
     if (method_usbDeviceRemoved == NULL) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
index 6086354..4a6bee5 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
@@ -64,6 +64,8 @@
     private final DevicePolicyManagerService mDpm;
     private final AlarmManager mAlarmManager;
 
+    private long mId;
+
     private final OnAlarmListener mBatchTimeoutAlarmListener = new OnAlarmListener() {
         @Override
         public void onAlarm() {
@@ -185,6 +187,10 @@
     private Bundle finalizeBatchAndBuildDeviceOwnerMessageLocked() {
         Bundle notificationExtras = null;
         if (mNetworkEvents.size() > 0) {
+            // Assign ids to the events.
+            for (NetworkEvent event : mNetworkEvents) {
+                event.setId(mId++);
+            }
             // Finalize the batch and start a new one from scratch.
             if (mBatches.size() >= MAX_BATCHES) {
                 // Remove the oldest batch if we hit the limit.
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index a2ec234..e5ab44f 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -26,6 +26,7 @@
     platform-test-annotations \
     ShortcutManagerTestUtils \
     truth-prebuilt \
+    testables \
     testng
 
 LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/aidl
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
index d3a8dee..c14f74c 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
@@ -35,7 +35,8 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.view.WindowManagerInternal;
+
+import com.android.server.wm.WindowManagerInternal;
 
 import org.junit.Before;
 import org.junit.BeforeClass;
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/GlobalActionPerformerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/GlobalActionPerformerTest.java
index 51e6bc9..1213e81 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/GlobalActionPerformerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/GlobalActionPerformerTest.java
@@ -22,7 +22,8 @@
 import android.accessibilityservice.AccessibilityService;
 import android.app.StatusBarManager;
 import android.content.Context;
-import android.view.WindowManagerInternal;
+
+import com.android.server.wm.WindowManagerInternal;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java b/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java
index fc12edc..1819398 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java
@@ -44,8 +44,10 @@
 import android.os.RemoteException;
 import android.support.test.runner.AndroidJUnit4;
 import android.view.KeyEvent;
-import android.view.WindowManagerPolicy;
+
 import com.android.server.accessibility.KeyEventDispatcher.KeyEventFilter;
+import com.android.server.policy.WindowManagerPolicy;
+
 import org.hamcrest.Description;
 import org.hamcrest.TypeSafeMatcher;
 import org.junit.Before;
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/KeyboardInterceptorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/KeyboardInterceptorTest.java
index 5db397f..ceb3f9d 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/KeyboardInterceptorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/KeyboardInterceptorTest.java
@@ -45,8 +45,9 @@
 import android.os.Looper;
 import android.support.test.runner.AndroidJUnit4;
 import android.view.KeyEvent;
-import android.view.WindowManagerPolicy;
-import android.view.WindowManagerPolicy.WindowState;
+
+import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.policy.WindowManagerPolicy.WindowState;
 
 /**
  * Tests for KeyboardInterceptor
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java
index 5887215..d3a30909 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java
@@ -45,10 +45,10 @@
 import android.os.Message;
 import android.support.test.runner.AndroidJUnit4;
 import android.view.MagnificationSpec;
-import android.view.WindowManagerInternal;
-import android.view.WindowManagerInternal.MagnificationCallbacks;
 
 import com.android.internal.R;
+import com.android.server.wm.WindowManagerInternal;
+import com.android.server.wm.WindowManagerInternal.MagnificationCallbacks;
 
 import org.hamcrest.CoreMatchers;
 import org.hamcrest.Description;
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
index ec99a9a..d286b3f 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
@@ -18,7 +18,7 @@
 
 import static android.view.MotionEvent.ACTION_DOWN;
 import static android.view.MotionEvent.ACTION_UP;
-import static android.view.WindowManagerPolicy.FLAG_PASS_TO_USER;
+import static android.view.WindowManagerPolicyConstants.FLAG_PASS_TO_USER;
 import static org.hamcrest.CoreMatchers.allOf;
 import static org.hamcrest.CoreMatchers.anyOf;
 import static org.hamcrest.CoreMatchers.everyItem;
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java
index 6311d00..dbebd01 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java
@@ -33,9 +33,10 @@
 import android.content.pm.ServiceInfo;
 import android.os.IBinder;
 import android.os.Looper;
-import android.view.WindowManagerInternal;
 import android.view.accessibility.AccessibilityEvent;
 
+import com.android.server.wm.WindowManagerInternal;
+
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
index 2b770ac..ee45595 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
@@ -21,10 +21,11 @@
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
 import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.WindowManagerPolicy.NAV_BAR_BOTTOM;
-import static android.view.WindowManagerPolicy.NAV_BAR_LEFT;
-import static android.view.WindowManagerPolicy.NAV_BAR_RIGHT;
 import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING;
+import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
+import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_LEFT;
+import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_RIGHT;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
@@ -36,7 +37,6 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.content.ComponentName;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.MediumTest;
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
index bc503c4..b4919b6 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
@@ -28,7 +28,6 @@
 
 import android.app.ActivityOptions;
 import android.app.IApplicationThread;
-import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
@@ -108,8 +107,8 @@
         final Rect bounds = new Rect(10, 10, 100, 100);
 
         mStarter.updateBounds(task, bounds);
-        assertEquals(task.mBounds, bounds);
-        assertEquals(task.getStack().mBounds, null);
+        assertEquals(task.getOverrideBounds(), bounds);
+        assertEquals(new Rect(), task.getStack().getOverrideBounds());
 
         // When in a resizeable stack, the stack bounds should be updated as well.
         final TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor)
@@ -124,10 +123,10 @@
 
         // In the case of no animation, the stack and task bounds should be set immediately.
         if (!ANIMATE) {
-            assertEquals(task2.getStack().mBounds, bounds);
-            assertEquals(task2.mBounds, bounds);
+            assertEquals(task2.getStack().getOverrideBounds(), bounds);
+            assertEquals(task2.getOverrideBounds(), bounds);
         } else {
-            assertEquals(task2.mBounds, null);
+            assertEquals(task2.getOverrideBounds(), new Rect());
         }
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index 9683e22..2fffb89 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -19,6 +19,7 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.doNothing;
@@ -415,6 +416,12 @@
         @Override
         protected T createStackWindowController(int displayId, boolean onTop, Rect outBounds) {
             mContainerController = (T) WindowTestUtils.createMockStackWindowContainerController();
+
+            // Primary pinned stacks require a non-empty out bounds to be set or else all tasks
+            // will be moved to the full screen stack.
+            if (getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+                outBounds.set(0, 0, 100, 100);
+            }
             return mContainerController;
         }
 
diff --git a/services/tests/servicestests/src/com/android/server/am/LaunchingTaskPositionerTests.java b/services/tests/servicestests/src/com/android/server/am/LaunchingTaskPositionerTests.java
index 01e2da6..13daf3e 100644
--- a/services/tests/servicestests/src/com/android/server/am/LaunchingTaskPositionerTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/LaunchingTaskPositionerTests.java
@@ -16,7 +16,6 @@
 
 package com.android.server.am;
 
-import android.content.ComponentName;
 import android.content.pm.ActivityInfo.WindowLayout;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
@@ -93,8 +92,8 @@
      */
     @Test
     public void testInitialBounds() throws Exception {
-        assertEquals(mStack.mBounds, STACK_BOUNDS);
-        assertEquals(mTask.mBounds, null);
+        assertEquals(mStack.getOverrideBounds(), STACK_BOUNDS);
+        assertEquals(mTask.getOverrideBounds(), new Rect());
     }
 
     /**
@@ -182,7 +181,7 @@
         mService.mStackSupervisor.getLaunchingBoundsController().layoutTask(mTask, layout);
 
         // Second task will be laid out on top of the first so starting bounds is the same.
-        final Rect expectedBounds = new Rect(mTask.mBounds);
+        final Rect expectedBounds = new Rect(mTask.getOverrideBounds());
 
         ActivityRecord activity = null;
         TaskRecord secondTask = null;
@@ -203,14 +202,16 @@
             if ((gravity & (Gravity.TOP | Gravity.RIGHT)) == (Gravity.TOP | Gravity.RIGHT)
                     || (gravity & (Gravity.BOTTOM | Gravity.RIGHT))
                     == (Gravity.BOTTOM | Gravity.RIGHT)) {
-                expectedBounds.offset(-LaunchingTaskPositioner.getHorizontalStep(mStack.mBounds),
-                        0);
+                expectedBounds.offset(-LaunchingTaskPositioner.getHorizontalStep(
+                        mStack.getOverrideBounds()), 0);
             } else if ((gravity & Gravity.TOP) == Gravity.TOP
                     || (gravity & Gravity.BOTTOM) == Gravity.BOTTOM) {
-                expectedBounds.offset(LaunchingTaskPositioner.getHorizontalStep(mStack.mBounds), 0);
+                expectedBounds.offset(
+                        LaunchingTaskPositioner.getHorizontalStep(mStack.getOverrideBounds()), 0);
             } else {
-                expectedBounds.offset(LaunchingTaskPositioner.getHorizontalStep(mStack.mBounds),
-                        LaunchingTaskPositioner.getVerticalStep(mStack.mBounds));
+                expectedBounds.offset(
+                        LaunchingTaskPositioner.getHorizontalStep(mStack.getOverrideBounds()),
+                        LaunchingTaskPositioner.getVerticalStep(mStack.getOverrideBounds()));
             }
 
             assertEquals(mResult, expectedBounds);
@@ -228,10 +229,12 @@
 
     private Rect getDefaultBounds(int gravity) {
         final Rect bounds = new Rect();
-        bounds.set(mStack.mBounds);
+        bounds.set(mStack.getOverrideBounds());
 
-        final int verticalInset = LaunchingTaskPositioner.getFreeformStartTop(mStack.mBounds);
-        final int horizontalInset = LaunchingTaskPositioner.getFreeformStartLeft(mStack.mBounds);
+        final int verticalInset =
+                LaunchingTaskPositioner.getFreeformStartTop(mStack.getOverrideBounds());
+        final int horizontalInset =
+                LaunchingTaskPositioner.getFreeformStartLeft(mStack.getOverrideBounds());
 
         bounds.inset(horizontalInset, verticalInset);
 
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java
index db317a0..a92d1db 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java
@@ -20,8 +20,6 @@
 import android.os.Parcel;
 import android.test.suitebuilder.annotation.SmallTest;
 
-import static junit.framework.Assert.assertEquals;
-
 @SmallTest
 public class NetworkEventTest extends DpmTestBase {
 
@@ -30,6 +28,7 @@
      */
     public void testConnectEventParceling() {
         ConnectEvent event = new ConnectEvent("127.0.0.1", 80, "com.android.whateverdude", 100000);
+        event.setId(5L);
         Parcel p = Parcel.obtain();
         p.writeParcelable(event, 0);
         p.setDataPosition(0);
@@ -39,6 +38,7 @@
         assertEquals(event.getPort(), unparceledEvent.getPort());
         assertEquals(event.getPackageName(), unparceledEvent.getPackageName());
         assertEquals(event.getTimestamp(), unparceledEvent.getTimestamp());
+        assertEquals(event.getId(), unparceledEvent.getId());
     }
 
     /**
@@ -47,6 +47,7 @@
     public void testDnsEventParceling() {
         DnsEvent event = new DnsEvent("d.android.com", new String[]{"192.168.0.1", "127.0.0.1"}, 2,
                 "com.android.whateverdude", 100000);
+        event.setId(5L);
         Parcel p = Parcel.obtain();
         p.writeParcelable(event, 0);
         p.setDataPosition(0);
@@ -59,5 +60,6 @@
                 unparceledEvent.getTotalResolvedAddressCount());
         assertEquals(event.getPackageName(), unparceledEvent.getPackageName());
         assertEquals(event.getTimestamp(), unparceledEvent.getTimestamp());
+        assertEquals(event.getId(), unparceledEvent.getId());
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
index 61df22e..1211f00 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -26,7 +26,6 @@
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.view.SurfaceControl;
-import android.view.WindowManagerInternal;
 
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
@@ -34,6 +33,7 @@
 import com.android.server.display.DisplayManagerService.SyncRoot;
 import com.android.server.display.VirtualDisplayAdapter.SurfaceControlDisplayFactory;
 import com.android.server.lights.LightsManager;
+import com.android.server.wm.WindowManagerInternal;
 
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index 2ad0580..ff25172 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -66,10 +66,12 @@
                 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, authToken, PASSWORD_QUALITY_ALPHABETIC,
                 USER_ID);
 
-        AuthenticationResult result = manager.unwrapPasswordBasedSyntheticPassword(mGateKeeperService, handle, PASSWORD, USER_ID);
+        AuthenticationResult result = manager.unwrapPasswordBasedSyntheticPassword(
+                mGateKeeperService, handle, PASSWORD, USER_ID, null);
         assertEquals(result.authToken.deriveKeyStorePassword(), authToken.deriveKeyStorePassword());
 
-        result = manager.unwrapPasswordBasedSyntheticPassword(mGateKeeperService, handle, BADPASSWORD, USER_ID);
+        result = manager.unwrapPasswordBasedSyntheticPassword(mGateKeeperService, handle,
+                BADPASSWORD, USER_ID, null);
         assertNull(result.authToken);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
new file mode 100644
index 0000000..a70441d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.policy;
+
+import android.annotation.Nullable;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.view.Display;
+import android.view.IApplicationToken;
+import android.view.WindowManager;
+
+public class FakeWindowState implements WindowManagerPolicy.WindowState {
+
+    public final Rect parentFrame = new Rect();
+    public final Rect displayFrame = new Rect();
+    public final Rect overscanFrame = new Rect();
+    public final Rect contentFrame = new Rect();
+    public final Rect visibleFrame = new Rect();
+    public final Rect decorFrame = new Rect();
+    public final Rect stableFrame = new Rect();
+    public Rect outsetFrame = new Rect();
+
+    public WindowManager.LayoutParams attrs;
+    public int displayId;
+    public boolean isVoiceInteraction;
+    public boolean inMultiWindowMode;
+    public boolean visible = true;
+    public int surfaceLayer = 1;
+
+    public boolean policyVisible = true;
+
+    @Override
+    public int getOwningUid() {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+    @Override
+    public String getOwningPackage() {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+    @Override
+    public void computeFrameLw(Rect parentFrame, Rect displayFrame, Rect overlayFrame,
+            Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame,
+            @Nullable Rect outsetFrame) {
+        this.parentFrame.set(parentFrame);
+        this.displayFrame.set(displayFrame);
+        this.overscanFrame.set(overlayFrame);
+        this.contentFrame.set(contentFrame);
+        this.visibleFrame.set(visibleFrame);
+        this.decorFrame.set(decorFrame);
+        this.stableFrame.set(stableFrame);
+        this.outsetFrame = outsetFrame == null ? null : new Rect(outsetFrame);
+    }
+
+    @Override
+    public Rect getFrameLw() {
+        return parentFrame;
+    }
+
+    @Override
+    public Point getShownPositionLw() {
+        return new Point(parentFrame.left, parentFrame.top);
+    }
+
+    @Override
+    public Rect getDisplayFrameLw() {
+        return displayFrame;
+    }
+
+    @Override
+    public Rect getOverscanFrameLw() {
+        return overscanFrame;
+    }
+
+    @Override
+    public Rect getContentFrameLw() {
+        return contentFrame;
+    }
+
+    @Override
+    public Rect getVisibleFrameLw() {
+        return visibleFrame;
+    }
+
+    @Override
+    public boolean getGivenInsetsPendingLw() {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+    @Override
+    public Rect getGivenContentInsetsLw() {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+    @Override
+    public Rect getGivenVisibleInsetsLw() {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+    @Override
+    public WindowManager.LayoutParams getAttrs() {
+        return attrs;
+    }
+
+    @Override
+    public boolean getNeedsMenuLw(WindowManagerPolicy.WindowState bottom) {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+    @Override
+    public int getSystemUiVisibility() {
+        return attrs.systemUiVisibility | attrs.subtreeSystemUiVisibility;
+    }
+
+    @Override
+    public int getSurfaceLayer() {
+        return surfaceLayer;
+    }
+
+    @Override
+    public int getBaseType() {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+    @Override
+    public IApplicationToken getAppToken() {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+    @Override
+    public boolean isVoiceInteraction() {
+        return isVoiceInteraction;
+    }
+
+    @Override
+    public boolean hasAppShownWindows() {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+    @Override
+    public boolean isVisibleLw() {
+        return visible && policyVisible;
+    }
+
+    @Override
+    public boolean isDisplayedLw() {
+        return isVisibleLw();
+    }
+
+    @Override
+    public boolean isAnimatingLw() {
+        return false;
+    }
+
+    @Override
+    public boolean canAffectSystemUiFlags() {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+    @Override
+    public boolean isGoneForLayoutLw() {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+    @Override
+    public boolean isDrawnLw() {
+        return true;
+    }
+
+    @Override
+    public boolean hasDrawnLw() {
+        return true;
+    }
+
+    @Override
+    public boolean hideLw(boolean doAnimation) {
+        if (!policyVisible) {
+            return false;
+        }
+        policyVisible = false;
+        return true;
+    }
+
+    @Override
+    public boolean showLw(boolean doAnimation) {
+        if (policyVisible) {
+            return false;
+        }
+        policyVisible = true;
+        return true;
+    }
+
+    @Override
+    public boolean isAlive() {
+        return true;
+    }
+
+    @Override
+    public boolean isDefaultDisplay() {
+        return displayId == Display.DEFAULT_DISPLAY;
+    }
+
+    @Override
+    public boolean isDimming() {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+    @Override
+    public int getWindowingMode() {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+    @Override
+    public boolean isInMultiWindowMode() {
+        return inMultiWindowMode;
+    }
+
+    @Override
+    public int getRotationAnimationHint() {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+    @Override
+    public boolean isInputMethodWindow() {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+    @Override
+    public int getDisplayId() {
+        return displayId;
+    }
+
+    @Override
+    public boolean canAcquireSleepToken() {
+        throw new UnsupportedOperationException("not implemented");
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java
new file mode 100644
index 0000000..0941d4f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.policy;
+
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+
+import static org.junit.Assert.assertEquals;
+
+import android.graphics.PixelFormat;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.WindowManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class PhoneWindowManagerLayoutTest extends PhoneWindowManagerTestBase {
+
+    private FakeWindowState mAppWindow;
+
+    @Before
+    public void setUp() throws Exception {
+        mAppWindow = new FakeWindowState();
+        mAppWindow.attrs = new WindowManager.LayoutParams(MATCH_PARENT, MATCH_PARENT,
+                TYPE_APPLICATION,
+                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+                PixelFormat.TRANSLUCENT);
+
+        addStatusBar();
+        addNavigationBar();
+    }
+
+    @Test
+    public void layoutWindowLw_appDrawsBars() throws Exception {
+        mAppWindow.attrs.flags |= FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+        mPolicy.addWindow(mAppWindow);
+
+        mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
+
+        assertInsetByTopBottom(mAppWindow.parentFrame, 0, 0);
+        assertInsetByTopBottom(mAppWindow.stableFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mAppWindow.contentFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mAppWindow.decorFrame, 0, 0);
+    }
+
+    @Test
+    public void layoutWindowLw_appWontDrawBars() throws Exception {
+        mAppWindow.attrs.flags &= ~FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+        mPolicy.addWindow(mAppWindow);
+
+        mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
+
+        assertInsetByTopBottom(mAppWindow.parentFrame, 0, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mAppWindow.stableFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mAppWindow.contentFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mAppWindow.decorFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+    }
+
+    @Test
+    public void layoutWindowLw_appWontDrawBars_forceStatus() throws Exception {
+        mAppWindow.attrs.flags &= ~FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+        mAppWindow.attrs.privateFlags |= PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
+        mPolicy.addWindow(mAppWindow);
+
+        mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
+
+        assertInsetByTopBottom(mAppWindow.parentFrame, 0, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mAppWindow.stableFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mAppWindow.contentFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mAppWindow.decorFrame, 0, NAV_BAR_HEIGHT);
+    }
+
+    @Test
+    public void addingWindow_doesNotTamperWithSysuiFlags() {
+        mAppWindow.attrs.flags |= FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+        mPolicy.addWindow(mAppWindow);
+
+        assertEquals(0, mAppWindow.attrs.systemUiVisibility);
+        assertEquals(0, mAppWindow.attrs.subtreeSystemUiVisibility);
+    }
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
new file mode 100644
index 0000000..9c55707
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.policy;
+
+import static android.view.Surface.ROTATION_0;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.os.UserHandle;
+import android.support.test.InstrumentationRegistry;
+import android.testing.TestableResources;
+import android.view.Display;
+import android.view.DisplayInfo;
+import android.view.Gravity;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.IAccessibilityManager;
+
+import com.android.server.policy.keyguard.KeyguardServiceDelegate;
+import com.android.server.wm.DisplayFrames;
+
+import org.junit.Before;
+
+public class PhoneWindowManagerTestBase {
+    static final int DISPLAY_WIDTH = 500;
+    static final int DISPLAY_HEIGHT = 1000;
+
+    static final int STATUS_BAR_HEIGHT = 10;
+    static final int NAV_BAR_HEIGHT = 15;
+
+    TestablePhoneWindowManager mPolicy;
+    TestContextWrapper mContext;
+    DisplayFrames mFrames;
+
+    FakeWindowState mStatusBar;
+    FakeWindowState mNavigationBar;
+
+    @Before
+    public void setUpBase() throws Exception {
+        mContext = new TestContextWrapper(InstrumentationRegistry.getTargetContext());
+        mContext.getResourceMocker().addOverride(
+                com.android.internal.R.dimen.status_bar_height, STATUS_BAR_HEIGHT);
+        mContext.getResourceMocker().addOverride(
+                com.android.internal.R.dimen.navigation_bar_height, NAV_BAR_HEIGHT);
+        mContext.getResourceMocker().addOverride(
+                com.android.internal.R.dimen.navigation_bar_height_landscape, NAV_BAR_HEIGHT);
+        mContext.getResourceMocker().addOverride(
+                com.android.internal.R.dimen.navigation_bar_width, NAV_BAR_HEIGHT);
+
+        mPolicy = TestablePhoneWindowManager.create(mContext);
+
+        DisplayInfo info = new DisplayInfo();
+        info.logicalWidth = DISPLAY_WIDTH;
+        info.logicalHeight = DISPLAY_HEIGHT;
+        info.rotation = ROTATION_0;
+        mFrames = new DisplayFrames(Display.DEFAULT_DISPLAY, info);
+    }
+
+    public void addStatusBar() {
+        mStatusBar = new FakeWindowState();
+        mStatusBar.attrs = new WindowManager.LayoutParams(MATCH_PARENT, STATUS_BAR_HEIGHT,
+                TYPE_STATUS_BAR, 0 /* flags */, PixelFormat.TRANSLUCENT);
+        mStatusBar.attrs.gravity = Gravity.TOP;
+
+        mPolicy.addWindow(mStatusBar);
+        mPolicy.mLastSystemUiFlags |= View.STATUS_BAR_TRANSPARENT;
+    }
+
+    public void addNavigationBar() {
+        mNavigationBar = new FakeWindowState();
+        mNavigationBar.attrs = new WindowManager.LayoutParams(MATCH_PARENT, STATUS_BAR_HEIGHT,
+                TYPE_NAVIGATION_BAR, 0 /* flags */, PixelFormat.TRANSLUCENT);
+        mNavigationBar.attrs.gravity = Gravity.BOTTOM;
+
+        mPolicy.addWindow(mNavigationBar);
+        mPolicy.mHasNavigationBar = true;
+        mPolicy.mLastSystemUiFlags |= View.NAVIGATION_BAR_TRANSPARENT;
+    }
+
+    /** Asserts that {@code actual} is inset by the given amounts from the full display rect. */
+    public void assertInsetBy(Rect actual, int expectedInsetLeft, int expectedInsetTop,
+            int expectedInsetRight, int expectedInsetBottom) {
+        assertEquals(new Rect(expectedInsetLeft, expectedInsetTop,
+                DISPLAY_WIDTH - expectedInsetRight, DISPLAY_HEIGHT - expectedInsetBottom), actual);
+    }
+
+    /**
+     * Asserts that {@code actual} is inset by the given amounts from the full display rect.
+     *
+     * Convenience wrapper for when only the top and bottom inset are non-zero.
+     */
+    public void assertInsetByTopBottom(Rect actual, int expectedInsetTop, int expectedInsetBottom) {
+        assertInsetBy(actual, 0, expectedInsetTop, 0, expectedInsetBottom);
+    }
+
+    static class TestContextWrapper extends ContextWrapper {
+        private final TestableResources mResourceMocker;
+
+        public TestContextWrapper(Context targetContext) {
+            super(targetContext);
+            mResourceMocker = new TestableResources(targetContext.getResources());
+        }
+
+        @Override
+        public int checkPermission(String permission, int pid, int uid) {
+            return PackageManager.PERMISSION_GRANTED;
+        }
+
+        @Override
+        public int checkPermission(String permission, int pid, int uid, IBinder callerToken) {
+            return PackageManager.PERMISSION_GRANTED;
+        }
+
+        @Override
+        public Resources getResources() {
+            return mResourceMocker.getResources();
+        }
+
+        public TestableResources getResourceMocker() {
+            return mResourceMocker;
+        }
+    }
+
+    static class TestablePhoneWindowManager extends PhoneWindowManager {
+
+        public TestablePhoneWindowManager() {
+        }
+
+        @Override
+        void initializeHdmiState() {
+            // Do nothing.
+        }
+
+        @Override
+        Context getSystemUiContext() {
+            return mContext;
+        }
+
+        void addWindow(WindowState state) {
+            if (state instanceof FakeWindowState) {
+                ((FakeWindowState) state).surfaceLayer =
+                        getWindowLayerFromTypeLw(state.getAttrs().type);
+            }
+            adjustWindowParamsLw(state, state.getAttrs(), true /* hasStatusBarPermission */);
+            assertEquals(WindowManagerGlobal.ADD_OKAY, prepareAddWindowLw(state, state.getAttrs()));
+        }
+
+        public static TestablePhoneWindowManager create(Context context) {
+            TestablePhoneWindowManager[] policy = new TestablePhoneWindowManager[1];
+            InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+                policy[0] = new TestablePhoneWindowManager();
+                policy[0].mContext = context;
+                policy[0].mKeyguardDelegate = mock(KeyguardServiceDelegate.class);
+                policy[0].mAccessibilityManager = new AccessibilityManager(context,
+                        mock(IAccessibilityManager.class), UserHandle.USER_CURRENT);
+                policy[0].mSystemGestures = mock(SystemGesturesPointerEventListener.class);
+                policy[0].onConfigurationChanged();
+            });
+            return policy[0];
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/FileUpdaterTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/FileUpdaterTest.java
index 7e2a7d2..7324fe6 100644
--- a/services/tests/servicestests/src/com/android/server/power/batterysaver/FileUpdaterTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/FileUpdaterTest.java
@@ -15,8 +15,9 @@
  */
 package com.android.server.power.batterysaver;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
@@ -26,6 +27,7 @@
 import static org.mockito.Mockito.verify;
 
 import android.content.Context;
+import android.hardware.camera2.impl.GetCommand;
 import android.os.Handler;
 import android.os.Looper;
 import android.support.test.InstrumentationRegistry;
@@ -40,6 +42,7 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.io.File;
 import java.io.IOException;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -72,6 +75,17 @@
         void injectWtf(String message, Throwable e) {
             mInjector.injectWtf(message, e);
         }
+
+        @Override
+        File injectDefaultValuesFilename() {
+            return new File(InstrumentationRegistry.getContext().getCacheDir() +
+                    "/test-default.xml");
+        }
+
+        @Override
+        boolean injectShouldSkipWrite() {
+            return false;
+        }
     }
 
     private interface Injector {
@@ -334,4 +348,57 @@
         reset(mInjector);
         testMultiWrites();
     }
+
+    @Test
+    public void testWriteReadDefault() throws Exception {
+        doReturn("111").when(mInjector).injectReadFromFileTrimmed("file1");
+        doReturn("222").when(mInjector).injectReadFromFileTrimmed("file2");
+        doReturn("333").when(mInjector).injectReadFromFileTrimmed("file3");
+
+        // Write
+        final ArrayMap<String, String> values = new ArrayMap<>();
+        values.put("file1", "11");
+        values.put("file2", "22");
+        values.put("file3", "33");
+
+        mInstance.writeFiles(values);
+        waitUntilMainHandlerDrain();
+
+        verify(mInjector, times(1)).injectWriteToFile("file1", "11");
+        verify(mInjector, times(1)).injectWriteToFile("file2", "22");
+        verify(mInjector, times(1)).injectWriteToFile("file3", "33");
+
+        // Clear and reload the default.
+        assertEquals(3, mInstance.getDefaultValuesForTest().size());
+        mInstance.getDefaultValuesForTest().clear();
+        assertEquals(0, mInstance.getDefaultValuesForTest().size());
+
+        mInstance.systemReady(/*runtimeRestarted=*/ true);
+
+        assertEquals(3, mInstance.getDefaultValuesForTest().size());
+
+        // Reset to default
+        mInstance.restoreDefault();
+        waitUntilMainHandlerDrain();
+
+        verify(mInjector, times(1)).injectWriteToFile("file1", "111");
+        verify(mInjector, times(1)).injectWriteToFile("file2", "222");
+        verify(mInjector, times(1)).injectWriteToFile("file3", "333");
+
+        // Make sure the default file still exists.
+        assertTrue(mInstance.injectDefaultValuesFilename().exists());
+
+        // Simulate a clean boot.
+        mInstance.getDefaultValuesForTest().clear();
+        assertEquals(0, mInstance.getDefaultValuesForTest().size());
+
+        mInstance.systemReady(/*runtimeRestarted=*/ false);
+
+        // Default is empty, and the file is gone.
+        assertEquals(0, mInstance.getDefaultValuesForTest().size());
+        assertFalse(mInstance.injectDefaultValuesFilename().exists());
+
+        // No WTF should have happened.
+        veriryWtf(0);
+   }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
index 0081214..53a5899 100644
--- a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
@@ -31,7 +31,8 @@
 import android.support.test.annotation.UiThreadTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.view.WindowManagerInternal.AppTransitionListener;
+
+import com.android.server.wm.WindowManagerInternal.AppTransitionListener;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index a45695f..c735341 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -47,7 +47,6 @@
 import android.view.InputChannel;
 import android.view.KeyEvent;
 import android.view.WindowManager;
-import android.view.WindowManagerPolicy;
 import android.view.animation.Animation;
 import android.os.PowerManagerInternal;
 
@@ -55,6 +54,7 @@
 import com.android.internal.policy.IShortcutService;
 import com.android.server.input.InputManagerService;
 import com.android.server.LocalServices;
+import com.android.server.policy.WindowManagerPolicy;
 
 import java.io.PrintWriter;
 
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
index 5d2bb4d..fdcf57b 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
@@ -21,8 +21,9 @@
 import org.junit.runner.RunWith;
 
 import android.app.ActivityManager.TaskDescription;
-import android.content.Context;
+import android.content.res.Configuration;
 import android.graphics.Rect;
+import android.os.Debug;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
@@ -75,11 +76,23 @@
         final Rect mInsetBounds = new Rect();
         boolean mFullscreenForTest = true;
         TaskWithBounds(Rect bounds) {
-            super(0, mStubStack, 0, sWm, null, 0, false, new TaskDescription(), null);
+            super(0, mStubStack, 0, sWm, 0, false, new TaskDescription(), null);
             mBounds = bounds;
+            setBounds(bounds);
         }
+
         @Override
-        void getBounds(Rect outBounds) {
+        public Rect getBounds() {
+            return mBounds;
+        }
+
+        @Override
+        public void getBounds(Rect out) {
+            out.set(mBounds);
+        }
+
+        @Override
+        public void getOverrideBounds(Rect outBounds) {
             outBounds.set(mBounds);
         }
         @Override
@@ -327,11 +340,8 @@
 
         w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null);
         w.calculatePolicyCrop(policyCrop);
-        // If we were above system decor we wouldnt' get any cropping though
-        w.mLayer = sWm.mSystemDecorLayer + 1;
-        w.calculatePolicyCrop(policyCrop);
-        assertRect(policyCrop, 0, 0, logicalWidth, logicalHeight);
-        w.mLayer = 1;
+        assertRect(policyCrop, 0, cf.top, logicalWidth, cf.bottom);
+
         dcf.setEmpty();
         // Likewise with no decor frame we would get no crop
         w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null);
@@ -395,7 +405,9 @@
         final int xInset = logicalWidth / 10;
         final int yInset = logicalWidth / 10;
         final Rect cf = new Rect(xInset, yInset, logicalWidth - xInset, logicalHeight - yInset);
-        w.mAppToken.onOverrideConfigurationChanged(w.mAppToken.getOverrideConfiguration(), cf);
+        Configuration config = new Configuration(w.mAppToken.getOverrideConfiguration());
+        config.windowConfiguration.setBounds(cf);
+        w.mAppToken.onOverrideConfigurationChanged(config);
         pf.set(0, 0, logicalWidth, logicalHeight);
         task.mFullscreenForTest = true;
 
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
index 1aafac6..b2334e8 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
@@ -29,11 +29,17 @@
 import static android.app.AppOpsManager.OP_NONE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static android.content.res.Configuration.EMPTY;
+
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyFloat;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import org.mockito.invocation.InvocationOnMock;
+
 /**
  * A collection of static functions that can be referenced by other test packages to provide access
  * to WindowManager related test functionality.
@@ -64,13 +70,24 @@
     public static StackWindowController createMockStackWindowContainerController() {
         StackWindowController controller = mock(StackWindowController.class);
         controller.mContainer = mock(TestTaskStack.class);
+
+        // many components rely on the {@link StackWindowController#adjustConfigurationForBounds}
+        // to properly set bounds values in the configuration. We must mimick those actions here.
+        doAnswer((InvocationOnMock invocationOnMock) -> {
+            final Configuration config = invocationOnMock.<Configuration>getArgument(7);
+            final Rect bounds = invocationOnMock.<Rect>getArgument(0);
+            config.windowConfiguration.setBounds(bounds);
+            return null;
+        }).when(controller).adjustConfigurationForBounds(any(), any(), any(), any(),
+                anyBoolean(), anyBoolean(), anyFloat(), any(), any());
+
         return controller;
     }
 
     /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
     public static Task createTaskInStack(WindowManagerService service, TaskStack stack,
             int userId) {
-        final Task newTask = new Task(sNextTaskId++, stack, userId, service, null, 0, false,
+        final Task newTask = new Task(sNextTaskId++, stack, userId, service, 0, false,
                 new ActivityManager.TaskDescription(), null);
         stack.addTask(newTask, POSITION_TOP);
         return newTask;
@@ -98,17 +115,17 @@
         TestAppWindowToken(DisplayContent dc) {
             super(dc.mService, new IApplicationToken.Stub() {
                 public String getName() {return null;}
-                }, false, dc, true /* fillsParent */, null /* bounds */);
+                }, false, dc, true /* fillsParent */);
         }
 
         TestAppWindowToken(WindowManagerService service, IApplicationToken token,
                 boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
                 boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
                 int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
-                boolean alwaysFocusable, AppWindowContainerController controller, Rect bounds) {
+                boolean alwaysFocusable, AppWindowContainerController controller) {
             super(service, token, voiceInteraction, dc, inputDispatchingTimeoutNanos, fullscreen,
                     showForAllUsers, targetSdk, orientation, rotationAnimationHint, configChanges,
-                    launchTaskBehind, alwaysFocusable, controller, bounds);
+                    launchTaskBehind, alwaysFocusable, controller);
         }
 
         int getWindowsCount() {
@@ -175,10 +192,10 @@
         private boolean mUseLocalIsAnimating = false;
         private boolean mIsAnimating = false;
 
-        TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
+        TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service,
                 int resizeMode, boolean supportsPictureInPicture,
                 TaskWindowContainerController controller) {
-            super(taskId, stack, userId, service, bounds, resizeMode, supportsPictureInPicture,
+            super(taskId, stack, userId, service, resizeMode, supportsPictureInPicture,
                     new ActivityManager.TaskDescription(), controller);
         }
 
@@ -247,9 +264,9 @@
         }
 
         @Override
-        TestTask createTask(int taskId, TaskStack stack, int userId, Rect bounds, int resizeMode,
+        TestTask createTask(int taskId, TaskStack stack, int userId, int resizeMode,
                 boolean supportsPictureInPicture, ActivityManager.TaskDescription taskDescription) {
-            return new TestTask(taskId, stack, userId, mService, bounds, resizeMode,
+            return new TestTask(taskId, stack, userId, mService, resizeMode,
                     supportsPictureInPicture, this);
         }
     }
@@ -269,8 +286,7 @@
                     true /* showForAllUsers */, 0 /* configChanges */, false /* voiceInteraction */,
                     false /* launchTaskBehind */, false /* alwaysFocusable */,
                     0 /* targetSdkVersion */, 0 /* rotationAnimationHint */,
-                    0 /* inputDispatchingTimeoutNanos */, taskController.mService,
-                    null /* bounds */);
+                    0 /* inputDispatchingTimeoutNanos */, taskController.mService);
             mToken = token;
         }
 
@@ -279,12 +295,12 @@
                 boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
                 boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
                 int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
-                boolean alwaysFocusable, AppWindowContainerController controller, Rect bounds) {
+                boolean alwaysFocusable, AppWindowContainerController controller) {
             return new TestAppWindowToken(service, token, voiceInteraction, dc,
                     inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk,
                     orientation,
                     rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
-                    controller, bounds);
+                    controller);
         }
 
         AppWindowToken getAppWindowToken(DisplayContent dc) {
diff --git a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
index f7c4b1f..4e23b51 100644
--- a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
@@ -185,7 +185,6 @@
         // target.
         assertWindowLayerGreaterThan(mTransaction, mImeWindow, mChildAppWindowAbove);
         assertWindowLayerGreaterThan(mTransaction, mImeWindow, mAppWindow);
-        assertWindowLayerGreaterThan(mTransaction, mImeWindow, mDockedDividerWindow);
         assertWindowLayerGreaterThan(mTransaction, mNavBarWindow, mImeWindow);
         assertWindowLayerGreaterThan(mTransaction, mStatusBarWindow, mImeWindow);
 
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index d359b70..7bea8a1 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -255,6 +255,7 @@
     }
 
     private void alsaFileAdded(String name) {
+        Slog.i(TAG, "alsaFileAdded(" + name + ")");
         int type = AlsaDevice.TYPE_UNKNOWN;
         int card = -1, device = -1;
 
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 9bc9cd0..dd2e192 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -19,13 +19,8 @@
 import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Context;
-import android.hardware.usb.UsbConfiguration;
 import android.hardware.usb.UsbConstants;
 import android.hardware.usb.UsbDevice;
-import android.hardware.usb.UsbDeviceConnection;
-import android.hardware.usb.UsbEndpoint;
-import android.hardware.usb.UsbInterface;
-import android.hardware.usb.UsbManager;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.text.TextUtils;
@@ -37,7 +32,6 @@
 import com.android.server.usb.descriptors.report.TextReportCanvas;
 import com.android.server.usb.descriptors.tree.UsbDescriptorsTree;
 
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 
@@ -50,28 +44,23 @@
 
     private final Context mContext;
 
-    // contains all connected USB devices
-    private final HashMap<String, UsbDevice> mDevices = new HashMap<>();
-
     // USB busses to exclude from USB host support
     private final String[] mHostBlacklist;
 
-    private final Object mLock = new Object();
-
-    private UsbDevice mNewDevice;
-    private UsbConfiguration mNewConfiguration;
-    private UsbInterface mNewInterface;
-    private ArrayList<UsbConfiguration> mNewConfigurations;
-    private ArrayList<UsbInterface> mNewInterfaces;
-    private ArrayList<UsbEndpoint> mNewEndpoints;
-
     private final UsbAlsaManager mUsbAlsaManager;
     private final UsbSettingsManager mSettingsManager;
 
+    private final Object mLock = new Object();
     @GuardedBy("mLock")
+    // contains all connected USB devices
+    private final HashMap<String, UsbDevice> mDevices = new HashMap<>();
+
+    private Object mSettingsLock = new Object();
+    @GuardedBy("mSettingsLock")
     private UsbProfileGroupSettingsManager mCurrentSettings;
 
-    @GuardedBy("mLock")
+    private Object mHandlerLock = new Object();
+    @GuardedBy("mHandlerLock")
     private ComponentName mUsbDeviceConnectionHandler;
 
     public UsbHostManager(Context context, UsbAlsaManager alsaManager,
@@ -91,33 +80,33 @@
     }
 
     public void setCurrentUserSettings(UsbProfileGroupSettingsManager settings) {
-        synchronized (mLock) {
+        synchronized (mSettingsLock) {
             mCurrentSettings = settings;
         }
     }
 
     private UsbProfileGroupSettingsManager getCurrentUserSettings() {
-        synchronized (mLock) {
+        synchronized (mSettingsLock) {
             return mCurrentSettings;
         }
     }
 
     public void setUsbDeviceConnectionHandler(@Nullable ComponentName usbDeviceConnectionHandler) {
-        synchronized (mLock) {
+        synchronized (mHandlerLock) {
             mUsbDeviceConnectionHandler = usbDeviceConnectionHandler;
         }
     }
 
     private @Nullable ComponentName getUsbDeviceConnectionHandler() {
-        synchronized (mLock) {
+        synchronized (mHandlerLock) {
             return mUsbDeviceConnectionHandler;
         }
     }
 
-    private boolean isBlackListed(String deviceName) {
+    private boolean isBlackListed(String deviceAddress) {
         int count = mHostBlacklist.length;
         for (int i = 0; i < count; i++) {
-            if (deviceName.startsWith(mHostBlacklist[i])) {
+            if (deviceAddress.startsWith(mHostBlacklist[i])) {
                 return true;
             }
         }
@@ -136,166 +125,73 @@
     }
 
     /* Called from JNI in monitorUsbHostBus() to report new USB devices
-       Returns true if successful, in which case the JNI code will continue adding configurations,
-       interfaces and endpoints, and finally call endUsbDeviceAdded after all descriptors
-       have been processed
+       Returns true if successful, i.e. the USB Audio device descriptors are
+       correctly parsed and the unique device is added to the audio device list.
      */
     @SuppressWarnings("unused")
-    private boolean beginUsbDeviceAdded(String deviceName, int vendorID, int productID,
-            int deviceClass, int deviceSubclass, int deviceProtocol,
-            String manufacturerName, String productName, int version, String serialNumber) {
-
+    private boolean usbDeviceAdded(String deviceAddress, int deviceClass, int deviceSubclass,
+            byte[] descriptors) {
         if (DEBUG) {
-            Slog.d(TAG, "usb:UsbHostManager.beginUsbDeviceAdded(" + deviceName + ")");
-            // Audio Class Codes:
-            // Audio: 0x01
-            // Audio Subclass Codes:
-            // undefined: 0x00
-            // audio control: 0x01
-            // audio streaming: 0x02
-            // midi streaming: 0x03
-
-            // some useful debugging info
-            Slog.d(TAG, "usb: nm:" + deviceName + " vnd:" + vendorID + " prd:" + productID + " cls:"
-                    + deviceClass + " sub:" + deviceSubclass + " proto:" + deviceProtocol);
+            Slog.d(TAG, "usbDeviceAdded(" + deviceAddress + ") - start");
         }
 
-        // OK this is non-obvious, but true. One can't tell if the device being attached is even
-        // potentially an audio device without parsing the interface descriptors, so punt on any
-        // such test until endUsbDeviceAdded() when we have that info.
-
-        if (isBlackListed(deviceName) ||
-                isBlackListed(deviceClass, deviceSubclass)) {
+        // check class/subclass first as it is more likely to be blacklisted
+        if (isBlackListed(deviceClass, deviceSubclass) || isBlackListed(deviceAddress)) {
+            if (DEBUG) {
+                Slog.d(TAG, "device is black listed");
+            }
             return false;
         }
 
         synchronized (mLock) {
-            if (mDevices.get(deviceName) != null) {
-                Slog.w(TAG, "device already on mDevices list: " + deviceName);
+            if (mDevices.get(deviceAddress) != null) {
+                Slog.w(TAG, "device already on mDevices list: " + deviceAddress);
+                //TODO If this is the same peripheral as is being connected, replace
+                // it with the new connection.
                 return false;
             }
 
-            if (mNewDevice != null) {
-                Slog.e(TAG, "mNewDevice is not null in endUsbDeviceAdded");
-                return false;
-            }
+            UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress);
+            if (parser.parseDescriptors(descriptors)) {
 
-            // Create version string in "%.%" format
-            String versionString = Integer.toString(version >> 8) + "." + (version & 0xFF);
-
-            mNewDevice = new UsbDevice(deviceName, vendorID, productID,
-                    deviceClass, deviceSubclass, deviceProtocol,
-                    manufacturerName, productName, versionString, serialNumber);
-
-            mNewConfigurations = new ArrayList<>();
-            mNewInterfaces = new ArrayList<>();
-            mNewEndpoints = new ArrayList<>();
-        }
-
-        return true;
-    }
-
-    /* Called from JNI in monitorUsbHostBus() to report new USB configuration for the device
-       currently being added.  Returns true if successful, false in case of error.
-     */
-    @SuppressWarnings("unused")
-    private void addUsbConfiguration(int id, String name, int attributes, int maxPower) {
-        if (mNewConfiguration != null) {
-            mNewConfiguration.setInterfaces(
-                    mNewInterfaces.toArray(new UsbInterface[mNewInterfaces.size()]));
-            mNewInterfaces.clear();
-        }
-
-        mNewConfiguration = new UsbConfiguration(id, name, attributes, maxPower);
-        mNewConfigurations.add(mNewConfiguration);
-    }
-
-    /* Called from JNI in monitorUsbHostBus() to report new USB interface for the device
-       currently being added.  Returns true if successful, false in case of error.
-     */
-    @SuppressWarnings("unused")
-    private void addUsbInterface(int id, String name, int altSetting,
-            int Class, int subClass, int protocol) {
-        if (mNewInterface != null) {
-            mNewInterface.setEndpoints(
-                    mNewEndpoints.toArray(new UsbEndpoint[mNewEndpoints.size()]));
-            mNewEndpoints.clear();
-        }
-
-        mNewInterface = new UsbInterface(id, altSetting, name, Class, subClass, protocol);
-        mNewInterfaces.add(mNewInterface);
-    }
-
-    /* Called from JNI in monitorUsbHostBus() to report new USB endpoint for the device
-       currently being added.  Returns true if successful, false in case of error.
-     */
-    @SuppressWarnings("unused")
-    private void addUsbEndpoint(int address, int attributes, int maxPacketSize, int interval) {
-        mNewEndpoints.add(new UsbEndpoint(address, attributes, maxPacketSize, interval));
-    }
-
-    /* Called from JNI in monitorUsbHostBus() to finish adding a new device */
-    @SuppressWarnings("unused")
-    private void endUsbDeviceAdded() {
-        if (DEBUG) {
-            Slog.d(TAG, "usb:UsbHostManager.endUsbDeviceAdded()");
-        }
-        if (mNewInterface != null) {
-            mNewInterface.setEndpoints(
-                    mNewEndpoints.toArray(new UsbEndpoint[mNewEndpoints.size()]));
-        }
-        if (mNewConfiguration != null) {
-            mNewConfiguration.setInterfaces(
-                    mNewInterfaces.toArray(new UsbInterface[mNewInterfaces.size()]));
-        }
-
-
-        synchronized (mLock) {
-            if (mNewDevice != null) {
-                mNewDevice.setConfigurations(
-                        mNewConfigurations.toArray(
-                                new UsbConfiguration[mNewConfigurations.size()]));
-                mDevices.put(mNewDevice.getDeviceName(), mNewDevice);
-                Slog.d(TAG, "Added device " + mNewDevice);
+                UsbDevice newDevice = parser.toAndroidUsbDevice();
+                mDevices.put(deviceAddress, newDevice);
 
                 // It is fine to call this only for the current user as all broadcasts are sent to
                 // all profiles of the user and the dialogs should only show once.
                 ComponentName usbDeviceConnectionHandler = getUsbDeviceConnectionHandler();
                 if (usbDeviceConnectionHandler == null) {
-                    getCurrentUserSettings().deviceAttached(mNewDevice);
+                    getCurrentUserSettings().deviceAttached(newDevice);
                 } else {
-                    getCurrentUserSettings().deviceAttachedForFixedHandler(mNewDevice,
+                    getCurrentUserSettings().deviceAttachedForFixedHandler(newDevice,
                             usbDeviceConnectionHandler);
                 }
-                // deviceName is something like: "/dev/bus/usb/001/001"
-                UsbDescriptorParser parser = new UsbDescriptorParser();
-                boolean isInputHeadset = false;
-                boolean isOutputHeadset = false;
-                if (parser.parseDevice(mNewDevice.getDeviceName())) {
-                    isInputHeadset = parser.isInputHeadset();
-                    isOutputHeadset = parser.isOutputHeadset();
-                    Slog.i(TAG, "---- isHeadset[in: " + isInputHeadset
-                            + " , out: " + isOutputHeadset + "]");
-                }
-                mUsbAlsaManager.usbDeviceAdded(mNewDevice,
-                        isInputHeadset, isOutputHeadset);
+
+                // Headset?
+                boolean isInputHeadset = parser.isInputHeadset();
+                boolean isOutputHeadset = parser.isOutputHeadset();
+                Slog.i(TAG, "---- isHeadset[in: " + isInputHeadset
+                        + " , out: " + isOutputHeadset + "]");
+
+                mUsbAlsaManager.usbDeviceAdded(newDevice, isInputHeadset, isOutputHeadset);
             } else {
-                Slog.e(TAG, "mNewDevice is null in endUsbDeviceAdded");
+                Slog.e(TAG, "Error parsing USB device descriptors for " + deviceAddress);
+                return false;
             }
-            mNewDevice = null;
-            mNewConfigurations = null;
-            mNewInterfaces = null;
-            mNewEndpoints = null;
-            mNewConfiguration = null;
-            mNewInterface = null;
         }
+
+        if (DEBUG) {
+            Slog.d(TAG, "beginUsbDeviceAdded(" + deviceAddress + ") end");
+        }
+
+        return true;
     }
 
     /* Called from JNI in monitorUsbHostBus to report USB device removal */
     @SuppressWarnings("unused")
-    private void usbDeviceRemoved(String deviceName) {
+    private void usbDeviceRemoved(String deviceAddress) {
         synchronized (mLock) {
-            UsbDevice device = mDevices.remove(deviceName);
+            UsbDevice device = mDevices.remove(deviceAddress);
             if (device != null) {
                 mUsbAlsaManager.usbDeviceRemoved(device);
                 mSettingsManager.usbDeviceRemoved(device);
@@ -323,32 +219,35 @@
     }
 
     /* Opens the specified USB device */
-    public ParcelFileDescriptor openDevice(String deviceName, UsbUserSettingsManager settings,
+    public ParcelFileDescriptor openDevice(String deviceAddress, UsbUserSettingsManager settings,
             String packageName, int uid) {
         synchronized (mLock) {
-            if (isBlackListed(deviceName)) {
+            if (isBlackListed(deviceAddress)) {
                 throw new SecurityException("USB device is on a restricted bus");
             }
-            UsbDevice device = mDevices.get(deviceName);
+            UsbDevice device = mDevices.get(deviceAddress);
             if (device == null) {
                 // if it is not in mDevices, it either does not exist or is blacklisted
                 throw new IllegalArgumentException(
-                        "device " + deviceName + " does not exist or is restricted");
+                        "device " + deviceAddress + " does not exist or is restricted");
             }
+
             settings.checkPermission(device, packageName, uid);
-            return nativeOpenDevice(deviceName);
+            return nativeOpenDevice(deviceAddress);
         }
     }
 
     public void dump(IndentingPrintWriter pw) {
-        synchronized (mLock) {
-            pw.println("USB Host State:");
-            for (String name : mDevices.keySet()) {
-                pw.println("  " + name + ": " + mDevices.get(name));
-            }
+        pw.println("USB Host State:");
+        synchronized (mHandlerLock) {
             if (mUsbDeviceConnectionHandler != null) {
                 pw.println("Default USB Host Connection handler: " + mUsbDeviceConnectionHandler);
             }
+        }
+        synchronized (mLock) {
+            for (String name : mDevices.keySet()) {
+                pw.println("  " + name + ": " + mDevices.get(name));
+            }
 
             Collection<UsbDevice> devices = mDevices.values();
             if (devices.size() != 0) {
@@ -356,17 +255,12 @@
                 for (UsbDevice device : devices) {
                     StringBuilder stringBuilder = new StringBuilder();
 
-                    UsbDescriptorParser parser = new UsbDescriptorParser();
-                    if (parser.parseDevice(device.getDeviceName())) {
+                    UsbDescriptorParser parser = new UsbDescriptorParser(device.getDeviceName());
+                    if (parser.parseDevice()) {
                         UsbDescriptorsTree descriptorTree = new UsbDescriptorsTree();
                         descriptorTree.parse(parser);
 
-                        UsbManager usbManager =
-                                (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
-                        UsbDeviceConnection connection = usbManager.openDevice(device);
-
-                        descriptorTree.report(new TextReportCanvas(connection, stringBuilder));
-                        connection.close();
+                        descriptorTree.report(new TextReportCanvas(parser, stringBuilder));
 
                         stringBuilder.append("isHeadset[in: " + parser.isInputHeadset()
                                 + " , out: " + parser.isOutputHeadset() + "]");
@@ -382,5 +276,5 @@
     }
 
     private native void monitorUsbHostBus();
-    private native ParcelFileDescriptor nativeOpenDevice(String deviceName);
+    private native ParcelFileDescriptor nativeOpenDevice(String deviceAddress);
 }
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java
index 75279c6..511e59a 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java
@@ -15,8 +15,13 @@
  */
 package com.android.server.usb.descriptors;
 
+import android.hardware.usb.UsbConfiguration;
+import android.hardware.usb.UsbInterface;
+
 import com.android.server.usb.descriptors.report.ReportCanvas;
 
+import java.util.ArrayList;
+
 /**
  * @hide
  * An USB Config Descriptor.
@@ -35,6 +40,9 @@
                                 //     D4..0 Reserved, set to 0.
     private byte mMaxPower;     // 8:1 Maximum Power Consumption in 2mA units
 
+    private ArrayList<UsbInterfaceDescriptor> mInterfaceDescriptors =
+            new ArrayList<UsbInterfaceDescriptor>();
+
     UsbConfigDescriptor(int length, byte type) {
         super(length, type);
         mHierarchyLevel = 2;
@@ -64,6 +72,22 @@
         return mMaxPower;
     }
 
+    void addInterfaceDescriptor(UsbInterfaceDescriptor interfaceDesc) {
+        mInterfaceDescriptors.add(interfaceDesc);
+    }
+
+    UsbConfiguration toAndroid(UsbDescriptorParser parser) {
+        String name = parser.getDescriptorString(mConfigIndex);
+        UsbConfiguration config = new
+                UsbConfiguration(mConfigValue, name, mAttribs, mMaxPower);
+        UsbInterface[] interfaces = new UsbInterface[mInterfaceDescriptors.size()];
+        for (int index = 0; index < mInterfaceDescriptors.size(); index++) {
+            interfaces[index] = mInterfaceDescriptors.get(index).toAndroid(parser);
+        }
+        config.setInterfaces(interfaces);
+        return config;
+    }
+
     @Override
     public int parseRawDescriptors(ByteStream stream) {
         mTotalLength = stream.unpackUsbShort();
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
index ad7bde5c..c5052c8 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
@@ -15,6 +15,7 @@
  */
 package com.android.server.usb.descriptors;
 
+import android.hardware.usb.UsbDevice;
 import android.util.Log;
 
 import java.util.ArrayList;
@@ -25,11 +26,16 @@
  */
 public final class UsbDescriptorParser {
     private static final String TAG = "UsbDescriptorParser";
+    private static final boolean DEBUG = false;
+
+    private final String mDeviceAddr;
 
     // Descriptor Objects
+    private static final int DESCRIPTORS_ALLOC_SIZE = 128;
     private ArrayList<UsbDescriptor> mDescriptors = new ArrayList<UsbDescriptor>();
 
     private UsbDeviceDescriptor mDeviceDescriptor;
+    private UsbConfigDescriptor mCurConfigDescriptor;
     private UsbInterfaceDescriptor mCurInterfaceDescriptor;
 
     // The AudioClass spec implemented by the AudioClass Interfaces
@@ -37,7 +43,13 @@
     // Obtained from the first AudioClass Header descriptor.
     private int mACInterfacesSpec = UsbDeviceDescriptor.USBSPEC_1_0;
 
-    public UsbDescriptorParser() {}
+    public UsbDescriptorParser(String deviceAddr) {
+        mDeviceAddr = deviceAddr;
+    }
+
+    public String getDeviceAddr() {
+        return mDeviceAddr;
+    }
 
     /**
      * @return the USB Spec value associated with the Device descriptor for the
@@ -60,6 +72,18 @@
     public int getACInterfaceSpec() {
         return mACInterfacesSpec;
     }
+
+    private class UsbDescriptorsStreamFormatException extends Exception {
+        String mMessage;
+        UsbDescriptorsStreamFormatException(String message) {
+            mMessage = message;
+        }
+
+        public String toString() {
+            return "Descriptor Stream Format Exception: " + mMessage;
+        }
+    }
+
     /**
      * The probability (as returned by getHeadsetProbability() at which we conclude
      * the peripheral is a headset.
@@ -67,7 +91,8 @@
     private static final float IN_HEADSET_TRIGGER = 0.75f;
     private static final float OUT_HEADSET_TRIGGER = 0.75f;
 
-    private UsbDescriptor allocDescriptor(ByteStream stream) {
+    private UsbDescriptor allocDescriptor(ByteStream stream)
+            throws UsbDescriptorsStreamFormatException {
         stream.resetReadCount();
 
         int length = stream.getUnsignedByte();
@@ -83,15 +108,38 @@
                 break;
 
             case UsbDescriptor.DESCRIPTORTYPE_CONFIG:
-                descriptor = new UsbConfigDescriptor(length, type);
+                descriptor = mCurConfigDescriptor = new UsbConfigDescriptor(length, type);
+                if (mDeviceDescriptor != null) {
+                    mDeviceDescriptor.addConfigDescriptor(mCurConfigDescriptor);
+                } else {
+                    Log.e(TAG, "Config Descriptor found with no associated Device Descriptor!");
+                    throw new UsbDescriptorsStreamFormatException(
+                            "Config Descriptor found with no associated Device Descriptor!");
+                }
                 break;
 
             case UsbDescriptor.DESCRIPTORTYPE_INTERFACE:
                 descriptor = mCurInterfaceDescriptor = new UsbInterfaceDescriptor(length, type);
+                if (mCurConfigDescriptor != null) {
+                    mCurConfigDescriptor.addInterfaceDescriptor(mCurInterfaceDescriptor);
+                } else {
+                    Log.e(TAG, "Interface Descriptor found with no associated Config Descriptor!");
+                    throw new UsbDescriptorsStreamFormatException(
+                            "Interface Descriptor found with no associated Config Descriptor!");
+                }
                 break;
 
             case UsbDescriptor.DESCRIPTORTYPE_ENDPOINT:
                 descriptor = new UsbEndpointDescriptor(length, type);
+                if (mCurInterfaceDescriptor != null) {
+                    mCurInterfaceDescriptor.addEndpointDescriptor(
+                            (UsbEndpointDescriptor) descriptor);
+                } else {
+                    Log.e(TAG,
+                            "Endpoint Descriptor found with no associated Interface Descriptor!");
+                    throw new UsbDescriptorsStreamFormatException(
+                            "Endpoint Descriptor found with no associated Interface Descriptor!");
+                }
                 break;
 
             /*
@@ -144,8 +192,12 @@
     /**
      * @hide
      */
-    public void parseDescriptors(byte[] descriptors) {
-        mDescriptors.clear();
+    public boolean parseDescriptors(byte[] descriptors) {
+        if (DEBUG) {
+            Log.d(TAG, "parseDescriptors() - start");
+        }
+        // This will allow us to (probably) alloc mDescriptors just once.
+        mDescriptors = new ArrayList<UsbDescriptor>(DESCRIPTORS_ALLOC_SIZE);
 
         ByteStream stream = new ByteStream(descriptors);
         while (stream.available() > 0) {
@@ -173,21 +225,36 @@
                 }
             }
         }
+        if (DEBUG) {
+            Log.d(TAG, "parseDescriptors() - end " + mDescriptors.size() + " descriptors.");
+        }
+        return true;
     }
 
     /**
      * @hide
      */
-    public boolean parseDevice(String deviceAddr) {
-        byte[] rawDescriptors = getRawDescriptors(deviceAddr);
-        if (rawDescriptors != null) {
-            parseDescriptors(rawDescriptors);
-            return true;
-        }
-        return false;
+    public boolean parseDevice() {
+        byte[] rawDescriptors = getRawDescriptors();
+
+        return rawDescriptors != null
+            ? parseDescriptors(rawDescriptors) : false;
     }
 
-    private native byte[] getRawDescriptors(String deviceAddr);
+    private byte[] getRawDescriptors() {
+        return getRawDescriptors_native(mDeviceAddr);
+    }
+
+    private native byte[] getRawDescriptors_native(String deviceAddr);
+
+    /**
+     * @hide
+     */
+    public String getDescriptorString(int stringId) {
+        return getDescriptorString_native(mDeviceAddr, stringId);
+    }
+
+    private native String getDescriptorString_native(String deviceAddr, int stringId);
 
     public int getParsingSpec() {
         return mDeviceDescriptor != null ? mDeviceDescriptor.getSpec() : 0;
@@ -200,6 +267,17 @@
     /**
      * @hide
      */
+    public UsbDevice toAndroidUsbDevice() {
+        if (mDeviceDescriptor == null) {
+            return null;
+        }
+
+        return mDeviceDescriptor.toAndroid(this);
+    }
+
+    /**
+     * @hide
+     */
     public ArrayList<UsbDescriptor> getDescriptors(byte type) {
         ArrayList<UsbDescriptor> list = new ArrayList<UsbDescriptor>();
         for (UsbDescriptor descriptor : mDescriptors) {
@@ -355,8 +433,6 @@
      * to count on the peripheral being a headset.
      */
     public boolean isInputHeadset() {
-        // TEMP
-        Log.i(TAG, "---- isInputHeadset() prob:" + (getInputHeadsetProbability() * 100f) + "%");
         return getInputHeadsetProbability() >= IN_HEADSET_TRIGGER;
     }
 
@@ -410,8 +486,6 @@
      * to count on the peripheral being a headset.
      */
     public boolean isOutputHeadset() {
-        // TEMP
-        Log.i(TAG, "---- isOutputHeadset() prob:" + (getOutputHeadsetProbability() * 100f) + "%");
         return getOutputHeadsetProbability() >= OUT_HEADSET_TRIGGER;
     }
 
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java
index d5cb89e..c89d9b6 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java
@@ -15,9 +15,14 @@
  */
 package com.android.server.usb.descriptors;
 
+import android.hardware.usb.UsbConfiguration;
+import android.hardware.usb.UsbDevice;
+
 import com.android.server.usb.descriptors.report.ReportCanvas;
 import com.android.server.usb.descriptors.report.UsbStrings;
 
+import java.util.ArrayList;
+
 /**
  * @hide
  * A USB Device Descriptor.
@@ -44,6 +49,9 @@
     private byte mSerialNum;    // 16:1 Index of Serial Number String Descriptor
     private byte mNumConfigs;   // 17:1 Number of Possible Configurations
 
+    private ArrayList<UsbConfigDescriptor> mConfigDescriptors =
+            new ArrayList<UsbConfigDescriptor>();
+
     UsbDeviceDescriptor(int length, byte type) {
         super(length, type);
         mHierarchyLevel = 1;
@@ -97,6 +105,35 @@
         return mNumConfigs;
     }
 
+    void addConfigDescriptor(UsbConfigDescriptor config) {
+        mConfigDescriptors.add(config);
+    }
+
+    /**
+     * @hide
+     */
+    public UsbDevice toAndroid(UsbDescriptorParser parser) {
+        String mfgName = parser.getDescriptorString(mMfgIndex);
+        String prodName = parser.getDescriptorString(mProductIndex);
+
+        // Create version string in "%.%" format
+        String versionString =
+                Integer.toString(mDeviceRelease >> 8) + "." + (mDeviceRelease & 0xFF);
+        String serialStr = parser.getDescriptorString(mSerialNum);
+
+        UsbDevice device = new UsbDevice(parser.getDeviceAddr(), mVendorID, mProductID,
+                mDevClass, mDevSubClass,
+                mProtocol, mfgName, prodName,
+                versionString, serialStr);
+        UsbConfiguration[] configs = new UsbConfiguration[mConfigDescriptors.size()];
+        for (int index = 0; index < mConfigDescriptors.size(); index++) {
+            configs[index] = mConfigDescriptors.get(index).toAndroid(parser);
+        }
+        device.setConfigurations(configs);
+
+        return device;
+    }
+
     @Override
     public int parseRawDescriptors(ByteStream stream) {
         mSpec = stream.unpackUsbShort();
@@ -134,12 +171,11 @@
                 + " Product ID: " + ReportCanvas.getHexString(getProductID())
                 + " Product Release: " + ReportCanvas.getBCDString(getDeviceRelease()));
 
+        UsbDescriptorParser parser = canvas.getParser();
         byte mfgIndex = getMfgIndex();
-        String manufacturer =
-                UsbDescriptor.getUsbDescriptorString(canvas.getConnection(), mfgIndex);
+        String manufacturer = parser.getDescriptorString(mfgIndex);
         byte productIndex = getProductIndex();
-        String product =
-                UsbDescriptor.getUsbDescriptorString(canvas.getConnection(), productIndex);
+        String product = parser.getDescriptorString(productIndex);
 
         canvas.writeListItem("Manufacturer " + mfgIndex + ": " + manufacturer
                 + " Product " + productIndex + ": " + product);
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java
index 6322fbe..9cb8f05 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java
@@ -15,6 +15,8 @@
  */
 package com.android.server.usb.descriptors;
 
+import android.hardware.usb.UsbEndpoint;
+
 import com.android.server.usb.descriptors.report.ReportCanvas;
 
 /**
@@ -105,6 +107,10 @@
         return mSyncAddress;
     }
 
+    /* package */ UsbEndpoint toAndroid(UsbDescriptorParser parser) {
+        return new UsbEndpoint(mEndpointAddress, mAttributes, mPacketSize, mInterval);
+    }
+
     @Override
     public int parseRawDescriptors(ByteStream stream) {
         mEndpointAddress = stream.getByte();
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java
index 4eef6ca..645807d 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java
@@ -15,9 +15,14 @@
  */
 package com.android.server.usb.descriptors;
 
+import android.hardware.usb.UsbEndpoint;
+import android.hardware.usb.UsbInterface;
+
 import com.android.server.usb.descriptors.report.ReportCanvas;
 import com.android.server.usb.descriptors.report.UsbStrings;
 
+import java.util.ArrayList;
+
 /**
  * @hide
  * A common super-class for all USB Interface Descritor subtypes.
@@ -34,6 +39,9 @@
     protected byte mProtocol;         // 7:1 Protocol Code
     protected byte mDescrIndex;       // 8:1 Index of String Descriptor Describing this interface
 
+    private ArrayList<UsbEndpointDescriptor> mEndpointDescriptors =
+            new ArrayList<UsbEndpointDescriptor>();
+
     UsbInterfaceDescriptor(int length, byte type) {
         super(length, type);
         mHierarchyLevel = 3;
@@ -80,6 +88,22 @@
         return mDescrIndex;
     }
 
+    void addEndpointDescriptor(UsbEndpointDescriptor endpoint) {
+        mEndpointDescriptors.add(endpoint);
+    }
+
+    UsbInterface toAndroid(UsbDescriptorParser parser) {
+        String name = parser.getDescriptorString(mDescrIndex);
+        UsbInterface ntrface = new UsbInterface(
+                mInterfaceNumber, mAlternateSetting, name, mUsbClass, mUsbSubclass, mProtocol);
+        UsbEndpoint[] endpoints = new UsbEndpoint[mEndpointDescriptors.size()];
+        for (int index = 0; index < mEndpointDescriptors.size(); index++) {
+            endpoints[index] = mEndpointDescriptors.get(index).toAndroid(parser);
+        }
+        ntrface.setEndpoints(endpoints);
+        return ntrface;
+    }
+
     @Override
     public void report(ReportCanvas canvas) {
         super.report(canvas);
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/HTMLReportCanvas.java b/services/usb/java/com/android/server/usb/descriptors/report/HTMLReportCanvas.java
index 99ebcca..adfc514 100644
--- a/services/usb/java/com/android/server/usb/descriptors/report/HTMLReportCanvas.java
+++ b/services/usb/java/com/android/server/usb/descriptors/report/HTMLReportCanvas.java
@@ -15,7 +15,7 @@
  */
 package com.android.server.usb.descriptors.report;
 
-import android.hardware.usb.UsbDeviceConnection;
+import com.android.server.usb.descriptors.UsbDescriptorParser;
 
 /**
  * @hide
@@ -32,8 +32,8 @@
      * from the USB device.
      * @param stringBuilder Generated output gets written into this object.
      */
-    public HTMLReportCanvas(UsbDeviceConnection connection, StringBuilder stringBuilder) {
-        super(connection);
+    public HTMLReportCanvas(UsbDescriptorParser parser, StringBuilder stringBuilder) {
+        super(parser);
 
         mStringBuilder = stringBuilder;
     }
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/ReportCanvas.java b/services/usb/java/com/android/server/usb/descriptors/report/ReportCanvas.java
index 9e0adf5..c34dc98 100644
--- a/services/usb/java/com/android/server/usb/descriptors/report/ReportCanvas.java
+++ b/services/usb/java/com/android/server/usb/descriptors/report/ReportCanvas.java
@@ -15,7 +15,7 @@
  */
 package com.android.server.usb.descriptors.report;
 
-import android.hardware.usb.UsbDeviceConnection;
+import com.android.server.usb.descriptors.UsbDescriptorParser;
 
 /**
  * @hide
@@ -24,22 +24,19 @@
 public abstract class ReportCanvas {
     private static final String TAG = "ReportCanvas";
 
-    private final UsbDeviceConnection mConnection;
+    private final UsbDescriptorParser mParser;
 
     /**
      * Constructor.
      * @param connection    The USB connection object used to retrieve strings
      * from the USB device.
      */
-    public ReportCanvas(UsbDeviceConnection connection) {
-        mConnection = connection;
+    public ReportCanvas(UsbDescriptorParser parser) {
+        mParser = parser;
     }
 
-    /**
-     * @returns the UsbDeviceConnection member (mConnection).
-     */
-    public UsbDeviceConnection getConnection() {
-        return mConnection;
+    public UsbDescriptorParser getParser() {
+        return mParser;
     }
 
     /**
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/TextReportCanvas.java b/services/usb/java/com/android/server/usb/descriptors/report/TextReportCanvas.java
index a43569d..1e19ea1 100644
--- a/services/usb/java/com/android/server/usb/descriptors/report/TextReportCanvas.java
+++ b/services/usb/java/com/android/server/usb/descriptors/report/TextReportCanvas.java
@@ -15,7 +15,7 @@
  */
 package com.android.server.usb.descriptors.report;
 
-import android.hardware.usb.UsbDeviceConnection;
+import com.android.server.usb.descriptors.UsbDescriptorParser;
 
 /**
  * @hide
@@ -34,8 +34,8 @@
      * from the USB device.
      * @param stringBuilder Generated output gets written into this object.
      */
-    public TextReportCanvas(UsbDeviceConnection connection, StringBuilder stringBuilder) {
-        super(connection);
+    public TextReportCanvas(UsbDescriptorParser parser, StringBuilder stringBuilder) {
+        super(parser);
 
         mStringBuilder = stringBuilder;
     }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 44e5314..2d93da9 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -427,8 +427,11 @@
                     if (hasComponent) {
                         mShortcutServiceInternal.setShortcutHostPackage(TAG,
                                 serviceComponent.getPackageName(), mCurUser);
+                        mAmInternal.setAllowAppSwitches(TAG,
+                                serviceInfo.applicationInfo.uid, mCurUser);
                     } else {
                         mShortcutServiceInternal.setShortcutHostPackage(TAG, null, mCurUser);
+                        mAmInternal.setAllowAppSwitches(TAG, -1, mCurUser);
                     }
                 }
 
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 1db6ef7..69371a1 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -816,6 +816,14 @@
     public static final String KEY_IMS_CONFERENCE_SIZE_LIMIT_INT = "ims_conference_size_limit_int";
 
     /**
+     * Determines whether manage IMS conference calls is supported by a carrier.  When {@code true},
+     * manage IMS conference call is supported, {@code false otherwise}.
+     * @hide
+     */
+    public static final String KEY_SUPPORT_MANAGE_IMS_CONFERENCE_CALL_BOOL =
+            "support_manage_ims_conference_call_bool";
+
+    /**
      * Determines whether High Definition audio property is displayed in the dialer UI.
      * If {@code false}, remove the HD audio property from the connection so that HD audio related
      * UI is not displayed. If {@code true}, keep HD audio property as it is configured.
@@ -1814,6 +1822,7 @@
         sDefaults.putInt(KEY_CDMA_3WAYCALL_FLASH_DELAY_INT , 0);
         sDefaults.putBoolean(KEY_SUPPORT_CONFERENCE_CALL_BOOL, true);
         sDefaults.putBoolean(KEY_SUPPORT_IMS_CONFERENCE_CALL_BOOL, true);
+        sDefaults.putBoolean(KEY_SUPPORT_MANAGE_IMS_CONFERENCE_CALL_BOOL, true);
         sDefaults.putBoolean(KEY_SUPPORT_VIDEO_CONFERENCE_CALL_BOOL, false);
         sDefaults.putBoolean(KEY_IS_IMS_CONFERENCE_SIZE_ENFORCED_BOOL, false);
         sDefaults.putInt(KEY_IMS_CONFERENCE_SIZE_LIMIT_INT, 5);
diff --git a/telephony/java/android/telephony/data/DataProfile.aidl b/telephony/java/android/telephony/data/DataProfile.aidl
new file mode 100644
index 0000000..65fdf91
--- /dev/null
+++ b/telephony/java/android/telephony/data/DataProfile.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** @hide */
+package android.telephony.data;
+
+parcelable DataProfile;
diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java
new file mode 100644
index 0000000..41c1430
--- /dev/null
+++ b/telephony/java/android/telephony/data/DataProfile.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.data;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import com.android.internal.telephony.RILConstants;
+
+/**
+ * Description of a mobile data profile used for establishing
+ * data connections.
+ *
+ * @hide
+ */
+@SystemApi
+public final class DataProfile implements Parcelable {
+
+    // The types indicating the data profile is used on GSM (3GPP) or CDMA (3GPP2) network.
+    public static final int TYPE_COMMON = 0;
+    public static final int TYPE_3GPP = 1;
+    public static final int TYPE_3GPP2 = 2;
+
+    private final int mProfileId;
+
+    private final String mApn;
+
+    private final String mProtocol;
+
+    private final int mAuthType;
+
+    private final String mUserName;
+
+    private final String mPassword;
+
+    private final int mType;
+
+    private final int mMaxConnsTime;
+
+    private final int mMaxConns;
+
+    private final int mWaitTime;
+
+    private final boolean mEnabled;
+
+    private final int mSupportedApnTypesBitmap;
+
+    private final String mRoamingProtocol;
+
+    private final int mBearerBitmap;
+
+    private final int mMtu;
+
+    private final String mMvnoType;
+
+    private final String mMvnoMatchData;
+
+    private final boolean mModemCognitive;
+
+    public DataProfile(int profileId, String apn, String protocol, int authType,
+                String userName, String password, int type, int maxConnsTime, int maxConns,
+                int waitTime, boolean enabled, int supportedApnTypesBitmap, String roamingProtocol,
+                int bearerBitmap, int mtu, String mvnoType, String mvnoMatchData,
+                boolean modemCognitive) {
+
+        this.mProfileId = profileId;
+        this.mApn = apn;
+        this.mProtocol = protocol;
+        if (authType == -1) {
+            authType = TextUtils.isEmpty(userName) ? RILConstants.SETUP_DATA_AUTH_NONE
+                    : RILConstants.SETUP_DATA_AUTH_PAP_CHAP;
+        }
+        this.mAuthType = authType;
+        this.mUserName = userName;
+        this.mPassword = password;
+        this.mType = type;
+        this.mMaxConnsTime = maxConnsTime;
+        this.mMaxConns = maxConns;
+        this.mWaitTime = waitTime;
+        this.mEnabled = enabled;
+
+        this.mSupportedApnTypesBitmap = supportedApnTypesBitmap;
+        this.mRoamingProtocol = roamingProtocol;
+        this.mBearerBitmap = bearerBitmap;
+        this.mMtu = mtu;
+        this.mMvnoType = mvnoType;
+        this.mMvnoMatchData = mvnoMatchData;
+        this.mModemCognitive = modemCognitive;
+    }
+
+    public DataProfile(Parcel source) {
+        mProfileId = source.readInt();
+        mApn = source.readString();
+        mProtocol = source.readString();
+        mAuthType = source.readInt();
+        mUserName = source.readString();
+        mPassword = source.readString();
+        mType = source.readInt();
+        mMaxConnsTime = source.readInt();
+        mMaxConns = source.readInt();
+        mWaitTime = source.readInt();
+        mEnabled = source.readBoolean();
+        mSupportedApnTypesBitmap = source.readInt();
+        mRoamingProtocol = source.readString();
+        mBearerBitmap = source.readInt();
+        mMtu = source.readInt();
+        mMvnoType = source.readString();
+        mMvnoMatchData = source.readString();
+        mModemCognitive = source.readBoolean();
+    }
+
+    /**
+     * @return Id of the data profile.
+     */
+    public int getProfileId() { return mProfileId; }
+
+    /**
+     * @return The APN to establish data connection.
+     */
+    public String getApn() { return mApn; }
+
+    /**
+     * @return The connection protocol, should be one of the PDP_type values in TS 27.007 section
+     * 10.1.1. For example, "IP", "IPV6", "IPV4V6", or "PPP".
+     */
+    public String getProtocol() { return mProtocol; }
+
+    /**
+     * @return The authentication protocol used for this PDP context
+     * (None: 0, PAP: 1, CHAP: 2, PAP&CHAP: 3)
+     */
+    public int getAuthType() { return mAuthType; }
+
+    /**
+     * @return The username for APN. Can be null.
+     */
+    public String getUserName() { return mUserName; }
+
+    /**
+     * @return The password for APN. Can be null.
+     */
+    public String getPassword() { return mPassword; }
+
+    /**
+     * @return The profile type. Could be one of TYPE_COMMON, TYPE_3GPP, or TYPE_3GPP2.
+     */
+    public int getType() { return mType; }
+
+    /**
+     * @return The period in seconds to limit the maximum connections.
+     */
+    public int getMaxConnsTime() { return mMaxConnsTime; }
+
+    /**
+     * @return The maximum connections allowed.
+     */
+    public int getMaxConns() { return mMaxConns; }
+
+    /**
+     * @return The required wait time in seconds after a successful UE initiated disconnect of a
+     * given PDN connection before the device can send a new PDN connection request for that given
+     * PDN.
+     */
+    public int getWaitTime() { return mWaitTime; }
+
+    /**
+     * @return True if the profile is enabled.
+     */
+    public boolean isEnabled() { return mEnabled; }
+
+    /**
+     * @return The supported APN types bitmap. See RIL_ApnTypes for the value of each bit.
+     */
+    public int getSupportedApnTypesBitmap() { return mSupportedApnTypesBitmap; }
+
+    /**
+     * @return  The connection protocol on roaming network, should be one of the PDP_type values in
+     * TS 27.007 section 10.1.1. For example, "IP", "IPV6", "IPV4V6", or "PPP".
+     */
+    public String getRoamingProtocol() { return mRoamingProtocol; }
+
+    /**
+     * @return The bearer bitmap. See RIL_RadioAccessFamily for the value of each bit.
+     */
+    public int getBearerBitmap() { return mBearerBitmap; }
+
+    /**
+     * @return The maximum transmission unit (MTU) size in bytes.
+     */
+    public int getMtu() { return mMtu; }
+
+    /**
+     * @return The MVNO type: possible values are "imsi", "gid", "spn".
+     */
+    public String getMvnoType() { return mMvnoType; }
+
+    /**
+     * @return The MVNO match data. For example,
+     * SPN: A MOBILE, BEN NL, ...
+     * IMSI: 302720x94, 2060188, ...
+     * GID: 4E, 33, ...
+     */
+    public String getMvnoMatchData() { return mMvnoMatchData; }
+
+    /**
+     * @return True if the data profile was sent to the modem through setDataProfile earlier.
+     */
+    public boolean isModemCognitive() { return mModemCognitive; }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public String toString() {
+        return "DataProfile=" + mProfileId + "/" + mApn + "/" + mProtocol + "/" + mAuthType
+                + "/" + mUserName + "/" + mPassword + "/" + mType + "/" + mMaxConnsTime
+                + "/" + mMaxConns + "/" + mWaitTime + "/" + mEnabled + "/"
+                + mSupportedApnTypesBitmap + "/" + mRoamingProtocol + "/" + mBearerBitmap + "/"
+                + mMtu + "/" + mMvnoType + "/" + mMvnoMatchData + "/" + mModemCognitive;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof DataProfile == false) return false;
+        return (o == this || toString().equals(o.toString()));
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mProfileId);
+        dest.writeString(mApn);
+        dest.writeString(mProtocol);
+        dest.writeInt(mAuthType);
+        dest.writeString(mUserName);
+        dest.writeString(mPassword);
+        dest.writeInt(mType);
+        dest.writeInt(mMaxConnsTime);
+        dest.writeInt(mMaxConns);
+        dest.writeInt(mWaitTime);
+        dest.writeBoolean(mEnabled);
+        dest.writeInt(mSupportedApnTypesBitmap);
+        dest.writeString(mRoamingProtocol);
+        dest.writeInt(mBearerBitmap);
+        dest.writeInt(mMtu);
+        dest.writeString(mMvnoType);
+        dest.writeString(mMvnoMatchData);
+        dest.writeBoolean(mModemCognitive);
+    }
+
+    public static final Parcelable.Creator<DataProfile> CREATOR =
+            new Parcelable.Creator<DataProfile>() {
+        @Override
+        public DataProfile createFromParcel(Parcel source) {
+            return new DataProfile(source);
+        }
+
+        @Override
+        public DataProfile[] newArray(int size) {
+            return new DataProfile[size];
+        }
+    };
+}
diff --git a/legacy-test/Android.mk b/test-base/Android.mk
similarity index 95%
rename from legacy-test/Android.mk
rename to test-base/Android.mk
index 4c150c8..f73eff7 100644
--- a/legacy-test/Android.mk
+++ b/test-base/Android.mk
@@ -63,8 +63,8 @@
 LEGACY_TEST_OUTPUT_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/legacy.test.stubs_intermediates/api.txt
 LEGACY_TEST_OUTPUT_REMOVED_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/legacy.test.stubs_intermediates/removed.txt
 
-LEGACY_TEST_API_FILE := $(LOCAL_PATH)/api/legacy-test-current.txt
-LEGACY_TEST_REMOVED_API_FILE := $(LOCAL_PATH)/api/legacy-test-removed.txt
+LEGACY_TEST_API_FILE := $(LOCAL_PATH)/api/android-test-base-current.txt
+LEGACY_TEST_REMOVED_API_FILE := $(LOCAL_PATH)/api/android-test-base-removed.txt
 
 LOCAL_DROIDDOC_OPTIONS:= \
     -stubpackages android.test:android.test.suitebuilder.annotation:com.android.internal.util:junit.framework \
@@ -119,7 +119,7 @@
     -error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 -error 15 \
     -error 16 -error 17 -error 18 -error 19 -error 20 -error 21 -error 23 -error 24 \
     -error 25 -error 26 -error 27, \
-    cat $(LOCAL_PATH)/api/apicheck_msg_legacy_test.txt, \
+    cat $(LOCAL_PATH)/api/apicheck_msg_android_test_base.txt, \
     check-legacy-test-api, \
     $(call doc-timestamp-for,legacy-test-api-stubs-gen) \
     ))
diff --git a/legacy-test/api/legacy-test-current.txt b/test-base/api/android-test-base-current.txt
similarity index 100%
rename from legacy-test/api/legacy-test-current.txt
rename to test-base/api/android-test-base-current.txt
diff --git a/legacy-test/api/legacy-test-removed.txt b/test-base/api/android-test-base-removed.txt
similarity index 100%
rename from legacy-test/api/legacy-test-removed.txt
rename to test-base/api/android-test-base-removed.txt
diff --git a/legacy-test/api/apicheck_msg_legacy_test.txt b/test-base/api/apicheck_msg_android_test_base.txt
similarity index 100%
rename from legacy-test/api/apicheck_msg_legacy_test.txt
rename to test-base/api/apicheck_msg_android_test_base.txt
diff --git a/legacy-test/jarjar-rules.txt b/test-base/jarjar-rules.txt
similarity index 100%
rename from legacy-test/jarjar-rules.txt
rename to test-base/jarjar-rules.txt
diff --git a/legacy-test/src/android/test/AndroidTestCase.java b/test-base/src/android/test/AndroidTestCase.java
similarity index 100%
rename from legacy-test/src/android/test/AndroidTestCase.java
rename to test-base/src/android/test/AndroidTestCase.java
diff --git a/legacy-test/src/android/test/FlakyTest.java b/test-base/src/android/test/FlakyTest.java
similarity index 100%
rename from legacy-test/src/android/test/FlakyTest.java
rename to test-base/src/android/test/FlakyTest.java
diff --git a/legacy-test/src/android/test/InstrumentationTestCase.java b/test-base/src/android/test/InstrumentationTestCase.java
similarity index 100%
rename from legacy-test/src/android/test/InstrumentationTestCase.java
rename to test-base/src/android/test/InstrumentationTestCase.java
diff --git a/legacy-test/src/android/test/InstrumentationTestSuite.java b/test-base/src/android/test/InstrumentationTestSuite.java
similarity index 100%
rename from legacy-test/src/android/test/InstrumentationTestSuite.java
rename to test-base/src/android/test/InstrumentationTestSuite.java
diff --git a/legacy-test/src/android/test/PerformanceTestCase.java b/test-base/src/android/test/PerformanceTestCase.java
similarity index 100%
rename from legacy-test/src/android/test/PerformanceTestCase.java
rename to test-base/src/android/test/PerformanceTestCase.java
diff --git a/legacy-test/src/android/test/RepetitiveTest.java b/test-base/src/android/test/RepetitiveTest.java
similarity index 100%
rename from legacy-test/src/android/test/RepetitiveTest.java
rename to test-base/src/android/test/RepetitiveTest.java
diff --git a/legacy-test/src/android/test/UiThreadTest.java b/test-base/src/android/test/UiThreadTest.java
similarity index 100%
rename from legacy-test/src/android/test/UiThreadTest.java
rename to test-base/src/android/test/UiThreadTest.java
diff --git a/legacy-test/src/android/test/package.html b/test-base/src/android/test/package.html
similarity index 100%
rename from legacy-test/src/android/test/package.html
rename to test-base/src/android/test/package.html
diff --git a/legacy-test/src/android/test/suitebuilder/annotation/LargeTest.java b/test-base/src/android/test/suitebuilder/annotation/LargeTest.java
similarity index 100%
rename from legacy-test/src/android/test/suitebuilder/annotation/LargeTest.java
rename to test-base/src/android/test/suitebuilder/annotation/LargeTest.java
diff --git a/legacy-test/src/android/test/suitebuilder/annotation/MediumTest.java b/test-base/src/android/test/suitebuilder/annotation/MediumTest.java
similarity index 100%
rename from legacy-test/src/android/test/suitebuilder/annotation/MediumTest.java
rename to test-base/src/android/test/suitebuilder/annotation/MediumTest.java
diff --git a/legacy-test/src/android/test/suitebuilder/annotation/SmallTest.java b/test-base/src/android/test/suitebuilder/annotation/SmallTest.java
similarity index 100%
rename from legacy-test/src/android/test/suitebuilder/annotation/SmallTest.java
rename to test-base/src/android/test/suitebuilder/annotation/SmallTest.java
diff --git a/legacy-test/src/android/test/suitebuilder/annotation/Smoke.java b/test-base/src/android/test/suitebuilder/annotation/Smoke.java
similarity index 100%
rename from legacy-test/src/android/test/suitebuilder/annotation/Smoke.java
rename to test-base/src/android/test/suitebuilder/annotation/Smoke.java
diff --git a/legacy-test/src/android/test/suitebuilder/annotation/Suppress.java b/test-base/src/android/test/suitebuilder/annotation/Suppress.java
similarity index 100%
rename from legacy-test/src/android/test/suitebuilder/annotation/Suppress.java
rename to test-base/src/android/test/suitebuilder/annotation/Suppress.java
diff --git a/legacy-test/src/android/test/suitebuilder/annotation/package.html b/test-base/src/android/test/suitebuilder/annotation/package.html
similarity index 100%
rename from legacy-test/src/android/test/suitebuilder/annotation/package.html
rename to test-base/src/android/test/suitebuilder/annotation/package.html
diff --git a/legacy-test/src/com/android/internal/util/Predicate.java b/test-base/src/com/android/internal/util/Predicate.java
similarity index 100%
rename from legacy-test/src/com/android/internal/util/Predicate.java
rename to test-base/src/com/android/internal/util/Predicate.java
diff --git a/legacy-test/src/junit/MODULE_LICENSE_CPL b/test-base/src/junit/MODULE_LICENSE_CPL
similarity index 100%
rename from legacy-test/src/junit/MODULE_LICENSE_CPL
rename to test-base/src/junit/MODULE_LICENSE_CPL
diff --git a/legacy-test/src/junit/README.android b/test-base/src/junit/README.android
similarity index 100%
rename from legacy-test/src/junit/README.android
rename to test-base/src/junit/README.android
diff --git a/legacy-test/src/junit/cpl-v10.html b/test-base/src/junit/cpl-v10.html
similarity index 100%
rename from legacy-test/src/junit/cpl-v10.html
rename to test-base/src/junit/cpl-v10.html
diff --git a/legacy-test/src/junit/framework/Assert.java b/test-base/src/junit/framework/Assert.java
similarity index 100%
rename from legacy-test/src/junit/framework/Assert.java
rename to test-base/src/junit/framework/Assert.java
diff --git a/legacy-test/src/junit/framework/AssertionFailedError.java b/test-base/src/junit/framework/AssertionFailedError.java
similarity index 100%
rename from legacy-test/src/junit/framework/AssertionFailedError.java
rename to test-base/src/junit/framework/AssertionFailedError.java
diff --git a/legacy-test/src/junit/framework/ComparisonCompactor.java b/test-base/src/junit/framework/ComparisonCompactor.java
similarity index 100%
rename from legacy-test/src/junit/framework/ComparisonCompactor.java
rename to test-base/src/junit/framework/ComparisonCompactor.java
diff --git a/legacy-test/src/junit/framework/ComparisonFailure.java b/test-base/src/junit/framework/ComparisonFailure.java
similarity index 100%
rename from legacy-test/src/junit/framework/ComparisonFailure.java
rename to test-base/src/junit/framework/ComparisonFailure.java
diff --git a/legacy-test/src/junit/framework/Protectable.java b/test-base/src/junit/framework/Protectable.java
similarity index 100%
rename from legacy-test/src/junit/framework/Protectable.java
rename to test-base/src/junit/framework/Protectable.java
diff --git a/legacy-test/src/junit/framework/Test.java b/test-base/src/junit/framework/Test.java
similarity index 100%
rename from legacy-test/src/junit/framework/Test.java
rename to test-base/src/junit/framework/Test.java
diff --git a/legacy-test/src/junit/framework/TestCase.java b/test-base/src/junit/framework/TestCase.java
similarity index 100%
rename from legacy-test/src/junit/framework/TestCase.java
rename to test-base/src/junit/framework/TestCase.java
diff --git a/legacy-test/src/junit/framework/TestFailure.java b/test-base/src/junit/framework/TestFailure.java
similarity index 100%
rename from legacy-test/src/junit/framework/TestFailure.java
rename to test-base/src/junit/framework/TestFailure.java
diff --git a/legacy-test/src/junit/framework/TestListener.java b/test-base/src/junit/framework/TestListener.java
similarity index 100%
rename from legacy-test/src/junit/framework/TestListener.java
rename to test-base/src/junit/framework/TestListener.java
diff --git a/legacy-test/src/junit/framework/TestResult.java b/test-base/src/junit/framework/TestResult.java
similarity index 100%
rename from legacy-test/src/junit/framework/TestResult.java
rename to test-base/src/junit/framework/TestResult.java
diff --git a/legacy-test/src/junit/framework/TestSuite.java b/test-base/src/junit/framework/TestSuite.java
similarity index 100%
rename from legacy-test/src/junit/framework/TestSuite.java
rename to test-base/src/junit/framework/TestSuite.java
diff --git a/test-mock/Android.mk b/test-mock/Android.mk
index 18da8b8..e4af17c 100644
--- a/test-mock/Android.mk
+++ b/test-mock/Android.mk
@@ -26,7 +26,7 @@
 
 LOCAL_JAVA_LIBRARIES := core-oj core-libart framework legacy-test
 
-LOCAL_JARJAR_RULES := $(LOCAL_PATH)/../legacy-test/jarjar-rules.txt
+LOCAL_JARJAR_RULES := $(LOCAL_PATH)/../test-base/jarjar-rules.txt
 
 LOCAL_MODULE:= repackaged.android.test.mock
 
@@ -130,15 +130,4 @@
 	@echo Copying removed.txt
 	$(hide) $(ACP) $(ANDROID_TEST_MOCK_OUTPUT_REMOVED_API_FILE) $(ANDROID_TEST_MOCK_REMOVED_API_FILE)
 
-# Build the android.test.mock.sdk library
-# =======================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := android.test.mock.sdk
-LOCAL_SDK_VERSION := current
-
-LOCAL_STATIC_JAVA_LIBRARIES := android.test.mock.stubs
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
 endif  # not TARGET_BUILD_APPS not TARGET_BUILD_PDK=true
diff --git a/test-runner/Android.mk b/test-runner/Android.mk
index d0f5b32..c0fd7f8 100644
--- a/test-runner/Android.mk
+++ b/test-runner/Android.mk
@@ -46,7 +46,7 @@
     legacy-test \
     android.test.mock \
 
-LOCAL_JARJAR_RULES := $(LOCAL_PATH)/../legacy-test/jarjar-rules.txt
+LOCAL_JARJAR_RULES := $(LOCAL_PATH)/../test-base/jarjar-rules.txt
 
 LOCAL_MODULE:= repackaged.android.test.runner
 
diff --git a/test-runner/api/android-test-runner-current.txt b/test-runner/api/android-test-runner-current.txt
index 905cfe7..1170eb5 100644
--- a/test-runner/api/android-test-runner-current.txt
+++ b/test-runner/api/android-test-runner-current.txt
@@ -271,8 +271,6 @@
   public deprecated class TestSuiteBuilder {
     ctor public TestSuiteBuilder(java.lang.Class);
     ctor public TestSuiteBuilder(java.lang.String, java.lang.ClassLoader);
-    method public android.test.suitebuilder.TestSuiteBuilder addRequirements(java.util.List<com.android.internal.util.Predicate<android.test.suitebuilder.TestMethod>>);
-    method public final android.test.suitebuilder.TestSuiteBuilder addRequirements(com.android.internal.util.Predicate<android.test.suitebuilder.TestMethod>...);
     method public final junit.framework.TestSuite build();
     method public android.test.suitebuilder.TestSuiteBuilder excludePackages(java.lang.String...);
     method protected java.lang.String getSuiteName();
diff --git a/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java b/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
index 6158e0c..2857696 100644
--- a/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
+++ b/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
@@ -119,6 +119,7 @@
      *
      * @param predicates Predicates to add to the list of requirements.
      * @return The builder for method chaining.
+     * @hide
      */
     public TestSuiteBuilder addRequirements(List<Predicate<TestMethod>> predicates) {
         this.predicates.addAll(predicates);
@@ -156,7 +157,7 @@
 
     /**
      * Override the default name for the suite being built. This should generally be called if you
-     * call {@link #addRequirements(com.android.internal.util.Predicate[])} to make it clear which
+     * call {@code addRequirements(com.android.internal.util.Predicate[])} to make it clear which
      * tests will be included. The name you specify is automatically prefixed with the package
      * containing the tests to be run. If more than one package is specified, the first is used.
      *
@@ -215,6 +216,7 @@
      *
      * @param predicates Predicates to add to the list of requirements.
      * @return The builder for method chaining.
+     * @hide
      */
     public final TestSuiteBuilder addRequirements(Predicate<TestMethod>... predicates) {
         ArrayList<Predicate<TestMethod>> list = new ArrayList<Predicate<TestMethod>>();
diff --git a/tests/testables/src/android/testing/TestableResources.java b/tests/testables/src/android/testing/TestableResources.java
index a2fa95d..c60f07d 100644
--- a/tests/testables/src/android/testing/TestableResources.java
+++ b/tests/testables/src/android/testing/TestableResources.java
@@ -39,7 +39,8 @@
     private final Resources mResources;
     private final SparseArray<Object> mOverrides = new SparseArray<>();
 
-    TestableResources(Resources realResources) {
+    /** Creates a TestableResources instance that calls through to the given real Resources. */
+    public TestableResources(Resources realResources) {
         mResources = mock(Resources.class, withSettings()
                 .spiedInstance(realResources)
                 .defaultAnswer(this::answer));
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 24187d9..02ac86c 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -707,7 +707,9 @@
           std::unique_ptr<FileReference> file_ref =
               util::make_unique<FileReference>(dst_pool->MakeRef(
                   str, StringPool::Context(StringPool::Context::kHighPriority, config)));
-          if (util::EndsWith(*file_ref->path, ".xml")) {
+          if (type == ResourceType::kRaw) {
+            file_ref->type = ResourceFile::Type::kUnknown;
+          } else if (util::EndsWith(*file_ref->path, ".xml")) {
             file_ref->type = ResourceFile::Type::kBinaryXml;
           } else if (util::EndsWith(*file_ref->path, ".png")) {
             file_ref->type = ResourceFile::Type::kPng;
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index cca1294..423d028 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -18,6 +18,10 @@
 namespace android {
 namespace stats_log_api_gen {
 
+const int PULL_ATOM_START_ID = 1000;
+
+int maxPushedAtomId = 2;
+
 using android::os::statsd::Atom;
 
 // TODO: Support WorkSources
@@ -195,12 +199,18 @@
         fprintf(out, "     */\n");
         char const* const comma = (i == atoms.decls.size() - 1) ? "" : ",";
         fprintf(out, "    %s = %d%s\n", constant.c_str(), atom->code, comma);
+        if (atom->code < PULL_ATOM_START_ID && atom->code > maxPushedAtomId) {
+            maxPushedAtomId = atom->code;
+        }
         i++;
     }
     fprintf(out, "\n");
     fprintf(out, "};\n");
     fprintf(out, "\n");
 
+    fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n",
+            maxPushedAtomId);
+
     // Print write methods
     fprintf(out, "//\n");
     fprintf(out, "// Write methods\n");
diff --git a/wifi/java/android/net/wifi/BatchedScanResult.java b/wifi/java/android/net/wifi/BatchedScanResult.java
index 6d9f00f..c06543e 100644
--- a/wifi/java/android/net/wifi/BatchedScanResult.java
+++ b/wifi/java/android/net/wifi/BatchedScanResult.java
@@ -17,6 +17,7 @@
 package android.net.wifi;
 
 import android.os.Parcelable;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 
 import java.util.ArrayList;
@@ -29,6 +30,7 @@
  * @removed
  */
 @Deprecated
+@SystemApi
 public class BatchedScanResult implements Parcelable {
     private static final String TAG = "BatchedScanResult";
 
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index a9e1e9d..abbb82a 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -21,6 +21,7 @@
 
 import android.net.wifi.hotspot2.OsuProvider;
 import android.net.wifi.hotspot2.PasspointConfiguration;
+import android.net.wifi.hotspot2.IProvisioningCallback;
 
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiInfo;
@@ -184,5 +185,7 @@
     void restoreBackupData(in byte[] data);
 
     void restoreSupplicantBackupData(in byte[] supplicantData, in byte[] ipConfigData);
+
+    void startSubscriptionProvisioning(in OsuProvider provider, in IProvisioningCallback callback);
 }
 
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 183cf0d..558004c 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -33,6 +33,8 @@
 import android.net.NetworkRequest;
 import android.net.wifi.hotspot2.OsuProvider;
 import android.net.wifi.hotspot2.PasspointConfiguration;
+import android.net.wifi.hotspot2.IProvisioningCallback;
+import android.net.wifi.hotspot2.ProvisioningCallback;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Handler;
@@ -3610,4 +3612,45 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Start subscription provisioning flow
+     * @param provider {@link OsuProvider} to provision with
+     * @param callback {@link ProvisioningCallback} for updates regarding provisioning flow
+     * @hide
+     */
+    public void startSubscriptionProvisioning(OsuProvider provider, ProvisioningCallback callback,
+            @Nullable Handler handler) {
+        Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper();
+        try {
+            mService.startSubscriptionProvisioning(provider,
+                    new ProvisioningCallbackProxy(looper, callback));
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    private static class ProvisioningCallbackProxy extends IProvisioningCallback.Stub {
+        private final Handler mHandler;
+        private final ProvisioningCallback mCallback;
+
+        ProvisioningCallbackProxy(Looper looper, ProvisioningCallback callback) {
+            mHandler = new Handler(looper);
+            mCallback = callback;
+        }
+
+        @Override
+        public void onProvisioningStatus(int status) {
+            mHandler.post(() -> {
+                mCallback.onProvisioningStatus(status);
+            });
+        }
+
+        @Override
+        public void onProvisioningFailure(int status) {
+            mHandler.post(() -> {
+                mCallback.onProvisioningFailure(status);
+            });
+        }
+    }
 }
diff --git a/wifi/java/android/net/wifi/hotspot2/IProvisioningCallback.aidl b/wifi/java/android/net/wifi/hotspot2/IProvisioningCallback.aidl
new file mode 100644
index 0000000..c2cb16a
--- /dev/null
+++ b/wifi/java/android/net/wifi/hotspot2/IProvisioningCallback.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.hotspot2;
+
+/**
+ * Interface for Provisioning callback.
+ *
+ * @hide
+ */
+oneway interface IProvisioningCallback
+{
+    /**
+     * Service to manager callback providing failure notification
+     */
+    void onProvisioningFailure(int status);
+
+    /**
+     * Service to manager callback providing Provisioning status
+     */
+    void onProvisioningStatus(int status);
+}
+
diff --git a/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java b/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java
new file mode 100644
index 0000000..8b86cdd
--- /dev/null
+++ b/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.hotspot2;
+
+import android.os.Handler;
+
+/**
+ * Base class for provisioning callbacks. Should be extended by applications and set when calling
+ * {@link WifiManager#startSubscriptionProvisiong(OsuProvider, ProvisioningCallback, Handler)}.
+ *
+ * @hide
+ */
+public abstract class ProvisioningCallback {
+
+   /**
+     * The reason code for Provisioning Failure due to connection failure to OSU AP.
+     * @hide
+     */
+    public static final int OSU_FAILURE_AP_CONNECTION      = 1;
+
+    /**
+     * The status code for Provisioning flow to indicate connecting to OSU AP
+     * @hide
+     */
+    public static final int OSU_STATUS_AP_CONNECTING       = 1;
+
+    /**
+     * The status code for Provisioning flow to indicate connected to OSU AP
+     * @hide
+     */
+    public static final int OSU_STATUS_AP_CONNECTED        = 2;
+
+    /**
+     * Provisioning status for OSU failure
+     * @param status indicates error condition
+     */
+    public abstract void onProvisioningFailure(int status);
+
+    /**
+     * Provisioning status when OSU is in progress
+     * @param status indicates status of OSU flow
+     */
+    public abstract void onProvisioningStatus(int status);
+}
+