Merge "TextView: Support multiple textAssist menu items."
diff --git a/api/current.txt b/api/current.txt
index 8b3c740..55f8751 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -40445,6 +40445,8 @@
     field public static final int ENCODING_7BIT = 1; // 0x1
     field public static final int ENCODING_8BIT = 2; // 0x2
     field public static final int ENCODING_UNKNOWN = 0; // 0x0
+    field public static final java.lang.String FORMAT_3GPP = "3gpp";
+    field public static final java.lang.String FORMAT_3GPP2 = "3gpp2";
     field public static final int MAX_USER_DATA_BYTES = 140; // 0x8c
     field public static final int MAX_USER_DATA_BYTES_WITH_HEADER = 134; // 0x86
     field public static final int MAX_USER_DATA_SEPTETS = 160; // 0xa0
diff --git a/api/system-current.txt b/api/system-current.txt
index ee23b6d..c6a6fdd 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -43965,6 +43965,8 @@
     field public static final int ENCODING_7BIT = 1; // 0x1
     field public static final int ENCODING_8BIT = 2; // 0x2
     field public static final int ENCODING_UNKNOWN = 0; // 0x0
+    field public static final java.lang.String FORMAT_3GPP = "3gpp";
+    field public static final java.lang.String FORMAT_3GPP2 = "3gpp2";
     field public static final int MAX_USER_DATA_BYTES = 140; // 0x8c
     field public static final int MAX_USER_DATA_BYTES_WITH_HEADER = 134; // 0x86
     field public static final int MAX_USER_DATA_SEPTETS = 160; // 0xa0
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 639877f..e9afa70 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -330,7 +330,6 @@
     method public deprecated java.util.List<android.net.wifi.BatchedScanResult> getBatchedScanResults();
     method public android.net.wifi.WifiConnectionStatistics getConnectionStatistics();
     method public deprecated boolean isBatchedScanSupported();
-    method public deprecated boolean setWifiApEnabled(android.net.wifi.WifiConfiguration, boolean);
     method public deprecated boolean startLocationRestrictedScan(android.os.WorkSource);
   }
 
diff --git a/api/test-current.txt b/api/test-current.txt
index 9a241ad..5e55bc3 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -32046,17 +32046,18 @@
   public static final class StrictMode.ViolationInfo implements android.os.Parcelable {
     ctor public StrictMode.ViolationInfo();
     ctor public StrictMode.ViolationInfo(java.lang.Throwable, int);
-    ctor public StrictMode.ViolationInfo(java.lang.String, java.lang.Throwable, int);
+    ctor public deprecated StrictMode.ViolationInfo(java.lang.String, java.lang.Throwable, int);
     ctor public StrictMode.ViolationInfo(android.os.Parcel);
     ctor public StrictMode.ViolationInfo(android.os.Parcel, boolean);
     method public int describeContents();
     method public void dump(android.util.Printer, java.lang.String);
+    method public java.lang.String getMessagePrefix();
+    method public java.lang.String getStackTrace();
+    method public java.lang.String getViolationDetails();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.os.StrictMode.ViolationInfo> CREATOR;
     field public java.lang.String broadcastIntentAction;
-    field public final android.app.ApplicationErrorReport.CrashInfo crashInfo;
     field public int durationMillis;
-    field public final java.lang.String message;
     field public int numAnimationsRunning;
     field public long numInstances;
     field public final int policy;
@@ -40840,6 +40841,8 @@
     field public static final int ENCODING_7BIT = 1; // 0x1
     field public static final int ENCODING_8BIT = 2; // 0x2
     field public static final int ENCODING_UNKNOWN = 0; // 0x0
+    field public static final java.lang.String FORMAT_3GPP = "3gpp";
+    field public static final java.lang.String FORMAT_3GPP2 = "3gpp2";
     field public static final int MAX_USER_DATA_BYTES = 140; // 0x8c
     field public static final int MAX_USER_DATA_BYTES_WITH_HEADER = 134; // 0x86
     field public static final int MAX_USER_DATA_SEPTETS = 160; // 0xa0
diff --git a/cmds/incidentd/tests/Reporter_test.cpp b/cmds/incidentd/tests/Reporter_test.cpp
index 5d074bc..8d99fc7 100644
--- a/cmds/incidentd/tests/Reporter_test.cpp
+++ b/cmds/incidentd/tests/Reporter_test.cpp
@@ -32,8 +32,6 @@
 using namespace std;
 using ::testing::StrEq;
 using ::testing::Test;
-using ::testing::internal::CaptureStdout;
-using ::testing::internal::GetCapturedStdout;
 
 class TestListener : public IIncidentReportStatusListener
 {
@@ -139,20 +137,24 @@
 }
 
 TEST_F(ReporterTest, RunReportWithHeaders) {
+    TemporaryFile tf;
     IncidentReportArgs args1, args2;
     args1.addSection(1);
     args2.addSection(2);
     std::vector<int8_t> header {'a', 'b', 'c', 'd', 'e'};
     args2.addHeader(header);
-    sp<ReportRequest> r1 = new ReportRequest(args1, l, STDOUT_FILENO);
-    sp<ReportRequest> r2 = new ReportRequest(args2, l, STDOUT_FILENO);
+    sp<ReportRequest> r1 = new ReportRequest(args1, l, tf.fd);
+    sp<ReportRequest> r2 = new ReportRequest(args2, l, tf.fd);
 
     reporter->batch.add(r1);
     reporter->batch.add(r2);
 
-    CaptureStdout();
     ASSERT_EQ(Reporter::REPORT_FINISHED, reporter->runReport());
-    EXPECT_THAT(GetCapturedStdout(), StrEq("\n\x5" "abcde"));
+
+    string result;
+    ReadFileToString(tf.path, &result);
+    EXPECT_THAT(result, StrEq("\n\x5" "abcde"));
+
     EXPECT_EQ(l->startInvoked, 2);
     EXPECT_EQ(l->finishInvoked, 2);
     EXPECT_TRUE(l->startSections.empty());
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 8946aed..dd9a965 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -38,6 +38,7 @@
     src/matchers/SimpleLogMatchingTracker.cpp \
     src/metrics/CountAnomalyTracker.cpp \
     src/metrics/MetricProducer.cpp \
+    src/metrics/EventMetricProducer.cpp \
     src/metrics/CountMetricProducer.cpp \
     src/metrics/DurationMetricProducer.cpp \
     src/metrics/MetricsManager.cpp \
@@ -65,7 +66,8 @@
     libselinux \
     libutils \
     libservices \
-    libandroidfw
+    libandroidfw \
+    libprotoutil
 
 # =========
 # statsd
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
index bde3846..aff4768 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include "SimpleConditionTracker.h"
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index 9ca7d62..c16971a 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -120,7 +120,7 @@
 
     int WAKE_LOCK_TAG_ID = 11;
     int WAKE_LOCK_UID_KEY_ID = 1;
-    int WAKE_LOCK_STATE_KEY = 2;
+    int WAKE_LOCK_STATE_KEY = 3;
     int WAKE_LOCK_ACQUIRE_VALUE = 1;
     int WAKE_LOCK_RELEASE_VALUE = 0;
 
@@ -167,7 +167,7 @@
     keyMatcher->set_key(UID_PROCESS_STATE_UID_KEY);
     metric->set_condition("SCREEN_IS_OFF");
 
-    // Count wake lock, slice by uid, while SCREEN_IS_OFF and app in background
+    // Count wake lock, slice by uid, while SCREEN_IS_ON and app in background
     metric = config.add_count_metric();
     metric->set_metric_id(4);
     metric->set_what("APP_GET_WL");
@@ -195,6 +195,11 @@
     link->add_key_in_main()->set_key(WAKE_LOCK_UID_KEY_ID);
     link->add_key_in_condition()->set_key(APP_USAGE_UID_KEY_ID);
 
+    // Add an EventMetric to log process state change events.
+    EventMetric* eventMetric = config.add_event_metric();
+    eventMetric->set_metric_id(6);
+    eventMetric->set_what("SCREEN_TURNED_ON");
+
     // Event matchers............
     LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
     eventMatcher->set_name("SCREEN_TURNED_ON");
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index fb992c1..1a039f6 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -17,6 +17,7 @@
 #include "logd/LogEvent.h"
 
 #include <sstream>
+#include "stats_util.h"
 
 namespace android {
 namespace os {
@@ -24,6 +25,7 @@
 
 using std::ostringstream;
 using std::string;
+using android::util::ProtoOutputStream;
 
 // We need to keep a copy of the android_log_event_list owned by this instance so that the char*
 // for strings is not cleared before we can read them.
@@ -203,30 +205,24 @@
     return result.str();
 }
 
-void LogEvent::ToProto(EventMetricData* out) const {
-    // TODO: Implement this when we have the ProtoOutputStream version.
-
-    // set timestamp of the event.
-    out->set_timestamp_nanos(mTimestampNs);
-
-    // uint64_t token = proto->StartObject(EventMetricData.FIELD);
+void LogEvent::ToProto(ProtoOutputStream& proto) const {
+    long long atomToken = proto.start(TYPE_MESSAGE + mTagId);
     const size_t N = mElements.size();
     for (size_t i=0; i<N; i++) {
         const int key = i + 1;
 
         const android_log_list_element& elem = mElements[i];
         if (elem.type == EVENT_TYPE_INT) {
-            // proto->Write(key, elem.data.int32);
+            proto.write(TYPE_INT32 + key, elem.data.int32);
         } else if (elem.type == EVENT_TYPE_LONG) {
-            // proto->Write(key, elem.data.int64);
+            proto.write(TYPE_INT64 + key, (long long)elem.data.int64);
         } else if (elem.type == EVENT_TYPE_FLOAT) {
-            // proto->Write(key, elem.data.float32);
+            proto.write(TYPE_FLOAT + key, elem.data.float32);
         } else if (elem.type == EVENT_TYPE_STRING) {
-            // proto->Write(key, elem.data.string);
+            proto.write(TYPE_STRING + key, elem.data.string);
         }
     }
-
-    //proto->EndObject(token);
+    proto.end(atomToken);
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 4102675..9ef20ea 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -18,9 +18,10 @@
 
 #include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
 
-#include <utils/Errors.h>
+#include <android/util/ProtoOutputStream.h>
 #include <log/log_event_list.h>
 #include <log/log_read.h>
+#include <utils/Errors.h>
 
 #include <memory>
 #include <string>
@@ -80,10 +81,9 @@
     string ToString() const;
 
     /**
-     * Write this object as an EventMetricData proto object.
-     * TODO: Use the streaming output generator to do this instead of this proto lite object?
+     * Write this object to a ProtoOutputStream.
      */
-    void ToProto(EventMetricData* out) const;
+    void ToProto(android::util::ProtoOutputStream& out) const;
 
     /*
      * Get a KeyValuePair proto object.
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
new file mode 100644
index 0000000..8b3f405
--- /dev/null
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ */
+
+#define DEBUG true  // STOPSHIP if true
+#include "Log.h"
+
+#include "EventMetricProducer.h"
+#include "stats_util.h"
+
+#include <cutils/log.h>
+#include <limits.h>
+#include <stdlib.h>
+
+using android::util::ProtoOutputStream;
+using std::map;
+using std::string;
+using std::unordered_map;
+using std::vector;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+// for StatsLogReport
+const int FIELD_ID_METRIC_ID = 1;
+const int FIELD_ID_START_REPORT_NANOS = 2;
+const int FIELD_ID_END_REPORT_NANOS = 2;
+const int FIELD_ID_EVENT_METRICS = 4;
+// for EventMetricData
+const int FIELD_ID_TIMESTAMP_NANOS = 1;
+const int FIELD_ID_STATS_EVENTS = 2;
+// for CountMetricDataWrapper
+const int FIELD_ID_DATA = 1;
+
+EventMetricProducer::EventMetricProducer(const EventMetric& metric, const int conditionIndex,
+                                         const sp<ConditionWizard>& wizard)
+    // TODO: Pass in the start time from MetricsManager, instead of calling time() here.
+    : MetricProducer((time(nullptr) * NANO_SECONDS_IN_A_SECOND), conditionIndex, wizard),
+      mMetric(metric) {
+    if (metric.links().size() > 0) {
+        mConditionLinks.insert(mConditionLinks.begin(), metric.links().begin(),
+                               metric.links().end());
+        mConditionSliced = true;
+    }
+
+    startNewProtoOutputStream(mStartTimeNs);
+
+    VLOG("metric %lld created. bucket size %lld start_time: %lld", metric.metric_id(),
+         (long long)mBucketSizeNs, (long long)mStartTimeNs);
+}
+
+EventMetricProducer::~EventMetricProducer() {
+    VLOG("~EventMetricProducer() called");
+}
+
+void EventMetricProducer::startNewProtoOutputStream(long long startTime) {
+    mProto = std::make_unique<ProtoOutputStream>();
+    // TODO: We need to auto-generate the field IDs for StatsLogReport, EventMetricData,
+    // and StatsEvent.
+    mProto->write(TYPE_INT32 + FIELD_ID_METRIC_ID, mMetric.metric_id());
+    mProto->write(TYPE_INT64 + FIELD_ID_START_REPORT_NANOS, startTime);
+    mProtoToken = mProto->start(TYPE_MESSAGE + FIELD_ID_EVENT_METRICS);
+}
+
+void EventMetricProducer::finish() {
+}
+
+void EventMetricProducer::onSlicedConditionMayChange() {
+}
+
+StatsLogReport EventMetricProducer::onDumpReport() {
+    long long endTime = time(nullptr) * NANO_SECONDS_IN_A_SECOND;
+    mProto->end(mProtoToken);
+    mProto->write(TYPE_INT64 + FIELD_ID_END_REPORT_NANOS, endTime);
+
+    size_t bufferSize = mProto->size();
+    VLOG("metric %lld dump report now... proto size: %zu ", mMetric.metric_id(), bufferSize);
+    std::unique_ptr<uint8_t[]> buffer(new uint8_t[bufferSize]);
+    size_t pos = 0;
+    auto it = mProto->data();
+    while (it.readBuffer() != NULL) {
+        size_t toRead = it.currentToRead();
+        std::memcpy(&buffer[pos], it.readBuffer(), toRead);
+        pos += toRead;
+        it.rp()->move(toRead);
+    }
+
+    startNewProtoOutputStream(endTime);
+
+    // TODO: Once we migrate all MetricProducers to use ProtoOutputStream, we should return this:
+    // return std::move(buffer);
+    return StatsLogReport();
+}
+
+void EventMetricProducer::onConditionChanged(const bool conditionMet) {
+    VLOG("Metric %lld onConditionChanged", mMetric.metric_id());
+    mCondition = conditionMet;
+}
+
+void EventMetricProducer::onMatchedLogEventInternal(
+        const size_t matcherIndex, const HashableDimensionKey& eventKey,
+        const std::map<std::string, HashableDimensionKey>& conditionKey, bool condition,
+        const LogEvent& event) {
+
+    if (!condition) {
+        return;
+    }
+
+    long long wrapperToken = mProto->start(TYPE_MESSAGE + FIELD_ID_DATA);
+    mProto->write(TYPE_INT64 + FIELD_ID_TIMESTAMP_NANOS, (long long)event.GetTimestampNs());
+    long long eventToken = mProto->start(TYPE_MESSAGE + FIELD_ID_STATS_EVENTS);
+    event.ToProto(*mProto);
+    mProto->end(eventToken);
+    mProto->end(wrapperToken);
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
new file mode 100644
index 0000000..879175c
--- /dev/null
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+#ifndef EVENT_METRIC_PRODUCER_H
+#define EVENT_METRIC_PRODUCER_H
+
+#include <unordered_map>
+
+#include <android/util/ProtoOutputStream.h>
+#include "../condition/ConditionTracker.h"
+#include "../matchers/matcher_util.h"
+#include "MetricProducer.h"
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "stats_util.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+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);
+
+    virtual ~EventMetricProducer();
+
+    void onMatchedLogEventInternal(const size_t matcherIndex, const HashableDimensionKey& eventKey,
+                                   const std::map<std::string, HashableDimensionKey>& conditionKey,
+                                   bool condition, const LogEvent& event) override;
+
+    void onConditionChanged(const bool conditionMet) override;
+
+    void finish() override;
+
+    StatsLogReport onDumpReport() override;
+
+    void onSlicedConditionMayChange() override;
+
+    // TODO: Implement this later.
+    virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{};
+
+private:
+    const EventMetric mMetric;
+
+    std::unique_ptr<android::util::ProtoOutputStream> mProto;
+
+    long long mProtoToken;
+
+    void startNewProtoOutputStream(long long timestamp);
+};
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
+#endif  // EVENT_METRIC_PRODUCER_H
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 23071aa..e90f998 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -20,6 +20,7 @@
 #include "../matchers/SimpleLogMatchingTracker.h"
 #include "CountMetricProducer.h"
 #include "DurationMetricProducer.h"
+#include "EventMetricProducer.h"
 #include "stats_util.h"
 
 using std::set;
@@ -31,13 +32,51 @@
 namespace os {
 namespace statsd {
 
-int getTrackerIndex(const string& name, const unordered_map<string, int>& logTrackerMap) {
-    auto logTrackerIt = logTrackerMap.find(name);
+bool handleMetricWithLogTrackers(const string what, const int metricIndex,
+                                 const unordered_map<string, int>& logTrackerMap,
+                                 unordered_map<int, std::vector<int>>& trackerToMetricMap,
+                                 int& logTrackerIndex) {
+    auto logTrackerIt = logTrackerMap.find(what);
     if (logTrackerIt == logTrackerMap.end()) {
-        ALOGW("cannot find the LogEventMatcher %s in config", name.c_str());
-        return MATCHER_NOT_FOUND;
+        ALOGW("cannot find the LogEntryMatcher %s in config", what.c_str());
+        return false;
     }
-    return logTrackerIt->second;
+    logTrackerIndex = logTrackerIt->second;
+    auto& metric_list = trackerToMetricMap[logTrackerIndex];
+    metric_list.push_back(metricIndex);
+    return true;
+}
+
+bool handleMetricWithConditions(
+        const string condition, const int metricIndex,
+        const unordered_map<string, int>& conditionTrackerMap,
+        const ::google::protobuf::RepeatedPtrField<::android::os::statsd::EventConditionLink>&
+                links,
+        vector<sp<ConditionTracker>>& allConditionTrackers, int& conditionIndex,
+        unordered_map<int, std::vector<int>>& conditionToMetricMap) {
+    auto condition_it = conditionTrackerMap.find(condition);
+    if (condition_it == conditionTrackerMap.end()) {
+        ALOGW("cannot find the Condition %s in the config", condition.c_str());
+        return false;
+    }
+
+    for (const auto& link : links) {
+        auto it = conditionTrackerMap.find(link.condition());
+        if (it == conditionTrackerMap.end()) {
+            ALOGW("cannot find the Condition %s in the config", link.condition().c_str());
+            return false;
+        }
+        allConditionTrackers[condition_it->second]->setSliced(true);
+        allConditionTrackers[it->second]->setSliced(true);
+        allConditionTrackers[it->second]->addDimensions(
+                vector<KeyMatcher>(link.key_in_condition().begin(), link.key_in_condition().end()));
+    }
+    conditionIndex = condition_it->second;
+
+    // will create new vector if not exist before.
+    auto& metricList = conditionToMetricMap[condition_it->second];
+    metricList.push_back(metricIndex);
+    return true;
 }
 
 bool initLogTrackers(const StatsdConfig& config, unordered_map<string, int>& logTrackerMap,
@@ -142,7 +181,8 @@
                  unordered_map<int, std::vector<int>>& conditionToMetricMap,
                  unordered_map<int, std::vector<int>>& trackerToMetricMap) {
     sp<ConditionWizard> wizard = new ConditionWizard(allConditionTrackers);
-    const int allMetricsCount = config.count_metric_size() + config.duration_metric_size();
+    const int allMetricsCount =
+            config.count_metric_size() + config.duration_metric_size() + config.event_metric_size();
     allMetricProducers.reserve(allMetricsCount);
 
     // Build MetricProducers for each metric defined in config.
@@ -155,100 +195,52 @@
         }
 
         int metricIndex = allMetricProducers.size();
-
-        auto logTrackerIt = logTrackerMap.find(metric.what());
-        if (logTrackerIt == logTrackerMap.end()) {
-            ALOGW("cannot find the LogEntryMatcher %s in config", metric.what().c_str());
+        int trackerIndex;
+        if (!handleMetricWithLogTrackers(metric.what(), metricIndex, logTrackerMap,
+                                         trackerToMetricMap, trackerIndex)) {
             return false;
         }
-        int logTrackerIndex = logTrackerIt->second;
-        auto& metric_list = trackerToMetricMap[logTrackerIndex];
-        metric_list.push_back(metricIndex);
 
-        sp<MetricProducer> countProducer;
-
+        int conditionIndex = -1;
         if (metric.has_condition()) {
-            auto condition_it = conditionTrackerMap.find(metric.condition());
-            if (condition_it == conditionTrackerMap.end()) {
-                ALOGW("cannot find the Condition %s in the config", metric.condition().c_str());
-                return false;
-            }
-
-            for (const auto& link : metric.links()) {
-                auto it = conditionTrackerMap.find(link.condition());
-                if (it == conditionTrackerMap.end()) {
-                    ALOGW("cannot find the Condition %s in the config", link.condition().c_str());
-                    return false;
-                }
-                allConditionTrackers[condition_it->second]->setSliced(true);
-                allConditionTrackers[it->second]->setSliced(true);
-                allConditionTrackers[it->second]->addDimensions(vector<KeyMatcher>(
-                        link.key_in_condition().begin(), link.key_in_condition().end()));
-            }
-
-            countProducer = new CountMetricProducer(metric, condition_it->second, wizard);
-            // will create new vector if not exist before.
-            auto& metricList = conditionToMetricMap[condition_it->second];
-            metricList.push_back(metricIndex);
-        } else {
-            countProducer = new CountMetricProducer(metric, -1 /*no condition*/, wizard);
+            handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
+                                       metric.links(), allConditionTrackers, conditionIndex,
+                                       conditionToMetricMap);
         }
+
+        sp<MetricProducer> countProducer = new CountMetricProducer(metric, conditionIndex, wizard);
         allMetricProducers.push_back(countProducer);
     }
 
     for (int i = 0; i < config.duration_metric_size(); i++) {
         int metricIndex = allMetricProducers.size();
-        const DurationMetric metric = config.duration_metric(i);
-        if (!metric.has_start()) {
-            ALOGW("cannot find start in DurationMetric %lld", metric.metric_id());
+        const DurationMetric& metric = config.duration_metric(i);
+        int trackerIndices[3] = {-1, -1, -1};
+        if (!metric.has_start() ||
+            !handleMetricWithLogTrackers(metric.start(), metricIndex, logTrackerMap,
+                                         trackerToMetricMap, trackerIndices[0])) {
+            ALOGE("Duration metrics must specify a valid the start event matcher");
             return false;
         }
 
-        int trackerIndices[] = {-1, -1, -1};
-        trackerIndices[0] = getTrackerIndex(metric.start(), logTrackerMap);
-
-        if (metric.has_stop()) {
-            trackerIndices[1] = getTrackerIndex(metric.stop(), logTrackerMap);
+        if (metric.has_stop() &&
+            !handleMetricWithLogTrackers(metric.stop(), metricIndex, logTrackerMap,
+                                         trackerToMetricMap, trackerIndices[1])) {
+            return false;
         }
 
-        if (metric.has_stop_all()) {
-            trackerIndices[2] = getTrackerIndex(metric.stop_all(), logTrackerMap);
-        }
-
-        for (const int& index : trackerIndices) {
-            if (index == MATCHER_NOT_FOUND) {
-                return false;
-            }
-            if (index >= 0) {
-                auto& metric_list = trackerToMetricMap[index];
-                metric_list.push_back(metricIndex);
-            }
+        if (metric.has_stop_all() &&
+            !handleMetricWithLogTrackers(metric.stop_all(), metricIndex, logTrackerMap,
+                                         trackerToMetricMap, trackerIndices[2])) {
+            return false;
         }
 
         int conditionIndex = -1;
 
         if (metric.has_predicate()) {
-            auto condition_it = conditionTrackerMap.find(metric.predicate());
-            if (condition_it == conditionTrackerMap.end()) {
-                ALOGW("cannot find the Condition %s in the config", metric.predicate().c_str());
-                return false;
-            }
-            conditionIndex = condition_it->second;
-
-            for (const auto& link : metric.links()) {
-                auto it = conditionTrackerMap.find(link.condition());
-                if (it == conditionTrackerMap.end()) {
-                    ALOGW("cannot find the Condition %s in the config", link.condition().c_str());
-                    return false;
-                }
-                allConditionTrackers[condition_it->second]->setSliced(true);
-                allConditionTrackers[it->second]->setSliced(true);
-                allConditionTrackers[it->second]->addDimensions(vector<KeyMatcher>(
-                        link.key_in_condition().begin(), link.key_in_condition().end()));
-            }
-
-            auto& metricList = conditionToMetricMap[conditionIndex];
-            metricList.push_back(metricIndex);
+            handleMetricWithConditions(metric.predicate(), metricIndex, conditionTrackerMap,
+                                       metric.links(), allConditionTrackers, conditionIndex,
+                                       conditionToMetricMap);
         }
 
         sp<MetricProducer> durationMetric =
@@ -257,6 +249,32 @@
 
         allMetricProducers.push_back(durationMetric);
     }
+
+    for (int i = 0; i < config.event_metric_size(); i++) {
+        int metricIndex = allMetricProducers.size();
+        const EventMetric& metric = config.event_metric(i);
+        if (!metric.has_metric_id() || !metric.has_what()) {
+            ALOGW("cannot find the metric id or what in config");
+            return false;
+        }
+        int trackerIndex;
+        if (!handleMetricWithLogTrackers(metric.what(), metricIndex, logTrackerMap,
+                                         trackerToMetricMap, trackerIndex)) {
+            return false;
+        }
+
+        int conditionIndex = -1;
+        if (metric.has_condition()) {
+            handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
+                                       metric.links(), allConditionTrackers, conditionIndex,
+                                       conditionToMetricMap);
+        }
+
+        sp<MetricProducer> eventMetric = new EventMetricProducer(metric, conditionIndex, wizard);
+
+        allMetricProducers.push_back(eventMetric);
+    }
+
     return true;
 }
 
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h
index f23df9f..6722eb3 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/metrics_manager_util.h
@@ -22,7 +22,6 @@
 
 #include "../condition/ConditionTracker.h"
 #include "../matchers/LogMatchingTracker.h"
-#include "CountMetricProducer.h"
 
 namespace android {
 namespace os {
@@ -91,8 +90,6 @@
                       std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
                       std::unordered_map<int, std::vector<int>>& trackerToConditionMap);
 
-int getTrackerIndex(const std::string& name, const std::unordered_map<string, int>& logTrackerMap);
-
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/stats_util.h b/cmds/statsd/src/stats_util.h
index 575588b..39c1d59 100644
--- a/cmds/statsd/src/stats_util.h
+++ b/cmds/statsd/src/stats_util.h
@@ -30,6 +30,14 @@
 #define MATCHER_NOT_FOUND -2
 #define NANO_SECONDS_IN_A_SECOND (1000 * 1000 * 1000)
 
+// TODO: Remove the following constants once they are exposed in ProtOutputStream.h
+const uint64_t FIELD_TYPE_SHIFT = 32;
+const uint64_t TYPE_MESSAGE = 11ULL << FIELD_TYPE_SHIFT;
+const uint64_t TYPE_INT64 = 3ULL << FIELD_TYPE_SHIFT;
+const uint64_t TYPE_INT32 = 5ULL << FIELD_TYPE_SHIFT;
+const uint64_t TYPE_FLOAT = 2ULL << FIELD_TYPE_SHIFT;
+const uint64_t TYPE_STRING = 9ULL << FIELD_TYPE_SHIFT;
+
 typedef std::string HashableDimensionKey;
 
 EventMetricData parse(log_msg msg);
diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java
index df87b45..33825b4 100644
--- a/core/java/android/app/slice/SliceProvider.java
+++ b/core/java/android/app/slice/SliceProvider.java
@@ -156,27 +156,34 @@
     }
 
     private Slice handleBindSlice(Uri sliceUri) {
-        Slice[] output = new Slice[1];
-        CountDownLatch latch = new CountDownLatch(1);
-        Handler mainHandler = new Handler(Looper.getMainLooper());
-        mainHandler.post(() -> {
-            ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
-            try {
-                StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
-                        .detectAll()
-                        .penaltyDeath()
-                        .build());
-                output[0] = onBindSlice(sliceUri);
-            } finally {
-                StrictMode.setThreadPolicy(oldPolicy);
+        if (Looper.myLooper() == Looper.getMainLooper()) {
+            return onBindSliceStrict(sliceUri);
+        } else {
+            CountDownLatch latch = new CountDownLatch(1);
+            Slice[] output = new Slice[1];
+            Handler.getMain().post(() -> {
+                output[0] = onBindSliceStrict(sliceUri);
                 latch.countDown();
+            });
+            try {
+                latch.await();
+                return output[0];
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
             }
-        });
+        }
+    }
+
+    private Slice onBindSliceStrict(Uri sliceUri) {
+        ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
         try {
-            latch.await();
-            return output[0];
-        } catch (InterruptedException e) {
-            throw new RuntimeException(e);
+            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
+                    .detectAll()
+                    .penaltyDeath()
+                    .build());
+            return onBindSlice(sliceUri);
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
         }
     }
 }
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index d73f852..dcc6821 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -375,7 +375,7 @@
      * {@code DownloadManager}, {@code MediaPlayer}) will refuse app's requests to use cleartext
      * traffic. Third-party libraries are encouraged to honor this flag as well.
      *
-     * <p>NOTE: {@code WebView} does not honor this flag.
+     * <p>NOTE: {@code WebView} honors this flag for applications targeting API level 26 and up.
      *
      * <p>This flag is ignored on Android N and above if an Android Network Security Config is
      * present.
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 143c51d..7d58658 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -467,7 +467,4 @@
     /** Updates the flags for the given permission. */
     public abstract void updatePermissionFlagsTEMP(@NonNull String permName,
             @NonNull String packageName, int flagMask, int flagValues, int userId);
-    /** Returns a PermissionGroup. */
-    public abstract @Nullable PackageParser.PermissionGroup getPermissionGroupTEMP(
-            @NonNull String groupName);
 }
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 826ec1eb..f52d94e 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -20,7 +20,6 @@
 import android.annotation.TestApi;
 import android.app.ActivityManager;
 import android.app.ActivityThread;
-import android.app.ApplicationErrorReport;
 import android.app.IActivityManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -48,8 +47,10 @@
 import java.io.StringWriter;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Deque;
 import java.util.HashMap;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -352,8 +353,8 @@
                 } else {
                     msg = "StrictMode policy violation:";
                 }
-                if (info.crashInfo != null) {
-                    Log.d(TAG, msg + " " + info.crashInfo.stackTrace);
+                if (info.hasStackTrace()) {
+                    Log.d(TAG, msg + " " + info.getStackTrace());
                 } else {
                     Log.d(TAG, msg + " missing stack trace!");
                 }
@@ -1247,28 +1248,6 @@
         }
     }
 
-    /** Like parsePolicyFromMessage(), but returns the violation. */
-    private static int parseViolationFromMessage(String message) {
-        if (message == null) {
-            return 0;
-        }
-        int violationIndex = message.indexOf("violation=");
-        if (violationIndex == -1) {
-            return 0;
-        }
-        int numberStartIndex = violationIndex + "violation=".length();
-        int numberEndIndex = message.indexOf(' ', numberStartIndex);
-        if (numberEndIndex == -1) {
-            numberEndIndex = message.length();
-        }
-        String violationString = message.substring(numberStartIndex, numberEndIndex);
-        try {
-            return Integer.parseInt(violationString);
-        } catch (NumberFormatException e) {
-            return 0;
-        }
-    }
-
     private static final ThreadLocal<ArrayList<ViolationInfo>> violationsBeingTimed =
             new ThreadLocal<ArrayList<ViolationInfo>>() {
                 @Override
@@ -1516,7 +1495,7 @@
         // to people who push/pop temporary policy in regions of code,
         // hence the policy being passed around.
         void handleViolation(final ViolationInfo info) {
-            if (info == null || info.crashInfo == null || info.crashInfo.stackTrace == null) {
+            if (info == null || !info.hasStackTrace()) {
                 Log.wtf(TAG, "unexpected null stacktrace");
                 return;
             }
@@ -1530,7 +1509,7 @@
                     gatheredViolations.set(violations);
                 }
                 for (ViolationInfo previous : violations) {
-                    if (info.crashInfo.stackTrace.equals(previous.crashInfo.stackTrace)) {
+                    if (info.getStackTrace().equals(previous.getStackTrace())) {
                         // Duplicate. Don't log.
                         return;
                     }
@@ -1576,8 +1555,7 @@
             }
 
             if (violationMaskSubset != 0) {
-                int violationBit = parseViolationFromMessage(info.crashInfo.exceptionMessage);
-                violationMaskSubset |= violationBit;
+                violationMaskSubset |= info.getViolationBit();
                 final int savedPolicyMask = getThreadPolicyMask();
 
                 final boolean justDropBox = (info.policy & THREAD_PENALTY_MASK) == PENALTY_DROPBOX;
@@ -1622,8 +1600,7 @@
     }
 
     private static void executeDeathPenalty(ViolationInfo info) {
-        int violationBit = parseViolationFromMessage(info.crashInfo.exceptionMessage);
-        throw new StrictModeViolation(info.policy, violationBit, null);
+        throw new StrictModeViolation(info.policy, info.getViolationBit(), null);
     }
 
     /**
@@ -2027,21 +2004,14 @@
      * read back all the encoded violations.
      */
     /* package */ static void readAndHandleBinderCallViolations(Parcel p) {
-        // Our own stack trace to append
-        StringWriter sw = new StringWriter();
-        sw.append("# via Binder call with stack:\n");
-        PrintWriter pw = new FastPrintWriter(sw, false, 256);
-        new LogStackTrace().printStackTrace(pw);
-        pw.flush();
-        String ourStack = sw.toString();
-
+        LogStackTrace localCallSite = new LogStackTrace();
         final int policyMask = getThreadPolicyMask();
         final boolean currentlyGathering = (policyMask & PENALTY_GATHER) != 0;
 
         final int size = p.readInt();
         for (int i = 0; i < size; i++) {
             final ViolationInfo info = new ViolationInfo(p, !currentlyGathering);
-            info.crashInfo.appendStackTrace(ourStack);
+            info.addLocalStack(localCallSite);
             BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
             if (policy instanceof AndroidBlockGuardPolicy) {
                 ((AndroidBlockGuardPolicy) policy).handleViolationWithTimingAttempt(info);
@@ -2366,10 +2336,18 @@
      */
     @TestApi
     public static final class ViolationInfo implements Parcelable {
-        public final String message;
+        /** Some VM violations provide additional information outside the throwable. */
+        @Nullable private final String mMessagePrefix;
 
-        /** Stack and other stuff info. */
-        @Nullable public final ApplicationErrorReport.CrashInfo crashInfo;
+        /** Stack and violation details. */
+        @Nullable private final Throwable mThrowable;
+
+        private final Deque<Throwable> mBinderStack = new ArrayDeque<>();
+
+        /** Memoized stack trace of full violation. */
+        @Nullable private String mStackTrace;
+        /** Memoized violation bit. */
+        private int mViolationBit;
 
         /** The strict mode policy mask at the time of violation. */
         public final int policy;
@@ -2404,19 +2382,25 @@
 
         /** Create an uninitialized instance of ViolationInfo */
         public ViolationInfo() {
-            message = null;
-            crashInfo = null;
+            mMessagePrefix = null;
+            mThrowable = null;
             policy = 0;
         }
 
+        /** Create an instance of ViolationInfo. */
         public ViolationInfo(Throwable tr, int policy) {
             this(null, tr, policy);
         }
 
-        /** Create an instance of ViolationInfo initialized from an exception. */
-        public ViolationInfo(String message, Throwable tr, int policy) {
-            this.message = message;
-            crashInfo = new ApplicationErrorReport.CrashInfo(tr);
+        /**
+         * Create an instance of ViolationInfo initialized from an exception with a message prefix.
+         *
+         * @deprecated prefixes belong in the Throwable.
+         */
+        @Deprecated
+        public ViolationInfo(String messagePrefix, Throwable tr, int policy) {
+            this.mMessagePrefix = messagePrefix;
+            this.mThrowable = tr;
             violationUptimeMillis = SystemClock.uptimeMillis();
             this.policy = policy;
             this.numAnimationsRunning = ValueAnimator.getCurrentAnimationsCount();
@@ -2446,11 +2430,101 @@
             }
         }
 
+        /** Equivalent output to {@link ApplicationErrorReport.CrashInfo#stackTrace}. */
+        public String getStackTrace() {
+            if (mThrowable != null && mStackTrace == null) {
+                StringWriter sw = new StringWriter();
+                PrintWriter pw = new FastPrintWriter(sw, false, 256);
+                mThrowable.printStackTrace(pw);
+                for (Throwable t : mBinderStack) {
+                    pw.append("# via Binder call with stack:\n");
+                    t.printStackTrace(pw);
+                }
+                pw.flush();
+                pw.close();
+                mStackTrace = sw.toString();
+            }
+            return mStackTrace;
+        }
+
+        /**
+         * Optional message describing this violation.
+         *
+         * @hide
+         */
+        @TestApi
+        public String getViolationDetails() {
+            if (mThrowable != null) {
+                return mThrowable.getMessage();
+            } else {
+                return "";
+            }
+        }
+
+        /**
+         * A handful of VM violations provide extra information that should be presented before
+         * {@link #getViolationDetails()}.
+         *
+         * @hide
+         */
+        @TestApi
+        public String getMessagePrefix() {
+            return mMessagePrefix != null ? mMessagePrefix : "";
+        }
+
+        /** If this violation has a useful stack trace.
+         *
+         * @hide
+         */
+        public boolean hasStackTrace() {
+            return mThrowable != null;
+        }
+
+        /**
+         * Add a {@link Throwable} from the current process that caused the underlying violation.
+         *
+         * @hide
+         */
+        void addLocalStack(Throwable t) {
+            mBinderStack.addFirst(t);
+        }
+
+        /**
+         * Retrieve the type of StrictMode violation.
+         *
+         * @hide
+         */
+        int getViolationBit() {
+            if (mThrowable == null || mThrowable.getMessage() == null) {
+                return 0;
+            }
+            if (mViolationBit != 0) {
+                return mViolationBit;
+            }
+            String message = mThrowable.getMessage();
+            int violationIndex = message.indexOf("violation=");
+            if (violationIndex == -1) {
+                return 0;
+            }
+            int numberStartIndex = violationIndex + "violation=".length();
+            int numberEndIndex = message.indexOf(' ', numberStartIndex);
+            if (numberEndIndex == -1) {
+                numberEndIndex = message.length();
+            }
+            String violationString = message.substring(numberStartIndex, numberEndIndex);
+            try {
+                mViolationBit = Integer.parseInt(violationString);
+                return mViolationBit;
+            } catch (NumberFormatException e) {
+                return 0;
+            }
+        }
+
         @Override
         public int hashCode() {
             int result = 17;
-            if (crashInfo != null) {
-                result = 37 * result + crashInfo.stackTrace.hashCode();
+            if (mThrowable != null) {
+                result = 37 * result + mThrowable.hashCode();
             }
             if (numAnimationsRunning != 0) {
                 result *= 37;
@@ -2478,11 +2552,11 @@
          *     should be removed.
          */
         public ViolationInfo(Parcel in, boolean unsetGatheringBit) {
-            message = in.readString();
-            if (in.readInt() != 0) {
-                crashInfo = new ApplicationErrorReport.CrashInfo(in);
-            } else {
-                crashInfo = null;
+            mMessagePrefix = in.readString();
+            mThrowable = (Throwable) in.readSerializable();
+            int binderStackSize = in.readInt();
+            for (int i = 0; i < binderStackSize; i++) {
+                mBinderStack.add((Throwable) in.readSerializable());
             }
             int rawPolicy = in.readInt();
             if (unsetGatheringBit) {
@@ -2502,12 +2576,11 @@
         /** Save a ViolationInfo instance to a parcel. */
         @Override
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeString(message);
-            if (crashInfo != null) {
-                dest.writeInt(1);
-                crashInfo.writeToParcel(dest, flags);
-            } else {
-                dest.writeInt(0);
+            dest.writeString(mMessagePrefix);
+            dest.writeSerializable(mThrowable);
+            dest.writeInt(mBinderStack.size());
+            for (Throwable t : mBinderStack) {
+                dest.writeSerializable(t);
             }
             int start = dest.dataPosition();
             dest.writeInt(policy);
@@ -2542,8 +2615,8 @@
 
         /** Dump a ViolationInfo instance to a Printer. */
         public void dump(Printer pw, String prefix) {
-            if (crashInfo != null) {
-                crashInfo.dump(pw, prefix);
+            if (mThrowable != null) {
+                pw.println(prefix + "stackTrace: " + getStackTrace());
             }
             pw.println(prefix + "policy: " + policy);
             if (durationMillis != -1) {
diff --git a/core/java/android/security/NetworkSecurityPolicy.java b/core/java/android/security/NetworkSecurityPolicy.java
index 812c956..0c4eeda 100644
--- a/core/java/android/security/NetworkSecurityPolicy.java
+++ b/core/java/android/security/NetworkSecurityPolicy.java
@@ -16,7 +16,6 @@
 
 package android.security;
 
-import android.annotation.TestApi;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.security.net.config.ApplicationConfig;
@@ -63,7 +62,8 @@
      * traffic from applications is handled by higher-level network stacks/components which can
      * honor this aspect of the policy.
      *
-     * <p>NOTE: {@link android.webkit.WebView} does not honor this flag.
+     * <p>NOTE: {@link android.webkit.WebView} honors this flag for applications targeting API level
+     * 26 and up.
      */
     public boolean isCleartextTrafficPermitted() {
         return libcore.net.NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted();
diff --git a/core/java/android/security/net/config/NetworkSecurityConfig.java b/core/java/android/security/net/config/NetworkSecurityConfig.java
index b9e5505..52f48ef 100644
--- a/core/java/android/security/net/config/NetworkSecurityConfig.java
+++ b/core/java/android/security/net/config/NetworkSecurityConfig.java
@@ -164,7 +164,8 @@
      * <p>
      * The default configuration has the following properties:
      * <ol>
-     * <li>Cleartext traffic is permitted for non-ephemeral apps.</li>
+     * <li>If the application targets API level 27 (Android O MR1) or lower then cleartext traffic
+     * is allowed by default.</li>
      * <li>Cleartext traffic is not permitted for ephemeral apps.</li>
      * <li>HSTS is not enforced.</li>
      * <li>No certificate pinning is used.</li>
@@ -183,7 +184,8 @@
                 // System certificate store, does not bypass static pins.
                 .addCertificatesEntryRef(
                         new CertificatesEntryRef(SystemCertificateSource.getInstance(), false));
-        final boolean cleartextTrafficPermitted = info.targetSandboxVersion < 2;
+        final boolean cleartextTrafficPermitted = info.targetSdkVersion < Build.VERSION_CODES.P
+                && info.targetSandboxVersion < 2;
         builder.setCleartextTrafficPermitted(cleartextTrafficPermitted);
         // Applications targeting N and above must opt in into trusting the user added certificate
         // store.
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index 8c3b8a2..26d2141 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -33,6 +33,52 @@
 
 /**
  * Information for generating a widget to handle classified text.
+ *
+ * <p>A TextClassification object contains icons, labels, onClickListeners and intents that may
+ * be used to build a widget that can be used to act on classified text.
+ *
+ * <p>e.g. building a view that, when clicked, shares the classified text with the preferred app:
+ *
+ * <pre>{@code
+ *   // Called preferably outside the UiThread.
+ *   TextClassification classification = textClassifier.classifyText(allText, 10, 25, null);
+ *
+ *   // Called on the UiThread.
+ *   Button button = new Button(context);
+ *   button.setCompoundDrawablesWithIntrinsicBounds(classification.getIcon(), null, null, null);
+ *   button.setText(classification.getLabel());
+ *   button.setOnClickListener(classification.getOnClickListener());
+ * }</pre>
+ *
+ * <p>e.g. starting an action mode with menu items that can handle the classified text:
+ *
+ * <pre>{@code
+ *   // Called preferably outside the UiThread.
+ *   final TextClassification classification = textClassifier.classifyText(allText, 10, 25, null);
+ *
+ *   // Called on the UiThread.
+ *   view.startActionMode(new ActionMode.Callback() {
+ *
+ *       public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+ *           for (int i = 0; i < classification.getActionCount(); i++) {
+ *               if (thisAppHasPermissionToInvokeIntent(classification.getIntent(i))) {
+ *                   menu.add(Menu.NONE, i, 20, classification.getLabel(i))
+ *                      .setIcon(classification.getIcon(i))
+ *                      .setIntent(classification.getIntent(i));
+ *               }
+ *           }
+ *           return true;
+ *       }
+ *
+ *       public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+ *           context.startActivity(item.getIntent());
+ *           return true;
+ *       }
+ *
+ *       ...
+ *   });
+ * }</pre>
+ *
  */
 public final class TextClassification {
 
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index c3601d9..46dbd0e 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -29,8 +29,8 @@
 /**
  * Interface for providing text classification related features.
  *
- * <p>Unless otherwise stated, methods of this interface are blocking operations and you should
- * avoid calling them on the UI thread.
+ * <p>Unless otherwise stated, methods of this interface are blocking operations.
+ * Avoid calling them on the UI thread.
  */
 public interface TextClassifier {
 
@@ -75,8 +75,8 @@
     };
 
     /**
-     * Returns suggested text selection indices, recognized types and their associated confidence
-     * scores. The selections are ordered from highest to lowest scoring.
+     * Returns suggested text selection start and end indices, recognized entity types, and their
+     * associated confidence scores. The entity types are ordered from highest to lowest scoring.
      *
      * @param text text providing context for the selected text (which is specified
      *      by the sub sequence starting at selectionStartIndex and ending at selectionEndIndex)
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 95cb454..48e427f 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -25,7 +25,6 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.Signature;
-import android.os.Build;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.StrictMode;
@@ -445,38 +444,17 @@
         }
     }
 
-    private static int prepareWebViewInSystemServer(String[] nativeLibraryPaths) {
-        if (DEBUG) Log.v(LOGTAG, "creating relro files");
-        int numRelros = 0;
-
-        // We must always trigger createRelRo regardless of the value of nativeLibraryPaths. Any
-        // unexpected values will be handled there to ensure that we trigger notifying any process
-        // waiting on relro creation.
-        if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
-            if (DEBUG) Log.v(LOGTAG, "Create 32 bit relro");
-            WebViewLibraryLoader.createRelroFile(false /* is64Bit */, nativeLibraryPaths[0]);
-            numRelros++;
-        }
-
-        if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
-            if (DEBUG) Log.v(LOGTAG, "Create 64 bit relro");
-            WebViewLibraryLoader.createRelroFile(true /* is64Bit */, nativeLibraryPaths[1]);
-            numRelros++;
-        }
-        return numRelros;
-    }
-
     /**
      * @hide
      */
     public static int onWebViewProviderChanged(PackageInfo packageInfo) {
-        String[] nativeLibs = null;
+        int startedRelroProcesses = 0;
         ApplicationInfo originalAppInfo = new ApplicationInfo(packageInfo.applicationInfo);
         try {
             fixupStubApplicationInfo(packageInfo.applicationInfo,
                                      AppGlobals.getInitialApplication().getPackageManager());
 
-            nativeLibs = WebViewLibraryLoader.updateWebViewZygoteVmSize(packageInfo);
+            startedRelroProcesses = WebViewLibraryLoader.prepareNativeLibraries(packageInfo);
         } catch (Throwable t) {
             // Log and discard errors at this stage as we must not crash the system server.
             Log.e(LOGTAG, "error preparing webview native library", t);
@@ -484,7 +462,7 @@
 
         WebViewZygote.onWebViewProviderChanged(packageInfo, originalAppInfo);
 
-        return prepareWebViewInSystemServer(nativeLibs);
+        return startedRelroProcesses;
     }
 
     private static String WEBVIEW_UPDATE_SERVICE_NAME = "webviewupdate";
diff --git a/core/java/android/webkit/WebViewLibraryLoader.java b/core/java/android/webkit/WebViewLibraryLoader.java
index fa1a390..175f35f 100644
--- a/core/java/android/webkit/WebViewLibraryLoader.java
+++ b/core/java/android/webkit/WebViewLibraryLoader.java
@@ -127,11 +127,34 @@
         }
     }
 
+    static int prepareNativeLibraries(PackageInfo webviewPackageInfo)
+            throws WebViewFactory.MissingWebViewPackageException {
+        String[] nativeLibs = updateWebViewZygoteVmSize(webviewPackageInfo);
+        if (DEBUG) Log.v(LOGTAG, "creating relro files");
+        int numRelros = 0;
+
+        // We must always trigger createRelRo regardless of the value of nativeLibraryPaths. Any
+        // unexpected values will be handled there to ensure that we trigger notifying any process
+        // waiting on relro creation.
+        if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
+            if (DEBUG) Log.v(LOGTAG, "Create 32 bit relro");
+            createRelroFile(false /* is64Bit */, nativeLibs[0]);
+            numRelros++;
+        }
+
+        if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
+            if (DEBUG) Log.v(LOGTAG, "Create 64 bit relro");
+            createRelroFile(true /* is64Bit */, nativeLibs[1]);
+            numRelros++;
+        }
+        return numRelros;
+    }
+
     /**
      *
      * @return the native WebView libraries in the new WebView APK.
      */
-    static String[] updateWebViewZygoteVmSize(PackageInfo packageInfo)
+    private static String[] updateWebViewZygoteVmSize(PackageInfo packageInfo)
             throws WebViewFactory.MissingWebViewPackageException {
         // Find the native libraries of the new WebView package, to change the size of the
         // memory region in the Zygote reserved for the library.
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index f63207a..e6da69d 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -166,7 +166,6 @@
     private static final int MENU_ITEM_ORDER_SECONDARY_ASSIST_ACTIONS_START = 50;
     private static final int MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START = 100;
 
-    private static final float MAGNIFIER_ZOOM = 1.25f;
     @IntDef({MagnifierHandleTrigger.SELECTION_START,
             MagnifierHandleTrigger.SELECTION_END,
             MagnifierHandleTrigger.INSERTION})
@@ -4621,7 +4620,7 @@
                     + mTextView.getTotalPaddingTop() - mTextView.getScrollY();
 
             suspendBlink();
-            mMagnifier.show(xPosInView, yPosInView, MAGNIFIER_ZOOM);
+            mMagnifier.show(xPosInView, yPosInView);
         }
 
         protected final void dismissMagnifier() {
diff --git a/core/java/com/android/internal/widget/Magnifier.java b/core/java/com/android/internal/widget/Magnifier.java
index 6d54d7b..f9e98ea 100644
--- a/core/java/com/android/internal/widget/Magnifier.java
+++ b/core/java/com/android/internal/widget/Magnifier.java
@@ -63,7 +63,7 @@
     // the copy is finished.
     private final Handler mPixelCopyHandler = Handler.getMain();
     // Current magnification scale.
-    private float mScale;
+    private final float mZoomScale;
     // Timer used to schedule the copy task.
     private Timer mTimer;
 
@@ -76,11 +76,12 @@
     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);
-        final float elevation = context.getResources().getDimension(R.dimen.magnifier_elevation);
+        mZoomScale = context.getResources().getFloat(R.dimen.magnifier_zoom_scale);
 
         mWindow = new PopupWindow(context);
         mWindow.setContentView(content);
@@ -90,7 +91,9 @@
         mWindow.setTouchable(false);
         mWindow.setBackgroundDrawable(null);
 
-        mBitmap = Bitmap.createBitmap(mWindowWidth, mWindowHeight, Bitmap.Config.ARGB_8888);
+        final int bitmapWidth = (int) (mWindowWidth / mZoomScale);
+        final int bitmapHeight = (int) (mWindowHeight / mZoomScale);
+        mBitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
         getImageView().setImageBitmap(mBitmap);
     }
 
@@ -101,20 +104,8 @@
      *        to the view. The lower end is clamped to 0
      * @param yPosInView vertical coordinate of the center point of the magnifier source
      *        relative to the view. The lower end is clamped to 0
-     * @param scale the scale at which the magnifier zooms on the source content. The
-     *        lower end is clamped to 1 and the higher end to 4
      */
-    public void show(@FloatRange(from=0) float xPosInView,
-            @FloatRange(from=0) float yPosInView,
-            @FloatRange(from=1, to=4) float scale) {
-        if (scale > 4) {
-            scale = 4;
-        }
-
-        if (scale < 1) {
-            scale = 1;
-        }
-
+    public void show(@FloatRange(from=0) float xPosInView, @FloatRange(from=0) float yPosInView) {
         if (xPosInView < 0) {
             xPosInView = 0;
         }
@@ -123,10 +114,6 @@
             yPosInView = 0;
         }
 
-        if (mScale != scale) {
-            resizeBitmap(scale);
-        }
-        mScale = scale;
         configureCoordinates(xPosInView, yPosInView);
 
         if (mTimer == null) {
@@ -164,6 +151,7 @@
     /**
      * @return the height of the magnifier window.
      */
+    @NonNull
     public int getHeight() {
         return mWindowHeight;
     }
@@ -171,15 +159,17 @@
     /**
      * @return the width of the magnifier window.
      */
+    @NonNull
     public int getWidth() {
         return mWindowWidth;
     }
 
-    private void resizeBitmap(float scale) {
-        final int bitmapWidth = (int) (mWindowWidth / scale);
-        final int bitmapHeight = (int) (mWindowHeight / scale);
-        mBitmap.reconfigure(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
-        getImageView().setImageBitmap(mBitmap);
+    /**
+     * @return the zoom scale of the magnifier.
+     */
+    @NonNull
+    public float getZoomScale() {
+        return mZoomScale;
     }
 
     private void configureCoordinates(float xPosInView, float yPosInView) {
diff --git a/core/res/res/layout/magnifier.xml b/core/res/res/layout/magnifier.xml
index d6cd8b4..f3344c7 100644
--- a/core/res/res/layout/magnifier.xml
+++ b/core/res/res/layout/magnifier.xml
@@ -22,10 +22,11 @@
     <LinearLayout
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:id="@+id/magnifier_inner"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
+        android:layout_width="@android:dimen/magnifier_width"
+        android:layout_height="@android:dimen/magnifier_height"
+        android:elevation="@android:dimen/magnifier_elevation"
         android:background="?android:attr/floatingToolbarPopupBackgroundDrawable"
-        android:elevation="@android:dimen/magnifier_elevation">
+        android:scaleType="fitXY">
         <ImageView
             android:id="@+id/magnifier_image"
             android:layout_width="match_parent"
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 08e2233..dc75ba6 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -525,6 +525,7 @@
     <dimen name="magnifier_height">48dp</dimen>
     <dimen name="magnifier_elevation">2dp</dimen>
     <dimen name="magnifier_offset">42dp</dimen>
+    <item type="dimen" format="float" name="magnifier_zoom_scale">1.25</item>
 
     <dimen name="chooser_grid_padding">0dp</dimen>
     <!-- Spacing around the background change frome service to non-service -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1627a0e..896de53 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2484,6 +2484,7 @@
   <java-symbol type="dimen" name="magnifier_width" />
   <java-symbol type="dimen" name="magnifier_height" />
   <java-symbol type="dimen" name="magnifier_elevation" />
+  <java-symbol type="dimen" name="magnifier_zoom_scale" />
   <java-symbol type="dimen" name="magnifier_offset" />
 
   <java-symbol type="string" name="date_picker_prev_month_button" />
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
index fbaf0f3..0806fa0 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
@@ -20,7 +20,6 @@
 import android.test.InstrumentationTestRunner;
 import android.test.InstrumentationTestSuite;
 
-import com.android.connectivitymanagertest.stress.WifiApStress;
 import com.android.connectivitymanagertest.stress.WifiStressTest;
 
 import junit.framework.TestSuite;
@@ -35,7 +34,7 @@
  */
 
 public class ConnectivityManagerStressTestRunner extends InstrumentationTestRunner {
-    private int mSoftApIterations = 100;
+    private int mSoftApIterations = 0;
     private int mScanIterations = 100;
     private int mReconnectIterations = 100;
     // sleep time before restart wifi, default is set to 2 minutes
@@ -47,7 +46,6 @@
     @Override
     public TestSuite getAllTests() {
         TestSuite suite = new InstrumentationTestSuite(this);
-        suite.addTestSuite(WifiApStress.class);
         suite.addTestSuite(WifiStressTest.class);
         return suite;
     }
@@ -60,13 +58,6 @@
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
-        String valueStr = icicle.getString("softap_iterations");
-        if (valueStr != null) {
-            int iteration = Integer.parseInt(valueStr);
-            if (iteration > 0) {
-                mSoftApIterations = iteration;
-            }
-        }
 
         String scanIterationStr = icicle.getString("scan_iterations");
         if (scanIterationStr != null) {
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
index 64fed7f..3706e4b 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
@@ -129,12 +129,6 @@
         // Get an instance of WifiManager
         mWifiManager =(WifiManager)mContext.getSystemService(Context.WIFI_SERVICE);
 
-        if (mWifiManager.isWifiApEnabled()) {
-            // if soft AP is enabled, disable it
-            mWifiManager.setWifiApEnabled(null, false);
-            logv("Disable soft ap");
-        }
-
         // register a connectivity receiver for CONNECTIVITY_ACTION;
         mConnectivityReceiver = new ConnectivityReceiver();
         mContext.registerReceiver(mConnectivityReceiver,
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerUnitTestRunner.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerUnitTestRunner.java
index 0e57a00..746cb84 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerUnitTestRunner.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerUnitTestRunner.java
@@ -19,7 +19,6 @@
 import android.test.InstrumentationTestRunner;
 import android.test.InstrumentationTestSuite;
 import com.android.connectivitymanagertest.unit.WifiClientTest;
-import com.android.connectivitymanagertest.unit.WifiSoftAPTest;
 
 import junit.framework.TestSuite;
 
@@ -35,7 +34,6 @@
     public TestSuite getAllTests() {
         TestSuite suite = new InstrumentationTestSuite(this);
         suite.addTestSuite(WifiClientTest.class);
-        suite.addTestSuite(WifiSoftAPTest.class);
         return suite;
     }
 
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
deleted file mode 100644
index de934b9..0000000
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2010, 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.connectivitymanagertest.stress;
-
-
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiConfiguration.AuthAlgorithm;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
-import android.net.wifi.WifiManager;
-import android.os.Environment;
-import android.test.suitebuilder.annotation.LargeTest;
-
-import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner;
-import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-
-/**
- * Stress test setting up device as wifi hotspot
- */
-public class WifiApStress extends ConnectivityManagerTestBase {
-    private static String NETWORK_ID = "AndroidAPTest";
-    private static String PASSWD = "androidwifi";
-    private final static String OUTPUT_FILE = "WifiStressTestOutput.txt";
-    private int mTotalIterations;
-    private BufferedWriter mOutputWriter = null;
-    private int mLastIteration = 0;
-    private boolean mWifiOnlyFlag;
-
-    public WifiApStress() {
-        super(WifiApStress.class.getSimpleName());
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        ConnectivityManagerStressTestRunner mRunner =
-            (ConnectivityManagerStressTestRunner)getInstrumentation();
-        mTotalIterations = mRunner.getSoftApInterations();
-        mWifiOnlyFlag = mRunner.isWifiOnly();
-        turnScreenOn();
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        // write the total number of iterations into output file
-        mOutputWriter = new BufferedWriter(new FileWriter(new File(
-                Environment.getExternalStorageDirectory(), OUTPUT_FILE)));
-        mOutputWriter.write(String.format("iteration %d out of %d\n",
-                mLastIteration + 1, mTotalIterations));
-        mOutputWriter.flush();
-        mOutputWriter.close();
-        super.tearDown();
-    }
-
-    @LargeTest
-    public void testWifiHotSpot() {
-        if (mWifiOnlyFlag) {
-            logv(getName() + " is excluded for wi-fi only test");
-            return;
-        }
-        WifiConfiguration config = new WifiConfiguration();
-        config.SSID = NETWORK_ID;
-        config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
-        config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
-        config.preSharedKey = PASSWD;
-
-        // if wifiap enabled, disable it
-        assertTrue("failed to disable wifi hotspot",
-                mWifiManager.setWifiApEnabled(config, false));
-        assertTrue("wifi hotspot not enabled", waitForWifiApState(
-                WifiManager.WIFI_AP_STATE_DISABLED, 2 * LONG_TIMEOUT));
-
-        // if Wifi is enabled, disable it
-        if (mWifiManager.isWifiEnabled()) {
-            assertTrue("failed to disable wifi", disableWifi());
-            // wait for the wifi state to be DISABLED
-            assertTrue("wifi state not disabled", waitForWifiState(
-                    WifiManager.WIFI_STATE_DISABLED, LONG_TIMEOUT));
-        }
-        int i;
-        for (i = 0; i < mTotalIterations; i++) {
-            logv("iteration: " + i);
-            mLastIteration = i;
-            // enable Wifi tethering
-            assertTrue("failed to enable wifi hotspot",
-                    mWifiManager.setWifiApEnabled(config, true));
-            // wait for wifi ap state to be ENABLED
-            assertTrue("wifi hotspot not enabled", waitForWifiApState(
-                    WifiManager.WIFI_AP_STATE_ENABLED, 2 * LONG_TIMEOUT));
-            // wait for wifi tethering result
-            assertTrue("tether state not changed", waitForTetherStateChange(LONG_TIMEOUT));
-            // allow the wifi tethering to be enabled for 10 seconds
-            try {
-                Thread.sleep(2 * SHORT_TIMEOUT);
-            } catch (Exception e) {
-                // ignore
-            }
-            assertTrue("no uplink data connection after Wi-Fi tethering", pingTest());
-            // disable wifi hotspot
-            assertTrue("failed to disable wifi hotspot",
-                    mWifiManager.setWifiApEnabled(config, false));
-            assertTrue("wifi hotspot not enabled", waitForWifiApState(
-                    WifiManager.WIFI_AP_STATE_DISABLED, 2 * LONG_TIMEOUT));
-            assertFalse("wifi hotspot still enabled", mWifiManager.isWifiApEnabled());
-        }
-    }
-
-}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiSoftAPTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiSoftAPTest.java
deleted file mode 100644
index f202862..0000000
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiSoftAPTest.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2010 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.connectivitymanagertest.unit;
-
-import android.content.Context;
-import android.net.wifi.WifiManager;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.AndroidTestCase;
-
-import android.util.Log;
-
-/**
- * Test Wifi soft AP configuration
- */
-public class WifiSoftAPTest extends AndroidTestCase {
-
-    private WifiManager mWifiManager;
-    private WifiConfiguration mWifiConfig = null;
-    private final String TAG = "WifiSoftAPTest";
-    private final int DURATION = 10000;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
-        assertNotNull(mWifiManager);
-        assertTrue(mWifiManager.setWifiApEnabled(null, true));
-        mWifiConfig = mWifiManager.getWifiApConfiguration();
-        if (mWifiConfig != null) {
-            Log.v(TAG, "mWifiConfig is " + mWifiConfig.toString());
-        } else {
-            Log.v(TAG, "mWifiConfig is null.");
-        }
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        Log.v(TAG, "turn off wifi tethering");
-        mWifiManager.setWifiApEnabled(null, false);
-        super.tearDown();
-    }
-
-    // Test case 1: Test the soft AP SSID with letters
-    @LargeTest
-    public void testApSsidWithAlphabet() {
-        WifiConfiguration config = new WifiConfiguration();
-        config.SSID = "abcdefghijklmnopqrstuvwxyz";
-        config.allowedKeyManagement.set(KeyMgmt.NONE);
-        mWifiConfig = config;
-        assertTrue(mWifiManager.setWifiApEnabled(mWifiConfig, true));
-        try {
-            Thread.sleep(DURATION);
-        } catch (InterruptedException e) {
-            Log.v(TAG, "exception " + e.getStackTrace());
-            assertFalse(true);
-        }
-        assertNotNull(mWifiManager.getWifiApConfiguration());
-        assertEquals("wifi AP state is not enabled", WifiManager.WIFI_AP_STATE_ENABLED,
-                     mWifiManager.getWifiApState());
-    }
-}
diff --git a/libs/protoutil/include/android/util/ProtoOutputStream.h b/libs/protoutil/include/android/util/ProtoOutputStream.h
index 0f1cced..10be649 100644
--- a/libs/protoutil/include/android/util/ProtoOutputStream.h
+++ b/libs/protoutil/include/android/util/ProtoOutputStream.h
@@ -49,7 +49,7 @@
     bool write(uint64_t fieldId, long long val);
     bool write(uint64_t fieldId, bool val);
     bool write(uint64_t fieldId, std::string val);
-    bool write(uint64_t fieldId, const char* val);
+    bool write(uint64_t fieldId, const char* val, size_t size);
 
     /**
      * Starts a sub-message write session.
@@ -103,4 +103,4 @@
 }
 }
 
-#endif // ANDROID_UTIL_PROTOOUTPUT_STREAM_H
\ No newline at end of file
+#endif // ANDROID_UTIL_PROTOOUTPUT_STREAM_H
diff --git a/libs/protoutil/src/ProtoOutputStream.cpp b/libs/protoutil/src/ProtoOutputStream.cpp
index 15144ac..9dadf1c 100644
--- a/libs/protoutil/src/ProtoOutputStream.cpp
+++ b/libs/protoutil/src/ProtoOutputStream.cpp
@@ -225,14 +225,13 @@
 }
 
 bool
-ProtoOutputStream::write(uint64_t fieldId, const char* val)
+ProtoOutputStream::write(uint64_t fieldId, const char* val, size_t size)
 {
     if (mCompact) return false;
     const uint32_t id = (uint32_t)fieldId;
-    int size = 0;
-    while (val[size] != '\0') size++;
     switch (fieldId & FIELD_TYPE_MASK) {
         case TYPE_STRING:
+        case TYPE_BYTES:
             writeUtf8StringImpl(id, val, size);
             return true;
         default:
diff --git a/packages/SettingsLib/OWNERS b/packages/SettingsLib/OWNERS
new file mode 100644
index 0000000..4211c27
--- /dev/null
+++ b/packages/SettingsLib/OWNERS
@@ -0,0 +1,21 @@
+# People who can approve changes for submission
+asapperstein@google.com
+asargent@google.com
+dehboxturtle@google.com
+dhnishi@google.com
+dling@google.com
+dsandler@google.com
+evanlaird@google.com
+jackqdyulei@google.com
+jmonk@google.com
+mfritze@google.com
+nicoya@google.com
+rogerxue@google.com
+virgild@google.com
+zhfan@google.com
+
+# Emergency approvers in case the above are not available
+miket@google.com
+
+# Exempt resource files (because they are in a flat directory and too hard to manage via OWNERS)
+per-file *.xml=*
\ No newline at end of file
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
index 817989a..f4c9bb3 100755
--- a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
@@ -415,8 +415,8 @@
                             : (mLevel == 100 ? 0.38f : 0.5f)));
             mTextHeight = -mTextPaint.getFontMetrics().ascent;
             pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level / 10) : level);
-            pctX = mWidth * 0.5f;
-            pctY = (mHeight + mTextHeight) * 0.47f;
+            pctX = mWidth * 0.5f + left;
+            pctY = (mHeight + mTextHeight) * 0.47f + top;
             pctOpaque = levelTop > pctY;
             if (!pctOpaque) {
                 mTextPath.reset();
@@ -439,8 +439,8 @@
         if (!mCharging && !mPowerSaveEnabled) {
             if (level <= mCriticalLevel) {
                 // draw the warning text
-                final float x = mWidth * 0.5f;
-                final float y = (mHeight + mWarningTextHeight) * 0.48f;
+                final float x = mWidth * 0.5f + left;
+                final float y = (mHeight + mWarningTextHeight) * 0.48f + top;
                 c.drawText(mWarningString, x, y, mWarningTextPaint);
             } else if (pctOpaque) {
                 // draw the percentage text
diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/OWNERS b/packages/SettingsLib/src/com/android/settingslib/inputmethod/OWNERS
new file mode 100644
index 0000000..a0e28ba
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/inputmethod/OWNERS
@@ -0,0 +1,5 @@
+# Default reviewers for this and subdirectories.
+takaoka@google.com
+yukawa@google.com
+
+# Emergency approvers in case the above are not available
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java
new file mode 100644
index 0000000..3522b8a
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.settingslib.graph;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+import com.android.settingslib.TestConfig;
+import com.android.settingslib.testutils.shadow.SettingsLibShadowResources;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
+        shadows = SettingsLibShadowResources.class)
+public class BatteryMeterDrawableBaseTest {
+    private static final int PADDING = 5;
+    private static final int HEIGHT = 80;
+    private static final int WIDTH = 40;
+    @Mock
+    private Canvas mCanvas;
+    private Context mContext;
+    private BatteryMeterDrawableBase mBatteryMeterDrawableBase;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mContext = RuntimeEnvironment.application;
+        mBatteryMeterDrawableBase = new BatteryMeterDrawableBase(mContext, 0 /* frameColor */);
+    }
+
+    @Test
+    public void testDraw_hasPaddingAndBounds_drawWarningInCorrectPosition() {
+        mBatteryMeterDrawableBase.setPadding(PADDING, PADDING, PADDING, PADDING);
+        mBatteryMeterDrawableBase.setBounds(0, 0, WIDTH + 2 * PADDING, HEIGHT + 2 * PADDING);
+        mBatteryMeterDrawableBase.setBatteryLevel(3);
+
+        mBatteryMeterDrawableBase.draw(mCanvas);
+
+        // WIDTH * 0.5 + PADDING = 25
+        // (HEIGHT + TEXT_HEIGHT) * 0.48 + PADDING = 43.3999998
+        verify(mCanvas).drawText(eq("!"), eq(25f), eq(43.399998f), any(Paint.class));
+    }
+
+    @Test
+    public void testDraw_hasPaddingAndBounds_drawBatteryLevelInCorrectPosition() {
+        mBatteryMeterDrawableBase.setPadding(PADDING, PADDING, PADDING, PADDING);
+        mBatteryMeterDrawableBase.setBounds(0, 0, WIDTH + 2 * PADDING, HEIGHT + 2 * PADDING);
+        mBatteryMeterDrawableBase.setBatteryLevel(20);
+        mBatteryMeterDrawableBase.setShowPercent(true);
+
+        mBatteryMeterDrawableBase.draw(mCanvas);
+
+        // WIDTH * 0.5 + PADDING = 25
+        // (HEIGHT + TEXT_HEIGHT) * 0.47 + PADDING = 42.6
+        verify(mCanvas).drawText(eq("20"), eq(25f), eq(42.6f), any(Paint.class));
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index d24e51c..40ee838 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -382,13 +382,6 @@
         new AsyncTask<Void, Void, Void>() {
             @Override
             protected Void doInBackground(Void... args) {
-                // Disable tethering if enabling Wifi
-                final int wifiApState = mWifiManager.getWifiApState();
-                if (enabled && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
-                        (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
-                    mWifiManager.setWifiApEnabled(null, false);
-                }
-
                 mWifiManager.setWifiEnabled(enabled);
                 return null;
             }
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index cf1d33c..a139ac4 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -754,7 +754,7 @@
      * and re-binding, during which the system could *technically* hand that port out to someone
      * else.
      */
-    private void bindToRandomPort(FileDescriptor sockFd) throws IOException {
+    private int bindToRandomPort(FileDescriptor sockFd) throws IOException {
         for (int i = MAX_PORT_BIND_ATTEMPTS; i > 0; i--) {
             try {
                 FileDescriptor probeSocket = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
@@ -763,7 +763,7 @@
                 Os.close(probeSocket);
                 Log.v(TAG, "Binding to port " + port);
                 Os.bind(sockFd, INADDR_ANY, port);
-                return;
+                return port;
             } catch (ErrnoException e) {
                 // Someone miraculously claimed the port just after we closed probeSocket.
                 if (e.errno == OsConstants.EADDRINUSE) {
@@ -803,7 +803,7 @@
                 Log.v(TAG, "Binding to port " + port);
                 Os.bind(sockFd, INADDR_ANY, port);
             } else {
-                bindToRandomPort(sockFd);
+                port = bindToRandomPort(sockFd);
             }
             // This code is common to both the unspecified and specified port cases
             Os.setsockoptInt(
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index cd25610..bfbce40 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -641,8 +641,8 @@
                     break;
                 }
                 case H_PARTITION_FORGET: {
-                    final String partGuid = (String) msg.obj;
-                    forgetPartition(partGuid);
+                    final VolumeRecord rec = (VolumeRecord) msg.obj;
+                    forgetPartition(rec.partGuid, rec.fsUuid);
                     break;
                 }
                 case H_RESET: {
@@ -1694,7 +1694,7 @@
         synchronized (mLock) {
             final VolumeRecord rec = mRecords.remove(fsUuid);
             if (rec != null && !TextUtils.isEmpty(rec.partGuid)) {
-                mHandler.obtainMessage(H_PARTITION_FORGET, rec.partGuid).sendToTarget();
+                mHandler.obtainMessage(H_PARTITION_FORGET, rec).sendToTarget();
             }
             mCallbacks.notifyVolumeForgotten(fsUuid);
 
@@ -1718,7 +1718,7 @@
                 final String fsUuid = mRecords.keyAt(i);
                 final VolumeRecord rec = mRecords.valueAt(i);
                 if (!TextUtils.isEmpty(rec.partGuid)) {
-                    mHandler.obtainMessage(H_PARTITION_FORGET, rec.partGuid).sendToTarget();
+                    mHandler.obtainMessage(H_PARTITION_FORGET, rec).sendToTarget();
                 }
                 mCallbacks.notifyVolumeForgotten(fsUuid);
             }
@@ -1733,9 +1733,9 @@
         }
     }
 
-    private void forgetPartition(String partGuid) {
+    private void forgetPartition(String partGuid, String fsUuid) {
         try {
-            mVold.forgetPartition(partGuid);
+            mVold.forgetPartition(partGuid, fsUuid);
         } catch (Exception e) {
             Slog.wtf(TAG, e);
         }
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index 089db87..29073cb 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -38,7 +38,9 @@
 import static com.android.server.am.proto.ActivityDisplayProto.STACKS;
 import static com.android.server.am.proto.ActivityDisplayProto.ID;
 
+import android.annotation.Nullable;
 import android.app.ActivityManagerInternal;
+import android.app.ActivityOptions;
 import android.app.WindowConfiguration;
 import android.util.IntArray;
 import android.util.Slog;
@@ -206,6 +208,18 @@
     }
 
     /**
+     * Returns an existing stack compatible with the input params or creates one
+     * if a compatible stack doesn't exist.
+     * @see #getOrCreateStack(int, int, boolean)
+     */
+    <T extends ActivityStack> T getOrCreateStack(@Nullable ActivityRecord r,
+            @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, int activityType,
+            boolean onTop) {
+        final int windowingMode = resolveWindowingMode(r, options, candidateTask, activityType);
+        return getOrCreateStack(windowingMode, activityType, onTop);
+    }
+
+    /**
      * Creates a stack matching the input windowing mode and activity type on this display.
      * @param windowingMode The windowing mode the stack should be created in. If
      *                      {@link WindowConfiguration#WINDOWING_MODE_UNDEFINED} then the stack will
@@ -235,7 +249,7 @@
         }
 
         final ActivityManagerService service = mSupervisor.mService;
-        if (!mSupervisor.isWindowingModeSupported(windowingMode, service.mSupportsMultiWindow,
+        if (!isWindowingModeSupported(windowingMode, service.mSupportsMultiWindow,
                 service.mSupportsSplitScreenMultiWindow, service.mSupportsFreeformWindowManagement,
                 service.mSupportsPictureInPicture, activityType)) {
             throw new IllegalArgumentException("Can't create stack for unsupported windowingMode="
@@ -252,33 +266,27 @@
             }
         }
 
-        windowingMode = updateWindowingModeForSplitScreenIfNeeded(windowingMode, activityType);
-
         final int stackId = mSupervisor.getNextStackId();
-
-        final T stack = createStackUnchecked(windowingMode, activityType, stackId, onTop);
-
-        if (mDisplayId == DEFAULT_DISPLAY && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
-            // Make sure recents stack exist when creating a dock stack as it normally need to be on
-            // the other side of the docked stack and we make visibility decisions based on that.
-            // TODO: Not sure if this is needed after we change to calculate visibility based on
-            // stack z-order vs. id.
-            getOrCreateStack(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_RECENTS, onTop);
-        }
-
-        return stack;
+        return createStackUnchecked(windowingMode, activityType, stackId, onTop);
     }
 
     @VisibleForTesting
     <T extends ActivityStack> T createStackUnchecked(int windowingMode, int activityType,
             int stackId, boolean onTop) {
-        switch (windowingMode) {
-            case WINDOWING_MODE_PINNED:
-                return (T) new PinnedActivityStack(this, stackId, mSupervisor, onTop);
-            default:
-                return (T) new ActivityStack(
-                        this, stackId, mSupervisor, windowingMode, activityType, onTop);
+        if (windowingMode == WINDOWING_MODE_PINNED) {
+            return (T) new PinnedActivityStack(this, stackId, mSupervisor, onTop);
         }
+        final T stack = (T) new ActivityStack(
+                        this, stackId, mSupervisor, windowingMode, activityType, onTop);
+
+        if (mDisplayId == DEFAULT_DISPLAY && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+            // Make sure recents stack exist when creating a dock stack as it normally needs to be
+            // on the other side of the docked stack and we make visibility decisions based on that.
+            // TODO: Not sure if this is needed after we change to calculate visibility based on
+            // stack z-order vs. id.
+            getOrCreateStack(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_RECENTS, onTop);
+        }
+        return stack;
     }
 
     /**
@@ -372,6 +380,105 @@
         }
     }
 
+    /**
+     * Returns true if the {@param windowingMode} is supported based on other parameters passed in.
+     * @param windowingMode The windowing mode we are checking support for.
+     * @param supportsMultiWindow If we should consider support for multi-window mode in general.
+     * @param supportsSplitScreen If we should consider support for split-screen multi-window.
+     * @param supportsFreeform If we should consider support for freeform multi-window.
+     * @param supportsPip If we should consider support for picture-in-picture mutli-window.
+     * @param activityType The activity type under consideration.
+     * @return true if the windowing mode is supported.
+     */
+    private boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow,
+            boolean supportsSplitScreen, boolean supportsFreeform, boolean supportsPip,
+            int activityType) {
+
+        if (windowingMode == WINDOWING_MODE_UNDEFINED
+                || windowingMode == WINDOWING_MODE_FULLSCREEN) {
+            return true;
+        }
+        if (!supportsMultiWindow) {
+            return false;
+        }
+
+        if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+                || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
+            return supportsSplitScreen && WindowConfiguration.supportSplitScreenWindowingMode(
+                    windowingMode, activityType);
+        }
+
+        if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) {
+            return false;
+        }
+
+        if (!supportsPip && windowingMode == WINDOWING_MODE_PINNED) {
+            return false;
+        }
+        return true;
+    }
+
+    int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
+            @Nullable TaskRecord task, int activityType) {
+
+        // First preference if the windowing mode in the activity options if set.
+        int windowingMode = (options != null)
+                ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
+
+        // If windowing mode is unset, then next preference is the candidate task, then the
+        // activity record.
+        if (windowingMode == WINDOWING_MODE_UNDEFINED) {
+            if (task != null) {
+                windowingMode = task.getWindowingMode();
+            }
+            if (windowingMode == WINDOWING_MODE_UNDEFINED && r != null) {
+                windowingMode = r.getWindowingMode();
+            }
+            if (windowingMode == WINDOWING_MODE_UNDEFINED) {
+                // Use the display's windowing mode.
+                windowingMode = getWindowingMode();
+            }
+        }
+
+        // Make sure the windowing mode we are trying to use makes sense for what is supported.
+        final ActivityManagerService service = mSupervisor.mService;
+        boolean supportsMultiWindow = service.mSupportsMultiWindow;
+        boolean supportsSplitScreen = service.mSupportsSplitScreenMultiWindow;
+        boolean supportsFreeform = service.mSupportsFreeformWindowManagement;
+        boolean supportsPip = service.mSupportsPictureInPicture;
+        if (supportsMultiWindow) {
+            if (task != null) {
+                supportsMultiWindow = task.isResizeable();
+                supportsSplitScreen = task.supportsSplitScreenWindowingMode();
+                // TODO: Do we need to check for freeform and Pip support here?
+            } else if (r != null) {
+                supportsMultiWindow = r.isResizeable();
+                supportsSplitScreen = r.supportsSplitScreenWindowingMode();
+                supportsFreeform = r.supportsFreeform();
+                supportsPip = r.supportsPictureInPicture();
+            }
+        }
+
+        final boolean inSplitScreenMode = hasSplitScreenPrimaryStack();
+        if (!inSplitScreenMode
+                && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) {
+            // Switch to fullscreen windowing mode if we are not in split-screen mode and we are
+            // trying to launch in split-screen secondary.
+            windowingMode = WINDOWING_MODE_FULLSCREEN;
+        } else if (inSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN
+                && supportsSplitScreen) {
+            windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+        }
+
+        if (windowingMode != WINDOWING_MODE_UNDEFINED
+                && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen,
+                supportsFreeform, supportsPip, activityType)) {
+            return windowingMode;
+        }
+        // Return the display's windowing mode
+        return getWindowingMode();
+    }
+
     /** Returns the top visible stack activity type that isn't in the exclude windowing mode. */
     int getTopVisibleStackActivityType(int excludeWindowingMode) {
         for (int i = mStacks.size() - 1; i >= 0; --i) {
@@ -408,6 +515,14 @@
         }
     }
 
+    /** We are in the process of exiting split-screen mode. */
+    void onExitingSplitScreenMode() {
+        // Remove reference to the primary-split-screen stack so it no longer has any effect on the
+        // display. For example, we want to be able to create fullscreen stack for standard activity
+        // types when exiting split-screen mode.
+        mSplitScreenPrimaryStack = null;
+    }
+
     ActivityStack getSplitScreenPrimaryStack() {
         return mSplitScreenPrimaryStack;
     }
@@ -424,21 +539,6 @@
         return mPinnedStack != null;
     }
 
-    int updateWindowingModeForSplitScreenIfNeeded(int windowingMode, int activityType) {
-        final boolean inSplitScreenMode = hasSplitScreenPrimaryStack();
-        if (!inSplitScreenMode
-                && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) {
-            // Switch to fullscreen windowing mode if we are not in split-screen mode and we are
-            // trying to launch in split-screen secondary.
-            return WINDOWING_MODE_FULLSCREEN;
-        } else if (inSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN
-                && WindowConfiguration.supportSplitScreenWindowingMode(
-                windowingMode, activityType)) {
-            return WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
-        }
-        return windowingMode;
-    }
-
     @Override
     public String toString() {
         return "ActivityDisplay={" + mDisplayId + " numStacks=" + mStacks.size() + "}";
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e1e53b3..3fd1f4a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -31,6 +31,7 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.content.pm.PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS;
@@ -10318,7 +10319,8 @@
             }
             // TODO(multi-display): Have the caller pass in the windowing mode and activity type.
             final ActivityStack stack = display.createStack(
-                    WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /*onTop*/);
+                    WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD,
+                    ON_TOP);
             return (stack != null) ? stack.mStackId : INVALID_STACK_ID;
         }
     }
@@ -14239,12 +14241,12 @@
                 }
             }
             sb.append("\n");
-            if (info.crashInfo != null && info.crashInfo.stackTrace != null) {
-                sb.append(info.crashInfo.stackTrace);
+            if (info.hasStackTrace()) {
+                sb.append(info.getStackTrace());
                 sb.append("\n");
             }
-            if (info.message != null) {
-                sb.append(info.message);
+            if (info.getViolationDetails() != null) {
+                sb.append(info.getViolationDetails());
                 sb.append("\n");
             }
 
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 2c72a4d..b885eab 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -165,6 +165,7 @@
 import android.view.IApplicationToken;
 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;
@@ -232,7 +233,9 @@
     final String processName; // process where this component wants to run
     final String taskAffinity; // as per ActivityInfo.taskAffinity
     final boolean stateNotNeeded; // As per ActivityInfo.flags
-    boolean fullscreen; // covers the full screen?
+    boolean fullscreen; // The activity is opaque and fills the entire space of this task.
+    // TODO: See if it possible to combine this with the fullscreen field.
+    final boolean hasWallpaper; // Has a wallpaper window as a background.
     final boolean noDisplay;  // activity is not displayed?
     private final boolean componentSpecified;  // did caller specify an explicit component?
     final boolean rootVoiceInteraction;  // was this the root activity of a voice interaction?
@@ -883,9 +886,14 @@
 
         Entry ent = AttributeCache.instance().get(packageName,
                 realTheme, com.android.internal.R.styleable.Window, userId);
-        fullscreen = ent != null && !ActivityInfo.isTranslucentOrFloating(ent.array);
-        noDisplay = ent != null && ent.array.getBoolean(
-                com.android.internal.R.styleable.Window_windowNoDisplay, false);
+        if (ent != null) {
+            fullscreen = !ActivityInfo.isTranslucentOrFloating(ent.array);
+            hasWallpaper = ent.array.getBoolean(R.styleable.Window_windowShowWallpaper, false);
+            noDisplay = ent.array.getBoolean(R.styleable.Window_windowNoDisplay, false);
+        } else {
+            hasWallpaper = false;
+            noDisplay = false;
+        }
 
         setActivityType(_componentSpecified, _launchedFromUid, _intent, options, sourceRecord);
 
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 941c371..f05243b 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -489,22 +489,19 @@
             activityType = ACTIVITY_TYPE_STANDARD;
         }
         final ActivityDisplay display = getDisplay();
-        if (display != null) {
-            if (activityType == ACTIVITY_TYPE_STANDARD
+        if (display != null && activityType == ACTIVITY_TYPE_STANDARD
                     && windowingMode == WINDOWING_MODE_UNDEFINED) {
-                // Standard activity types will mostly take on the windowing mode of the display if
-                // one isn't specified, so look-up a compatible stack based on the display's
-                // windowing mode.
-                windowingMode = display.getWindowingMode();
-            }
-            windowingMode =
-                    display.updateWindowingModeForSplitScreenIfNeeded(windowingMode, activityType);
+            // Standard activity types will mostly take on the windowing mode of the display if one
+            // isn't specified, so look-up a compatible stack based on the display's windowing mode.
+            windowingMode = display.getWindowingMode();
         }
         return super.isCompatible(windowingMode, activityType);
     }
 
     /** Adds the stack to specified display and calls WindowManager to do the same. */
     void reparent(ActivityDisplay activityDisplay, boolean onTop) {
+        // TODO: We should probably resolve the windowing mode for the stack on the new display here
+        // so that it end up in a compatible mode in the new display. e.g. split-screen secondary.
         removeFromDisplay();
         mTmpRect2.setEmpty();
         postAddToDisplay(activityDisplay, mTmpRect2.isEmpty() ? null : mTmpRect2, onTop);
@@ -1496,25 +1493,19 @@
         }
     }
 
-    /** Returns true if the stack contains a fullscreen task. */
-    private boolean hasFullscreenTask() {
-        for (int i = mTaskHistory.size() - 1; i >= 0; --i) {
-            final TaskRecord task = mTaskHistory.get(i);
-            if (task.mFullscreen) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     /**
      * Returns true if the stack is translucent and can have other contents visible behind it if
      * needed. A stack is considered translucent if it don't contain a visible or
      * starting (about to be visible) activity that is fullscreen (opaque).
      * @param starting The currently starting activity or null if there is none.
+     * TODO: Can be removed once we are no longer using returnToType for back functionality
      * @param stackBehind The stack directly behind this one.
      */
-    private boolean isStackTranslucent(ActivityRecord starting, ActivityStack stackBehind) {
+    @VisibleForTesting
+    boolean isStackTranslucent(ActivityRecord starting, ActivityStack stackBehind) {
+        if (!isAttached() || mForceHidden) {
+            return true;
+        }
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             final TaskRecord task = mTaskHistory.get(taskNdx);
             final ArrayList<ActivityRecord> activities = task.mActivities;
@@ -1533,7 +1524,7 @@
                     continue;
                 }
 
-                if (r.fullscreen) {
+                if (r.fullscreen || r.hasWallpaper) {
                     // Stack isn't translucent if it has at least one fullscreen activity
                     // that is visible.
                     return false;
@@ -1572,127 +1563,66 @@
         if (!isAttached() || mForceHidden) {
             return false;
         }
-
-        final ActivityDisplay display = getDisplay();
-        if (isTopStackOnDisplay() || mStackSupervisor.isFocusedStack(this)) {
+        if (mStackSupervisor.isFocusedStack(this)) {
             return true;
         }
 
-        final int stackIndex = display.getIndexOf(this);
-
-        // Check position and visibility of this stack relative to the front stack on its display.
-        final ActivityStack topStack = getDisplay().getTopStack();
-        final int windowingMode = getWindowingMode();
-        final int activityType = getActivityType();
-
-        if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
-            // If the assistant stack is focused and translucent, then the docked stack is always
-            // visible
-            if (topStack.isActivityTypeAssistant()) {
-                return topStack.isStackTranslucent(starting, this);
-            }
-            return true;
-        }
-
-        // Set home stack to invisible when it is below but not immediately below the docked stack
-        // A case would be if recents stack exists but has no tasks and is below the docked stack
-        // and home stack is below recents
-        if (activityType == ACTIVITY_TYPE_HOME) {
-            final ActivityStack splitScreenStack = display.getSplitScreenPrimaryStack();
-            int dockedStackIndex = display.getIndexOf(splitScreenStack);
-            if (dockedStackIndex > stackIndex && stackIndex != dockedStackIndex - 1) {
-                return false;
-            }
-        }
-
-        // Find the first stack behind front stack that actually got something visible.
-        int stackBehindTopIndex = display.getIndexOf(topStack) - 1;
-        while (stackBehindTopIndex >= 0 &&
-                display.getChildAt(stackBehindTopIndex).topRunningActivityLocked() == null) {
-            stackBehindTopIndex--;
-        }
-        final ActivityStack stackBehindTop = (stackBehindTopIndex >= 0)
-                ? display.getChildAt(stackBehindTopIndex) : null;
-        int stackBehindTopWindowingMode = WINDOWING_MODE_UNDEFINED;
-        int stackBehindTopActivityType = ACTIVITY_TYPE_UNDEFINED;
-        if (stackBehindTop != null) {
-            stackBehindTopWindowingMode = stackBehindTop.getWindowingMode();
-            stackBehindTopActivityType = stackBehindTop.getActivityType();
-        }
-
-        final boolean alwaysOnTop = topStack.getWindowConfiguration().isAlwaysOnTop();
-        if (topStack.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY || alwaysOnTop) {
-            if (this == stackBehindTop) {
-                // Stacks directly behind the docked or pinned stack are always visible.
-                return true;
-            } else if (alwaysOnTop && stackIndex == stackBehindTopIndex - 1) {
-                // Otherwise, this stack can also be visible if it is directly behind a docked stack
-                // or translucent assistant stack behind an always-on-top top-most stack
-                if (stackBehindTopWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
-                    return true;
-                } else if (stackBehindTopActivityType == ACTIVITY_TYPE_ASSISTANT) {
-                    return stackBehindTop.isStackTranslucent(starting, this);
-                }
-            }
-        }
-
-        if (topStack.isBackdropToTranslucentActivity()
-                && topStack.isStackTranslucent(starting, stackBehindTop)) {
-            // Stacks behind the fullscreen or assistant stack with a translucent activity are
-            // always visible so they can act as a backdrop to the translucent activity.
-            // For example, dialog activities
-            if (stackIndex == stackBehindTopIndex) {
-                return true;
-            }
-            if (stackBehindTopIndex >= 0) {
-                if ((stackBehindTopWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
-                        || stackBehindTopWindowingMode == WINDOWING_MODE_PINNED)
-                        && stackIndex == (stackBehindTopIndex - 1)) {
-                    // The stack behind the docked or pinned stack is also visible so we can have a
-                    // complete backdrop to the translucent activity when the docked stack is up.
-                    return true;
-                }
-            }
-        }
-
-        if (isOnHomeDisplay()) {
-            // Visibility of any stack on default display should have been determined by the
-            // conditions above.
+        final ActivityRecord top = topRunningActivityLocked();
+        if (top == null && isInStackLocked(starting) == null && !isTopStackOnDisplay()) {
+            // Shouldn't be visible if you don't have any running activities, not starting one, and
+            // not the top stack on display.
             return false;
         }
 
-        final int stackCount = display.getChildCount();
-        for (int i = stackIndex + 1; i < stackCount; i++) {
-            final ActivityStack stack = display.getChildAt(i);
-
-            if (!stack.mFullscreen && !stack.hasFullscreenTask()) {
-                continue;
-            }
-
-            if (!stack.isDynamicStacksVisibleBehindAllowed()) {
-                // These stacks can't have any dynamic stacks visible behind them.
-                return false;
-            }
-
-            if (!stack.isStackTranslucent(starting, null /* stackBehind */)) {
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    private boolean isBackdropToTranslucentActivity() {
-        if (isActivityTypeAssistant()) {
-            return true;
-        }
+        final ActivityDisplay display = getDisplay();
+        boolean gotOpaqueSplitScreenPrimary = false;
+        boolean gotOpaqueSplitScreenSecondary = false;
         final int windowingMode = getWindowingMode();
-        return windowingMode == WINDOWING_MODE_FULLSCREEN
-                || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
-    }
+        for (int i = display.getChildCount() - 1; i >= 0; --i) {
+            final ActivityStack other = display.getChildAt(i);
+            if (other == this) {
+                // Should be visible if there is no other stack occluding it.
+                return true;
+            }
 
-    private boolean isDynamicStacksVisibleBehindAllowed() {
-        return isActivityTypeAssistant() || getWindowingMode() == WINDOWING_MODE_PINNED;
+            final int otherWindowingMode = other.getWindowingMode();
+            // TODO: Can be removed once we are no longer using returnToType for back functionality
+            final ActivityStack stackBehind = i > 0 ? display.getChildAt(i - 1) : null;
+
+            if (otherWindowingMode == WINDOWING_MODE_FULLSCREEN) {
+                if (other.isStackTranslucent(starting, stackBehind)) {
+                    // Can be visible behind a translucent fullscreen stack.
+                    continue;
+                }
+                return false;
+            } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+                    && !gotOpaqueSplitScreenPrimary) {
+                gotOpaqueSplitScreenPrimary =
+                        !other.isStackTranslucent(starting, stackBehind);
+                if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+                        && gotOpaqueSplitScreenPrimary) {
+                    // Can not be visible behind another opaque stack in split-screen-primary mode.
+                    return false;
+                }
+            } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
+                    && !gotOpaqueSplitScreenSecondary) {
+                gotOpaqueSplitScreenSecondary =
+                        !other.isStackTranslucent(starting, stackBehind);
+                if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
+                        && gotOpaqueSplitScreenSecondary) {
+                    // Can not be visible behind another opaque stack in split-screen-secondary mode.
+                    return false;
+                }
+            }
+            if (gotOpaqueSplitScreenPrimary && gotOpaqueSplitScreenSecondary) {
+                // Can not be visible if we are in split-screen windowing mode and both halves of
+                // the screen are opaque.
+                return false;
+            }
+        }
+
+        // Well, nothing is stopping you from being visible...
+        return true;
     }
 
     final int rankTaskLayers(int baseLayer) {
@@ -5263,7 +5193,8 @@
     public String toString() {
         return "ActivityStack{" + Integer.toHexString(System.identityHashCode(this))
                 + " stackId=" + mStackId + " type=" + activityTypeToString(getActivityType())
-                + " mode=" + windowingModeToString(getWindowingMode()) + ", "
+                + " mode=" + windowingModeToString(getWindowingMode())
+                + " visible=" + shouldBeVisible(null /* starting */) + ", "
                 + mTaskHistory.size() + " tasks}";
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index c15b5e2..7a4a0d4 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -110,7 +110,6 @@
 import android.app.ProfilerInfo;
 import android.app.ResultInfo;
 import android.app.WaitResult;
-import android.app.WindowConfiguration;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -223,13 +222,6 @@
     // at the top of its container (e.g. stack).
     static final boolean ON_TOP = true;
 
-    // Used to indicate that an objects (e.g. task) removal from its container
-    // (e.g. stack) is due to it moving to another container.
-    static final boolean MOVING = true;
-
-    // Force the focus to change to the stack we are moving a task to..
-    static final boolean FORCE_FOCUS = true;
-
     // Don't execute any calls to resume.
     static final boolean DEFER_RESUME = true;
 
@@ -405,6 +397,7 @@
      * object each time.
      */
     private final Rect tempRect = new Rect();
+    private final ActivityOptions mTmpOptions = ActivityOptions.makeBasic();
 
     // The default minimal size that will be used if the activity doesn't specify its minimal size.
     // It will be calculated when the default display gets added.
@@ -2186,89 +2179,6 @@
         return null;
     }
 
-    /**
-     * Returns true if the {@param windowingMode} is supported based on other parameters passed in.
-     * @param windowingMode The windowing mode we are checking support for.
-     * @param supportsMultiWindow If we should consider support for multi-window mode in general.
-     * @param supportsSplitScreen If we should consider support for split-screen multi-window.
-     * @param supportsFreeform If we should consider support for freeform multi-window.
-     * @param supportsPip If we should consider support for picture-in-picture mutli-window.
-     * @param activityType The activity type under consideration.
-     * @return true if the windowing mode is supported.
-     */
-    boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow,
-            boolean supportsSplitScreen, boolean supportsFreeform, boolean supportsPip,
-            int activityType) {
-
-        if (windowingMode == WINDOWING_MODE_UNDEFINED
-                || windowingMode == WINDOWING_MODE_FULLSCREEN) {
-            return true;
-        }
-        if (!supportsMultiWindow) {
-            return false;
-        }
-
-        if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
-                || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
-            return supportsSplitScreen && WindowConfiguration.supportSplitScreenWindowingMode(
-                    windowingMode, activityType);
-        }
-
-        if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) {
-            return false;
-        }
-
-        if (!supportsPip && windowingMode == WINDOWING_MODE_PINNED) {
-            return false;
-        }
-        return true;
-    }
-
-    private int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
-            @Nullable TaskRecord task, int activityType) {
-
-        // First preference if the windowing mode in the activity options if set.
-        int windowingMode = (options != null)
-                ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
-
-        // If windowing mode is unset, then next preference is the candidate task, then the
-        // activity record.
-        if (windowingMode == WINDOWING_MODE_UNDEFINED) {
-            if (task != null) {
-                windowingMode = task.getWindowingMode();
-            }
-            if (windowingMode == WINDOWING_MODE_UNDEFINED && r != null) {
-                windowingMode = r.getWindowingMode();
-            }
-        }
-
-        // Make sure the windowing mode we are trying to use makes sense for what is supported.
-        boolean supportsMultiWindow = mService.mSupportsMultiWindow;
-        boolean supportsSplitScreen = mService.mSupportsSplitScreenMultiWindow;
-        boolean supportsFreeform = mService.mSupportsFreeformWindowManagement;
-        boolean supportsPip = mService.mSupportsPictureInPicture;
-        if (supportsMultiWindow) {
-            if (task != null) {
-                supportsMultiWindow = task.isResizeable();
-                supportsSplitScreen = task.supportsSplitScreenWindowingMode();
-                // TODO: Do we need to check for freeform and Pip support here?
-            } else if (r != null) {
-                supportsMultiWindow = r.isResizeable();
-                supportsSplitScreen = r.supportsSplitScreenWindowingMode();
-                supportsFreeform = r.supportsFreeform();
-                supportsPip = r.supportsPictureInPicture();
-            }
-        }
-
-        if (windowingMode != WINDOWING_MODE_UNDEFINED
-                && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen,
-                supportsFreeform, supportsPip, activityType)) {
-            return windowingMode;
-        }
-        // Return root/systems windowing mode
-        return getWindowingMode();
-    }
-
     int resolveActivityType(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
             @Nullable TaskRecord task) {
         // Preference is given to the activity type for the activity then the task since the type
@@ -2329,7 +2239,6 @@
         }
 
         final int activityType = resolveActivityType(r, options, candidateTask);
-        int windowingMode = resolveWindowingMode(r, options, candidateTask, activityType);
         T stack = null;
 
         // Next preference for stack goes to the display Id set in the activity options or the
@@ -2347,7 +2256,7 @@
             }
             final ActivityDisplay display = getActivityDisplayOrCreateLocked(displayId);
             if (display != null) {
-                stack = display.getOrCreateStack(windowingMode, activityType, onTop);
+                stack = display.getOrCreateStack(r, options, candidateTask, activityType, onTop);
                 if (stack != null) {
                     return stack;
                 }
@@ -2365,10 +2274,14 @@
             stack = r.getStack();
         }
         if (stack != null) {
-            if (stack.isCompatible(windowingMode, activityType)) {
-                return stack;
-            }
             display = stack.getDisplay();
+            if (display != null) {
+                final int windowingMode =
+                        display.resolveWindowingMode(r, options, candidateTask, activityType);
+                if (stack.isCompatible(windowingMode, activityType)) {
+                    return stack;
+                }
+            }
         }
 
         if (display == null
@@ -2379,7 +2292,7 @@
             display = getDefaultDisplay();
         }
 
-        return display.getOrCreateStack(windowingMode, activityType, onTop);
+        return display.getOrCreateStack(r, options, candidateTask, activityType, onTop);
     }
 
     /**
@@ -2596,6 +2509,8 @@
             final ActivityDisplay toDisplay = getActivityDisplay(toDisplayId);
 
             if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+                // Tell the display we are exiting split-screen mode.
+                toDisplay.onExitingSplitScreenMode();
                 // We are moving all tasks from the docked stack to the fullscreen stack,
                 // which is dismissing the docked stack, so resize all other stacks to
                 // fullscreen here already so we don't end up with resize trashing.
@@ -2625,35 +2540,34 @@
             final ArrayList<TaskRecord> tasks = fromStack.getAllTasks();
 
             if (!tasks.isEmpty()) {
+                mTmpOptions.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
                 final int size = tasks.size();
-                final ActivityStack fullscreenStack = toDisplay.getOrCreateStack(
-                        WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, onTop);
+                for (int i = 0; i < size; ++i) {
+                    final TaskRecord task = tasks.get(i);
+                    final ActivityStack toStack = toDisplay.getOrCreateStack(
+                                null, mTmpOptions, task, task.getActivityType(), onTop);
 
-                if (onTop) {
-                    final int returnToType =
-                            toDisplay.getTopVisibleStackActivityType(WINDOWING_MODE_PINNED);
-                    for (int i = 0; i < size; i++) {
-                        final TaskRecord task = tasks.get(i);
+                    if (onTop) {
+                        final int returnToType =
+                                toDisplay.getTopVisibleStackActivityType(WINDOWING_MODE_PINNED);
                         final boolean isTopTask = i == (size - 1);
                         if (inPinnedWindowingMode) {
-                            // Update the return-to to reflect where the pinned stack task was moved
-                            // from so that we retain the stack that was previously visible if the
-                            // pinned stack is recreated. See moveActivityToPinnedStackLocked().
+                            // Update the return-to to reflect where the pinned stack task was
+                            // moved from so that we retain the stack that was previously
+                            // visible if the pinned stack is recreated.
+                            // See moveActivityToPinnedStackLocked().
                             task.setTaskToReturnTo(returnToType);
                         }
                         // Defer resume until all the tasks have been moved to the fullscreen stack
-                        task.reparent(fullscreenStack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT,
+                        task.reparent(toStack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT,
                                 isTopTask /* animate */, DEFER_RESUME,
                                 schedulePictureInPictureModeChange,
                                 "moveTasksToFullscreenStack - onTop");
-                    }
-                } else {
-                    for (int i = 0; i < size; i++) {
-                        final TaskRecord task = tasks.get(i);
+                    } else {
                         // Position the tasks in the fullscreen stack in order at the bottom of the
                         // stack. Also defer resume until all the tasks have been moved to the
                         // fullscreen stack.
-                        task.reparent(fullscreenStack, i /* position */,
+                        task.reparent(toStack, ON_TOP,
                                 REPARENT_LEAVE_STACK_IN_PLACE, !ANIMATE, DEFER_RESUME,
                                 schedulePictureInPictureModeChange,
                                 "moveTasksToFullscreenStack - NOT_onTop");
@@ -3080,23 +2994,16 @@
                     + " task=" + task);
         }
 
-        // We don't allow moving a unresizeable task to the docked stack since the docked stack is
-        // used for split-screen mode and will cause things like the docked divider to show up. We
-        // instead leave the task in its current stack or move it to the fullscreen stack if it
-        // isn't currently in a stack.
+        // Leave the task in its current stack or a fullscreen stack if it isn't resizeable and the
+        // preferred stack is in multi-window mode.
         if (inMultiWindowMode && !task.isResizeable()) {
-            Slog.w(TAG, "Can not move unresizeable task=" + task + " to docked stack."
-                    + " Moving to stackId=" + stackId + " instead.");
-            // Temporarily disable resizeablility of the task as we don't want it to be resized if,
-            // for example, a docked stack is created which will lead to the stack we are moving
-            // from being resized and and its resizeable tasks being resized.
-            try {
-                task.mTemporarilyUnresizable = true;
-                stack = stack.getDisplay().createStack(
-                        WINDOWING_MODE_FULLSCREEN, stack.getActivityType(), toTop);
-            } finally {
-                task.mTemporarilyUnresizable = false;
+            Slog.w(TAG, "Can not move unresizeable task=" + task + " to multi-window stack=" + stack
+                    + " Moving to a fullscreen stack instead.");
+            if (prevStack != null) {
+                return prevStack;
             }
+            stack = stack.getDisplay().createStack(
+                    WINDOWING_MODE_FULLSCREEN, stack.getActivityType(), toTop);
         }
         return stack;
     }
@@ -4287,9 +4194,9 @@
         final boolean isSecondaryDisplayPreferred =
                 (preferredDisplayId != DEFAULT_DISPLAY && preferredDisplayId != INVALID_DISPLAY);
         final boolean inSplitScreenMode = actualStack != null
-                && actualStack.inSplitScreenWindowingMode();
+                && actualStack.getDisplay().hasSplitScreenPrimaryStack();
         if (((!inSplitScreenMode && preferredWindowingMode != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)
-                && !isSecondaryDisplayPreferred) || task.isActivityTypeHome()) {
+                && !isSecondaryDisplayPreferred) || !task.isActivityTypeStandardOrUndefined()) {
             return;
         }
 
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index c62cc38..aa82d00 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -1198,11 +1198,6 @@
                         + " (uid " + r.callingUid + ")");
                 skip = true;
             }
-            if (!skip) {
-                r.manifestCount++;
-            } else {
-                r.manifestSkipCount++;
-            }
             if (r.curApp != null && r.curApp.crashing) {
                 // If the target process is crashing, just skip it.
                 Slog.w(TAG, "Skipping deliver ordered [" + mQueueName + "] " + r
@@ -1283,6 +1278,16 @@
                 }
             }
 
+            if (!skip && !Intent.ACTION_SHUTDOWN.equals(r.intent.getAction())
+                    && !mService.mUserController
+                    .isUserRunning(UserHandle.getUserId(info.activityInfo.applicationInfo.uid),
+                            0 /* flags */)) {
+                skip = true;
+                Slog.w(TAG,
+                        "Skipping delivery to " + info.activityInfo.packageName + " / "
+                                + info.activityInfo.applicationInfo.uid + " : user is not running");
+            }
+
             if (skip) {
                 if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                         "Skipping delivery of ordered [" + mQueueName + "] "
@@ -1291,9 +1296,11 @@
                 r.receiver = null;
                 r.curFilter = null;
                 r.state = BroadcastRecord.IDLE;
+                r.manifestSkipCount++;
                 scheduleBroadcastsLocked();
                 return;
             }
+            r.manifestCount++;
 
             r.delivery[recIdx] = BroadcastRecord.DELIVERY_DELIVERED;
             r.state = BroadcastRecord.APP_RECEIVE;
@@ -1302,7 +1309,7 @@
             if (DEBUG_MU && r.callingUid > UserHandle.PER_USER_RANGE) {
                 Slog.v(TAG_MU, "Updated broadcast record activity info for secondary user, "
                         + info.activityInfo + ", callingUid = " + r.callingUid + ", uid = "
-                        + info.activityInfo.applicationInfo.uid);
+                        + receiverUid);
             }
 
             if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
@@ -1365,7 +1372,7 @@
                 // and mark the broadcast record as ready for the next.
                 Slog.w(TAG, "Unable to launch app "
                         + info.activityInfo.applicationInfo.packageName + "/"
-                        + info.activityInfo.applicationInfo.uid + " for broadcast "
+                        + receiverUid + " for broadcast "
                         + r.intent + ": process is bad");
                 logBroadcastReceiverDiscardLocked(r);
                 finishReceiverLocked(r, r.resultCode, r.resultData,
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index c451235..4080c27 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -231,9 +231,6 @@
     private boolean mSupportsPictureInPicture;  // Whether or not this task and its activities
             // support PiP. Based on the {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE} flag
             // of the root activity.
-    boolean mTemporarilyUnresizable; // Separate flag from mResizeMode used to suppress resize
-                                     // changes on a temporary basis.
-
     /** Can't be put in lockTask mode. */
     final static int LOCK_TASK_AUTH_DONT_LOCK = 0;
     /** Can enter app pinning with user approval. Can never start over existing lockTask task. */
@@ -1457,7 +1454,7 @@
 
     private boolean isResizeable(boolean checkSupportsPip) {
         return (mService.mForceResizableActivities || ActivityInfo.isResizeableMode(mResizeMode)
-                || (checkSupportsPip && mSupportsPictureInPicture)) && !mTemporarilyUnresizable;
+                || (checkSupportsPip && mSupportsPictureInPicture));
     }
 
     boolean isResizeable() {
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index e41c17d..4cf35bc 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -669,9 +669,11 @@
         for (String item : configValues) {
             if (DEBUG) Log.d(TAG, "GpsParamsResource: " + item);
             // We need to support "KEY =", but not "=VALUE".
-            String[] split = item.split("=");
-            if (split.length == 2) {
-                properties.setProperty(split[0].trim().toUpperCase(), split[1]);
+            int index = item.indexOf("=");
+            if (index > 0 && index + 1 < item.length()) {
+                String key = item.substring(0, index);
+                String value = item.substring(index + 1);
+                properties.setProperty(key.trim().toUpperCase(), value);
             } else {
                 Log.w(TAG, "malformed contents: " + item);
             }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 391deb7..7fb2ec4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -753,9 +753,6 @@
 
     PackageManagerInternal.ExternalSourcesPolicy mExternalSourcesPolicy;
 
-    // System configuration read by SystemConfig.
-    final int[] mGlobalGids;
-    final SparseArray<ArraySet<String>> mSystemPermissions;
     @GuardedBy("mAvailableFeatures")
     final ArrayMap<String, FeatureInfo> mAvailableFeatures;
 
@@ -938,10 +935,6 @@
     final ArrayMap<ComponentName, PackageParser.Instrumentation> mInstrumentation =
             new ArrayMap<ComponentName, PackageParser.Instrumentation>();
 
-    // Mapping from permission names to info about them.
-    final ArrayMap<String, PackageParser.PermissionGroup> mPermissionGroups =
-            new ArrayMap<String, PackageParser.PermissionGroup>();
-
     // Packages whose data we have transfered into another package, thus
     // should no longer exist.
     final ArraySet<String> mTransferedPackages = new ArraySet<String>();
@@ -2434,8 +2427,6 @@
 
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "get system config");
         SystemConfig systemConfig = SystemConfig.getInstance();
-        mGlobalGids = systemConfig.getGlobalGids();
-        mSystemPermissions = systemConfig.getSystemPermissions();
         mAvailableFeatures = systemConfig.getAvailableFeatures();
         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
 
@@ -4228,44 +4219,22 @@
     @Override
     public @Nullable ParceledListSlice<PermissionInfo> queryPermissionsByGroup(String groupName,
             int flags) {
-        // TODO Move this to PermissionManager when mPermissionGroups is moved there
-        synchronized (mPackages) {
-            if (groupName != null && !mPermissionGroups.containsKey(groupName)) {
-                // This is thrown as NameNotFoundException
-                return null;
-            }
-        }
-        return new ParceledListSlice<>(
-                mPermissionManager.getPermissionInfoByGroup(groupName, flags, getCallingUid()));
+        final List<PermissionInfo> permissionList =
+                mPermissionManager.getPermissionInfoByGroup(groupName, flags, getCallingUid());
+        return (permissionList == null) ? null : new ParceledListSlice<>(permissionList);
     }
 
     @Override
-    public PermissionGroupInfo getPermissionGroupInfo(String name, int flags) {
-        if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
-            return null;
-        }
-        // reader
-        synchronized (mPackages) {
-            return PackageParser.generatePermissionGroupInfo(
-                    mPermissionGroups.get(name), flags);
-        }
+    public PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags) {
+        return mPermissionManager.getPermissionGroupInfo(groupName, flags, getCallingUid());
     }
 
     @Override
     public @NonNull ParceledListSlice<PermissionGroupInfo> getAllPermissionGroups(int flags) {
-        if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
-            return ParceledListSlice.emptyList();
-        }
-        // reader
-        synchronized (mPackages) {
-            final int N = mPermissionGroups.size();
-            ArrayList<PermissionGroupInfo> out
-                    = new ArrayList<PermissionGroupInfo>(N);
-            for (PackageParser.PermissionGroup pg : mPermissionGroups.values()) {
-                out.add(PackageParser.generatePermissionGroupInfo(pg, flags));
-            }
-            return new ParceledListSlice<>(out);
-        }
+        final List<PermissionGroupInfo> permissionList =
+                mPermissionManager.getAllPermissionGroups(flags, getCallingUid());
+        return (permissionList == null)
+                ? ParceledListSlice.emptyList() : new ParceledListSlice<>(permissionList);
     }
 
     private ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags,
@@ -5138,59 +5107,7 @@
 
     @Override
     public int checkUidPermission(String permName, int uid) {
-        final int callingUid = Binder.getCallingUid();
-        final int callingUserId = UserHandle.getUserId(callingUid);
-        final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null;
-        final boolean isUidInstantApp = getInstantAppPackageName(uid) != null;
-        final int userId = UserHandle.getUserId(uid);
-        if (!sUserManager.exists(userId)) {
-            return PackageManager.PERMISSION_DENIED;
-        }
-
-        synchronized (mPackages) {
-            Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
-            if (obj != null) {
-                if (obj instanceof SharedUserSetting) {
-                    if (isCallerInstantApp) {
-                        return PackageManager.PERMISSION_DENIED;
-                    }
-                } else if (obj instanceof PackageSetting) {
-                    final PackageSetting ps = (PackageSetting) obj;
-                    if (filterAppAccessLPr(ps, callingUid, callingUserId)) {
-                        return PackageManager.PERMISSION_DENIED;
-                    }
-                }
-                final SettingBase settingBase = (SettingBase) obj;
-                final PermissionsState permissionsState = settingBase.getPermissionsState();
-                if (permissionsState.hasPermission(permName, userId)) {
-                    if (isUidInstantApp) {
-                        if (mSettings.mPermissions.isPermissionInstant(permName)) {
-                            return PackageManager.PERMISSION_GRANTED;
-                        }
-                    } else {
-                        return PackageManager.PERMISSION_GRANTED;
-                    }
-                }
-                // Special case: ACCESS_FINE_LOCATION permission includes ACCESS_COARSE_LOCATION
-                if (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName) && permissionsState
-                        .hasPermission(Manifest.permission.ACCESS_FINE_LOCATION, userId)) {
-                    return PackageManager.PERMISSION_GRANTED;
-                }
-            } else {
-                ArraySet<String> perms = mSystemPermissions.get(uid);
-                if (perms != null) {
-                    if (perms.contains(permName)) {
-                        return PackageManager.PERMISSION_GRANTED;
-                    }
-                    if (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName) && perms
-                            .contains(Manifest.permission.ACCESS_FINE_LOCATION)) {
-                        return PackageManager.PERMISSION_GRANTED;
-                    }
-                }
-            }
-        }
-
-        return PackageManager.PERMISSION_DENIED;
+        return mPermissionManager.checkUidPermission(permName, uid, getCallingUid());
     }
 
     @Override
@@ -11156,54 +11073,15 @@
                 if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Activities: " + r);
             }
 
-            N = pkg.permissionGroups.size();
-            r = null;
-            for (i=0; i<N; i++) {
-                PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i);
-                PackageParser.PermissionGroup cur = mPermissionGroups.get(pg.info.name);
-                final String curPackageName = cur == null ? null : cur.info.packageName;
-                // Dont allow ephemeral apps to define new permission groups.
-                if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
-                    Slog.w(TAG, "Permission group " + pg.info.name + " from package "
-                            + pg.info.packageName
-                            + " ignored: instant apps cannot define new permission groups.");
-                    continue;
-                }
-                final boolean isPackageUpdate = pg.info.packageName.equals(curPackageName);
-                if (cur == null || isPackageUpdate) {
-                    mPermissionGroups.put(pg.info.name, pg);
-                    if (chatty) {
-                        if (r == null) {
-                            r = new StringBuilder(256);
-                        } else {
-                            r.append(' ');
-                        }
-                        if (isPackageUpdate) {
-                            r.append("UPD:");
-                        }
-                        r.append(pg.info.name);
-                    }
-                } else {
-                    Slog.w(TAG, "Permission group " + pg.info.name + " from package "
-                            + pg.info.packageName + " ignored: original from "
-                            + cur.info.packageName);
-                    if (chatty) {
-                        if (r == null) {
-                            r = new StringBuilder(256);
-                        } else {
-                            r.append(' ');
-                        }
-                        r.append("DUP:");
-                        r.append(pg.info.name);
-                    }
-                }
-            }
-            if (r != null) {
-                if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Permission Groups: " + r);
+            // Don't allow ephemeral applications to define new permissions groups.
+            if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
+                Slog.w(TAG, "Permission groups from package " + pkg.packageName
+                        + " ignored: instant apps cannot define new permission groups.");
+            } else {
+                mPermissionManager.addAllPermissionGroups(pkg, chatty);
             }
 
-
-            // Dont allow ephemeral apps to define new permissions.
+            // Don't allow ephemeral applications to define new permissions.
             if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
                 Slog.w(TAG, "Permissions from package " + pkg.packageName
                         + " ignored: instant apps cannot define new permissions.");
@@ -12107,7 +11985,7 @@
             }
         }
 
-        permissionsState.setGlobalGids(mGlobalGids);
+        permissionsState.setGlobalGids(mPermissionManager.getGlobalGidsTEMP());
 
         final int N = pkg.requestedPermissions.size();
         for (int i=0; i<N; i++) {
@@ -23606,13 +23484,6 @@
         }
 
         @Override
-        public PackageParser.PermissionGroup getPermissionGroupTEMP(String groupName) {
-            synchronized (mPackages) {
-                return mPermissionGroups.get(groupName);
-            }
-        }
-
-        @Override
         public boolean isInstantApp(String packageName, int userId) {
             return PackageManagerService.this.isInstantApp(packageName, userId);
         }
diff --git a/services/core/java/com/android/server/pm/UserDataPreparer.java b/services/core/java/com/android/server/pm/UserDataPreparer.java
index b8b00af..bfe09b8 100644
--- a/services/core/java/com/android/server/pm/UserDataPreparer.java
+++ b/services/core/java/com/android/server/pm/UserDataPreparer.java
@@ -132,11 +132,9 @@
                 if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) {
                     FileUtils.deleteContentsAndDir(getUserSystemDirectory(userId));
                     FileUtils.deleteContentsAndDir(getDataSystemDeDirectory(userId));
-                    FileUtils.deleteContentsAndDir(getDataMiscDeDirectory(userId));
                 }
                 if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
                     FileUtils.deleteContentsAndDir(getDataSystemCeDirectory(userId));
-                    FileUtils.deleteContentsAndDir(getDataMiscCeDirectory(userId));
                 }
             }
 
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java
index 8aac52a..9605fcc 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.pm.PackageParser;
+import android.content.pm.PermissionGroupInfo;
 import android.content.pm.PermissionInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageManager.PermissionInfoFlags;
@@ -89,6 +90,7 @@
      * the permission settings.
      */
     public abstract void addAllPermissions(@NonNull PackageParser.Package pkg, boolean chatty);
+    public abstract void addAllPermissionGroups(@NonNull PackageParser.Package pkg, boolean chatty);
     public abstract void removeAllPermissions(@NonNull PackageParser.Package pkg, boolean chatty);
     public abstract boolean addDynamicPermission(@NonNull PermissionInfo info, boolean async,
             int callingUid, @Nullable PermissionCallback callback);
@@ -105,6 +107,16 @@
     public abstract int getPermissionFlags(@NonNull String permName,
             @NonNull String packageName, int callingUid, int userId);
     /**
+     * Retrieve all of the information we know about a particular group of permissions.
+     */
+    public abstract @Nullable PermissionGroupInfo getPermissionGroupInfo(
+            @NonNull String groupName, int flags, int callingUid);
+    /**
+     * Retrieve all of the known permission groups in the system.
+     */
+    public abstract @Nullable List<PermissionGroupInfo> getAllPermissionGroups(int flags,
+            int callingUid);
+    /**
      * Retrieve all of the information we know about a particular permission.
      */
     public abstract @Nullable PermissionInfo getPermissionInfo(@NonNull String permName,
@@ -132,6 +144,7 @@
 
     public abstract int checkPermission(@NonNull String permName, @NonNull String packageName,
             int callingUid, int userId);
+    public abstract int checkUidPermission(String permName, int uid, int callingUid);
 
     /**
      * Enforces the request is from the system or an app that has INTERACT_ACROSS_USERS
@@ -147,8 +160,6 @@
     public abstract @NonNull DefaultPermissionGrantPolicy getDefaultPermissionGrantPolicy();
 
     /** HACK HACK methods to allow for partial migration of data to the PermissionManager class */
-    public abstract Iterator<BasePermission> getPermissionIteratorTEMP();
     public abstract @Nullable BasePermission getPermissionTEMP(@NonNull String permName);
-    public abstract void putPermissionTEMP(@NonNull String permName,
-            @NonNull BasePermission permission);
+    public abstract @Nullable int[] getGlobalGidsTEMP();
 }
\ No newline at end of file
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index d2d857c..a94a00a 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -18,6 +18,7 @@
 
 import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
 import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
 
 import android.Manifest;
 import android.annotation.NonNull;
@@ -27,7 +28,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageParser;
-import android.content.pm.ParceledListSlice;
+import android.content.pm.PermissionGroupInfo;
 import android.content.pm.PermissionInfo;
 import android.content.pm.PackageParser.Package;
 import android.os.Binder;
@@ -43,6 +44,7 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseArray;
 
 import com.android.internal.R;
 import com.android.internal.logging.MetricsLogger;
@@ -58,6 +60,7 @@
 import com.android.server.pm.PackageSetting;
 import com.android.server.pm.ProcessLoggingHandler;
 import com.android.server.pm.SharedUserSetting;
+import com.android.server.pm.UserManagerService;
 import com.android.server.pm.permission.DefaultPermissionGrantPolicy.DefaultPermissionGrantedCallback;
 import com.android.server.pm.permission.PermissionManagerInternal.PermissionCallback;
 import com.android.server.pm.permission.PermissionsState.PermissionState;
@@ -122,6 +125,10 @@
     /** Default permission policy to provide proper behaviour out-of-the-box */
     private final DefaultPermissionGrantPolicy mDefaultPermissionGrantPolicy;
 
+    // System configuration read by SystemConfig.
+    private final SparseArray<ArraySet<String>> mSystemPermissions;
+    private final int[] mGlobalGids;
+
     /** Internal storage for permissions and related settings */
     private final PermissionSettings mSettings;
 
@@ -146,6 +153,9 @@
 
         mDefaultPermissionGrantPolicy = new DefaultPermissionGrantPolicy(
                 context, mHandlerThread.getLooper(), defaultGrantCallback, this);
+        SystemConfig systemConfig = SystemConfig.getInstance();
+        mSystemPermissions = systemConfig.getSystemPermissions();
+        mGlobalGids = systemConfig.getGlobalGids();
 
         // propagate permission configuration
         final ArrayMap<String, SystemConfig.PermissionEntry> permConfig =
@@ -230,14 +240,94 @@
         return PackageManager.PERMISSION_DENIED;
     }
 
-    private PermissionInfo getPermissionInfo(String name, String packageName, int flags,
+    private int checkUidPermission(String permName, int uid, int callingUid) {
+        final int callingUserId = UserHandle.getUserId(callingUid);
+        final boolean isCallerInstantApp =
+                mPackageManagerInt.getInstantAppPackageName(callingUid) != null;
+        final boolean isUidInstantApp =
+                mPackageManagerInt.getInstantAppPackageName(uid) != null;
+        final int userId = UserHandle.getUserId(uid);
+        if (!mUserManagerInt.exists(userId)) {
+            return PackageManager.PERMISSION_DENIED;
+        }
+
+        final String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
+        if (packages != null && packages.length > 0) {
+            final PackageParser.Package pkg = mPackageManagerInt.getPackage(packages[0]);
+            if (pkg.mSharedUserId != null) {
+                if (isCallerInstantApp) {
+                    return PackageManager.PERMISSION_DENIED;
+                }
+            } else {
+                if (mPackageManagerInt.filterAppAccess(pkg, callingUid, callingUserId)) {
+                    return PackageManager.PERMISSION_DENIED;
+                }
+            }
+            final PermissionsState permissionsState =
+                    ((PackageSetting) pkg.mExtras).getPermissionsState();
+            if (permissionsState.hasPermission(permName, userId)) {
+                if (isUidInstantApp) {
+                    if (mSettings.isPermissionInstant(permName)) {
+                        return PackageManager.PERMISSION_GRANTED;
+                    }
+                } else {
+                    return PackageManager.PERMISSION_GRANTED;
+                }
+            }
+            // Special case: ACCESS_FINE_LOCATION permission includes ACCESS_COARSE_LOCATION
+            if (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName) && permissionsState
+                    .hasPermission(Manifest.permission.ACCESS_FINE_LOCATION, userId)) {
+                return PackageManager.PERMISSION_GRANTED;
+            }
+        } else {
+            ArraySet<String> perms = mSystemPermissions.get(uid);
+            if (perms != null) {
+                if (perms.contains(permName)) {
+                    return PackageManager.PERMISSION_GRANTED;
+                }
+                if (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName) && perms
+                        .contains(Manifest.permission.ACCESS_FINE_LOCATION)) {
+                    return PackageManager.PERMISSION_GRANTED;
+                }
+            }
+        }
+        return PackageManager.PERMISSION_DENIED;
+    }
+
+    private PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags,
+            int callingUid) {
+        if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
+            return null;
+        }
+        synchronized (mLock) {
+            return PackageParser.generatePermissionGroupInfo(
+                    mSettings.mPermissionGroups.get(groupName), flags);
+        }
+    }
+
+    private List<PermissionGroupInfo> getAllPermissionGroups(int flags, int callingUid) {
+        if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
+            return null;
+        }
+        synchronized (mLock) {
+            final int N = mSettings.mPermissionGroups.size();
+            final ArrayList<PermissionGroupInfo> out
+                    = new ArrayList<PermissionGroupInfo>(N);
+            for (PackageParser.PermissionGroup pg : mSettings.mPermissionGroups.values()) {
+                out.add(PackageParser.generatePermissionGroupInfo(pg, flags));
+            }
+            return out;
+        }
+    }
+
+    private PermissionInfo getPermissionInfo(String permName, String packageName, int flags,
             int callingUid) {
         if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
             return null;
         }
         // reader
         synchronized (mLock) {
-            final BasePermission bp = mSettings.getPermissionLocked(name);
+            final BasePermission bp = mSettings.getPermissionLocked(permName);
             if (bp == null) {
                 return null;
             }
@@ -252,14 +342,10 @@
         if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
             return null;
         }
-        // reader
         synchronized (mLock) {
-            // TODO Uncomment when mPermissionGroups moves to this class
-//            if (groupName != null && !mPermissionGroups.containsKey(groupName)) {
-//                // This is thrown as NameNotFoundException
-//                return null;
-//            }
-
+            if (groupName != null && !mSettings.mPermissionGroups.containsKey(groupName)) {
+                return null;
+            }
             final ArrayList<PermissionInfo> out = new ArrayList<PermissionInfo>(10);
             for (BasePermission bp : mSettings.mPermissions.values()) {
                 final PermissionInfo pi = bp.generatePermissionInfo(groupName, flags);
@@ -314,21 +400,21 @@
             // Assume by default that we did not install this permission into the system.
             p.info.flags &= ~PermissionInfo.FLAG_INSTALLED;
 
-            // Now that permission groups have a special meaning, we ignore permission
-            // groups for legacy apps to prevent unexpected behavior. In particular,
-            // permissions for one app being granted to someone just because they happen
-            // to be in a group defined by another app (before this had no implications).
-            if (pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
-                p.group = mPackageManagerInt.getPermissionGroupTEMP(p.info.group);
-                // Warn for a permission in an unknown group.
-                if (PackageManagerService.DEBUG_PERMISSIONS
-                        && p.info.group != null && p.group == null) {
-                    Slog.i(TAG, "Permission " + p.info.name + " from package "
-                            + p.info.packageName + " in an unknown group " + p.info.group);
-                }
-            }
-
             synchronized (PermissionManagerService.this.mLock) {
+                // Now that permission groups have a special meaning, we ignore permission
+                // groups for legacy apps to prevent unexpected behavior. In particular,
+                // permissions for one app being granted to someone just because they happen
+                // to be in a group defined by another app (before this had no implications).
+                if (pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
+                    p.group = mSettings.mPermissionGroups.get(p.info.group);
+                    // Warn for a permission in an unknown group.
+                    if (PackageManagerService.DEBUG_PERMISSIONS
+                            && p.info.group != null && p.group == null) {
+                        Slog.i(TAG, "Permission " + p.info.name + " from package "
+                                + p.info.packageName + " in an unknown group " + p.info.group);
+                    }
+                }
+
                 if (p.tree) {
                     final BasePermission bp = BasePermission.createOrUpdate(
                             mSettings.getPermissionTreeLocked(p.info.name), p, pkg,
@@ -344,6 +430,48 @@
         }
     }
 
+    private void addAllPermissionGroups(PackageParser.Package pkg, boolean chatty) {
+        final int N = pkg.permissionGroups.size();
+        StringBuilder r = null;
+        for (int i=0; i<N; i++) {
+            final PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i);
+            final PackageParser.PermissionGroup cur = mSettings.mPermissionGroups.get(pg.info.name);
+            final String curPackageName = (cur == null) ? null : cur.info.packageName;
+            final boolean isPackageUpdate = pg.info.packageName.equals(curPackageName);
+            if (cur == null || isPackageUpdate) {
+                mSettings.mPermissionGroups.put(pg.info.name, pg);
+                if (chatty && PackageManagerService.DEBUG_PACKAGE_SCANNING) {
+                    if (r == null) {
+                        r = new StringBuilder(256);
+                    } else {
+                        r.append(' ');
+                    }
+                    if (isPackageUpdate) {
+                        r.append("UPD:");
+                    }
+                    r.append(pg.info.name);
+                }
+            } else {
+                Slog.w(TAG, "Permission group " + pg.info.name + " from package "
+                        + pg.info.packageName + " ignored: original from "
+                        + cur.info.packageName);
+                if (chatty && PackageManagerService.DEBUG_PACKAGE_SCANNING) {
+                    if (r == null) {
+                        r = new StringBuilder(256);
+                    } else {
+                        r.append(' ');
+                    }
+                    r.append("DUP:");
+                    r.append(pg.info.name);
+                }
+            }
+        }
+        if (r != null && PackageManagerService.DEBUG_PACKAGE_SCANNING) {
+            Log.d(TAG, "  Permission Groups: " + r);
+        }
+
+    }
+
     private void removeAllPermissions(PackageParser.Package pkg, boolean chatty) {
         synchronized (mLock) {
             int N = pkg.permissions.size();
@@ -1158,6 +1286,10 @@
             PermissionManagerService.this.addAllPermissions(pkg, chatty);
         }
         @Override
+        public void addAllPermissionGroups(Package pkg, boolean chatty) {
+            PermissionManagerService.this.addAllPermissionGroups(pkg, chatty);
+        }
+        @Override
         public void removeAllPermissions(Package pkg, boolean chatty) {
             PermissionManagerService.this.removeAllPermissions(pkg, chatty);
         }
@@ -1252,6 +1384,20 @@
                     permName, packageName, callingUid, userId);
         }
         @Override
+        public int checkUidPermission(String permName, int uid, int callingUid) {
+            return PermissionManagerService.this.checkUidPermission(permName, uid, callingUid);
+        }
+        @Override
+        public PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags,
+                int callingUid) {
+            return PermissionManagerService.this.getPermissionGroupInfo(
+                    groupName, flags, callingUid);
+        }
+        @Override
+        public List<PermissionGroupInfo> getAllPermissionGroups(int flags, int callingUid) {
+            return PermissionManagerService.this.getAllPermissionGroups(flags, callingUid);
+        }
+        @Override
         public PermissionInfo getPermissionInfo(String permName, String packageName, int flags,
                 int callingUid) {
             return PermissionManagerService.this.getPermissionInfo(
@@ -1277,15 +1423,9 @@
             }
         }
         @Override
-        public void putPermissionTEMP(String permName, BasePermission permission) {
+        public int[] getGlobalGidsTEMP() {
             synchronized (PermissionManagerService.this.mLock) {
-                mSettings.putPermissionLocked(permName, (BasePermission) permission);
-            }
-        }
-        @Override
-        public Iterator<BasePermission> getPermissionIteratorTEMP() {
-            synchronized (PermissionManagerService.this.mLock) {
-                return mSettings.getAllPermissionsLocked().iterator();
+                return mGlobalGids;
             }
         }
     }
diff --git a/services/core/java/com/android/server/pm/permission/PermissionSettings.java b/services/core/java/com/android/server/pm/permission/PermissionSettings.java
index 7d125c9..0ed94a1 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionSettings.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionSettings.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.content.pm.PackageParser;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
@@ -64,6 +65,14 @@
             new ArrayMap<String, BasePermission>();
 
     /**
+     * All permisson groups know to the system. The mapping is from permission group
+     * name to permission group object.
+     */
+    @GuardedBy("mLock")
+    final ArrayMap<String, PackageParser.PermissionGroup> mPermissionGroups =
+            new ArrayMap<String, PackageParser.PermissionGroup>();
+
+    /**
      * Set of packages that request a particular app op. The mapping is from permission
      * name to package names.
      */
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 3fdafc7..21dffff 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -22,6 +22,10 @@
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
+import android.animation.Animator;
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
+import android.annotation.Nullable;
 import android.content.ClipData;
 import android.content.ClipDescription;
 import android.content.Context;
@@ -29,7 +33,9 @@
 import android.graphics.Point;
 import android.hardware.input.InputManager;
 import android.os.Build;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.Message;
 import android.os.Process;
 import android.os.RemoteException;
@@ -44,16 +50,12 @@
 import android.view.InputDevice;
 import android.view.PointerIcon;
 import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
 import android.view.View;
 import android.view.WindowManager;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.Animation;
-import android.view.animation.AnimationSet;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
-import android.view.animation.ScaleAnimation;
 import android.view.animation.Transformation;
-import android.view.animation.TranslateAnimation;
 
 import com.android.server.input.InputApplicationHandle;
 import com.android.server.input.InputWindowHandle;
@@ -78,8 +80,20 @@
             View.DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION |
             View.DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION;
 
+    // Property names for animations
+    private static final String ANIMATED_PROPERTY_X = "x";
+    private static final String ANIMATED_PROPERTY_Y = "y";
+    private static final String ANIMATED_PROPERTY_ALPHA = "alpha";
+    private static final String ANIMATED_PROPERTY_SCALE = "scale";
+
+    // Messages for Handler.
+    private static final int MSG_ANIMATION_END = 0;
+
     final WindowManagerService mService;
     IBinder mToken;
+    /**
+     * Do not use the variable from the out of animation thread while mAnimator is not null.
+     */
     SurfaceControl mSurfaceControl;
     int mFlags;
     IBinder mLocalWin;
@@ -101,10 +115,10 @@
     boolean mDragInProgress;
     DisplayContent mDisplayContent;
 
-    private Animation mAnimation;
-    final Transformation mTransformation = new Transformation();
+    @Nullable private ValueAnimator mAnimator;
     private final Interpolator mCubicEaseOutInterpolator = new DecelerateInterpolator(1.5f);
     private Point mDisplaySize = new Point();
+    private final Handler mHandler;
 
     DragState(WindowManagerService service, IBinder token, SurfaceControl surface,
             int flags, IBinder localWin) {
@@ -114,9 +128,14 @@
         mFlags = flags;
         mLocalWin = localWin;
         mNotifiedWindows = new ArrayList<WindowState>();
+        mHandler = new DragStateHandler(service.mH.getLooper());
     }
 
     void reset() {
+        if (mAnimator != null) {
+            Slog.wtf(TAG_WM,
+                    "Unexpectedly destroying mSurfaceControl while animation is running");
+        }
         if (mSurfaceControl != null) {
             mSurfaceControl.destroy();
         }
@@ -388,11 +407,11 @@
     }
 
     void endDragLw() {
-        if (mAnimation != null) {
+        if (mAnimator != null) {
             return;
         }
         if (!mDragResult) {
-            mAnimation = createReturnAnimationLocked();
+            mAnimator = createReturnAnimationLocked();
             mService.scheduleAnimationLocked();
             return;  // Will call cleanUpDragLw when the animation is done.
         }
@@ -400,11 +419,22 @@
     }
 
     void cancelDragLw() {
-        if (mAnimation != null) {
+        if (mAnimator != null) {
             return;
         }
-        mAnimation = createCancelAnimationLocked();
-        mService.scheduleAnimationLocked();
+        if (!mDragInProgress) {
+            // This can happen if an app invokes Session#cancelDragAndDrop before
+            // Session#performDrag. Reset the drag state:
+            // 1. without sending the end broadcast because the start broadcast has not been sent,
+            // and
+            // 2. without playing the cancel animation because H.DRAG_START_TIMEOUT may be sent to
+            //    WindowManagerService, which will cause DragState#reset() while playing the
+            //    cancel animation.
+            reset();
+            mService.mDragState = null;
+            return;
+        }
+        mAnimator = createCancelAnimationLocked();
     }
 
     private void cleanUpDragLw() {
@@ -422,7 +452,7 @@
     }
 
     void notifyMoveLw(float x, float y) {
-        if (mAnimation != null) {
+        if (mAnimator != null) {
             return;
         }
         mCurrentX = x;
@@ -491,7 +521,7 @@
     // dispatch the global drag-ended message, 'false' if we need to wait for a
     // result from the recipient.
     boolean notifyDropLw(float x, float y) {
-        if (mAnimation != null) {
+        if (mAnimator != null) {
             return false;
         }
         mCurrentX = x;
@@ -560,56 +590,52 @@
                 dragAndDropPermissions, result);
     }
 
-    boolean stepAnimationLocked(long currentTimeMs) {
-        if (mAnimation == null) {
-            return false;
-        }
+    private ValueAnimator createReturnAnimationLocked() {
+        final ValueAnimator animator = ValueAnimator.ofPropertyValuesHolder(
+                PropertyValuesHolder.ofFloat(
+                        ANIMATED_PROPERTY_X, mCurrentX - mThumbOffsetX,
+                        mOriginalX - mThumbOffsetX),
+                PropertyValuesHolder.ofFloat(
+                        ANIMATED_PROPERTY_Y, mCurrentY - mThumbOffsetY,
+                        mOriginalY - mThumbOffsetY),
+                PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_SCALE, 1, 1),
+                PropertyValuesHolder.ofFloat(
+                        ANIMATED_PROPERTY_ALPHA, mOriginalAlpha, mOriginalAlpha / 2));
 
-        mTransformation.clear();
-        if (!mAnimation.getTransformation(currentTimeMs, mTransformation)) {
-            cleanUpDragLw();
-            return false;
-        }
-
-        mTransformation.getMatrix().postTranslate(
-                mCurrentX - mThumbOffsetX, mCurrentY - mThumbOffsetY);
-        final float tmpFloats[] = mService.mTmpFloats;
-        mTransformation.getMatrix().getValues(tmpFloats);
-        mSurfaceControl.setPosition(tmpFloats[Matrix.MTRANS_X], tmpFloats[Matrix.MTRANS_Y]);
-        mSurfaceControl.setAlpha(mTransformation.getAlpha());
-        mSurfaceControl.setMatrix(tmpFloats[Matrix.MSCALE_X], tmpFloats[Matrix.MSKEW_Y],
-                tmpFloats[Matrix.MSKEW_X], tmpFloats[Matrix.MSCALE_Y]);
-        return true;
-    }
-
-    private Animation createReturnAnimationLocked() {
-        final AnimationSet set = new AnimationSet(false);
         final float translateX = mOriginalX - mCurrentX;
         final float translateY = mOriginalY - mCurrentY;
-        set.addAnimation(new TranslateAnimation( 0, translateX, 0, translateY));
-        set.addAnimation(new AlphaAnimation(mOriginalAlpha, mOriginalAlpha / 2));
         // Adjust the duration to the travel distance.
         final double travelDistance = Math.sqrt(translateX * translateX + translateY * translateY);
         final double displayDiagonal =
                 Math.sqrt(mDisplaySize.x * mDisplaySize.x + mDisplaySize.y * mDisplaySize.y);
         final long duration = MIN_ANIMATION_DURATION_MS + (long) (travelDistance / displayDiagonal
                 * (MAX_ANIMATION_DURATION_MS - MIN_ANIMATION_DURATION_MS));
-        set.setDuration(duration);
-        set.setInterpolator(mCubicEaseOutInterpolator);
-        set.initialize(0, 0, 0, 0);
-        set.start();  // Will start on the first call to getTransformation.
-        return set;
+        final AnimationListener listener = new AnimationListener();
+        animator.setDuration(duration);
+        animator.setInterpolator(mCubicEaseOutInterpolator);
+        animator.addListener(listener);
+        animator.addUpdateListener(listener);
+
+        mService.mAnimationHandler.post(() -> animator.start());
+        return animator;
     }
 
-    private Animation createCancelAnimationLocked() {
-        final AnimationSet set = new AnimationSet(false);
-        set.addAnimation(new ScaleAnimation(1, 0, 1, 0, mThumbOffsetX, mThumbOffsetY));
-        set.addAnimation(new AlphaAnimation(mOriginalAlpha, 0));
-        set.setDuration(MIN_ANIMATION_DURATION_MS);
-        set.setInterpolator(mCubicEaseOutInterpolator);
-        set.initialize(0, 0, 0, 0);
-        set.start();  // Will start on the first call to getTransformation.
-        return set;
+    private ValueAnimator createCancelAnimationLocked() {
+        final ValueAnimator animator = ValueAnimator.ofPropertyValuesHolder(
+                PropertyValuesHolder.ofFloat(
+                        ANIMATED_PROPERTY_X, mCurrentX - mThumbOffsetX, mCurrentX),
+                PropertyValuesHolder.ofFloat(
+                        ANIMATED_PROPERTY_Y, mCurrentY - mThumbOffsetY, mCurrentY),
+                PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_SCALE, 1, 0),
+                PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_ALPHA, mOriginalAlpha, 0));
+        final AnimationListener listener = new AnimationListener();
+        animator.setDuration(MIN_ANIMATION_DURATION_MS);
+        animator.setInterpolator(mCubicEaseOutInterpolator);
+        animator.addListener(listener);
+        animator.addUpdateListener(listener);
+
+        mService.mAnimationHandler.post(() -> animator.start());
+        return animator;
     }
 
     private boolean isFromSource(int source) {
@@ -622,4 +648,68 @@
             InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_GRABBING);
         }
     }
+
+    private class DragStateHandler extends Handler {
+        DragStateHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_ANIMATION_END:
+                    synchronized (mService.mWindowMap) {
+                        if (mService.mDragState != DragState.this) {
+                            Slog.wtf(TAG_WM, "mDragState is updated unexpectedly while " +
+                                    "playing animation");
+                            return;
+                        }
+                        if (mAnimator == null) {
+                            Slog.wtf(TAG_WM, "Unexpected null mAnimator");
+                            return;
+                        }
+                        mAnimator = null;
+                        cleanUpDragLw();
+                    }
+                    break;
+            }
+        }
+    }
+
+    private class AnimationListener
+            implements ValueAnimator.AnimatorUpdateListener, Animator.AnimatorListener {
+        @Override
+        public void onAnimationUpdate(ValueAnimator animation) {
+            try (final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction()) {
+                transaction.setPosition(
+                        mSurfaceControl,
+                        (float) mAnimator.getAnimatedValue(ANIMATED_PROPERTY_X),
+                        (float) mAnimator.getAnimatedValue(ANIMATED_PROPERTY_Y));
+                transaction.setAlpha(
+                        mSurfaceControl,
+                        (float) mAnimator.getAnimatedValue(ANIMATED_PROPERTY_ALPHA));
+                transaction.setMatrix(
+                        mSurfaceControl,
+                        (float) mAnimator.getAnimatedValue(ANIMATED_PROPERTY_SCALE), 0,
+                        0, (float) mAnimator.getAnimatedValue(ANIMATED_PROPERTY_SCALE));
+                transaction.apply();
+            }
+        }
+
+        @Override
+        public void onAnimationStart(Animator animator) {}
+
+        @Override
+        public void onAnimationCancel(Animator animator) {}
+
+        @Override
+        public void onAnimationRepeat(Animator animator) {}
+
+        @Override
+        public void onAnimationEnd(Animator animator) {
+            // Updating mDragState requires the WM lock so continues it on the out of
+            // AnimationThread.
+            mHandler.sendEmptyMessage(MSG_ANIMATION_END);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 4dd147e..2bb0235 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -68,9 +68,7 @@
  * This class represents an active client session.  There is generally one
  * Session object per process that is interacting with the window manager.
  */
-// Needs to be public and not final so we can mock during tests...sucks I know :(
-public class Session extends IWindowSession.Stub
-        implements IBinder.DeathRecipient {
+class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
     final WindowManagerService mService;
     final IWindowSessionCallback mCallback;
     final IInputMethodClient mClient;
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index c01ee31..e409a68 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -223,10 +223,6 @@
                     }
                 }
 
-                if (mService.mDragState != null) {
-                    mAnimating |= mService.mDragState.stepAnimationLocked(mCurrentTime);
-                }
-
                 if (!mAnimating) {
                     cancelAnimation();
                 }
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 679be1d..9e4a9e9 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
@@ -57,7 +57,7 @@
             ComponentName.unflattenFromString("com.foo/.BarActivity2");
 
     private ActivityManagerService mService;
-    private ActivityStack mStack;
+    private TestActivityStack mStack;
     private TaskRecord mTask;
     private ActivityRecord mActivity;
 
@@ -76,13 +76,13 @@
     @Test
     public void testStackCleanupOnClearingTask() throws Exception {
         mActivity.setTask(null);
-        assertEquals(getActivityRemovedFromStackCount(), 1);
+        assertEquals(mStack.onActivityRemovedFromStackInvocationCount(), 1);
     }
 
     @Test
     public void testStackCleanupOnActivityRemoval() throws Exception {
         mTask.removeActivity(mActivity);
-        assertEquals(getActivityRemovedFromStackCount(),  1);
+        assertEquals(mStack.onActivityRemovedFromStackInvocationCount(),  1);
     }
 
     @Test
@@ -97,7 +97,7 @@
         final TaskRecord newTask =
                 createTask(mService.mStackSupervisor, testActivityComponent, mStack);
         mActivity.reparent(newTask, 0, null /*reason*/);
-        assertEquals(getActivityRemovedFromStackCount(), 0);
+        assertEquals(mStack.onActivityRemovedFromStackInvocationCount(), 0);
     }
 
     @Test
@@ -129,15 +129,6 @@
         assertEquals(expectedActivityBounds, mActivity.getBounds());
     }
 
-    private int getActivityRemovedFromStackCount() {
-        if (mStack instanceof ActivityStackReporter) {
-            return ((ActivityStackReporter) mStack).onActivityRemovedFromStackInvocationCount();
-        }
-
-        return -1;
-    }
-
-
     @Test
     public void testCanBeLaunchedOnDisplay() throws Exception {
         testSupportsLaunchingResizeable(false /*taskPresent*/, true /*taskResizeable*/,
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
index 4ee1f47..e17e51b 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
@@ -16,13 +16,19 @@
 
 package com.android.server.am;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 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.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
 import android.content.ComponentName;
 import android.content.pm.ActivityInfo;
@@ -45,7 +51,6 @@
 @Presubmit
 @RunWith(AndroidJUnit4.class)
 public class ActivityStackTests extends ActivityTestsBase {
-    private static final int TEST_STACK_ID = 100;
     private static final ComponentName testActivityComponent =
             ComponentName.unflattenFromString("com.foo/.BarActivity");
     private static final ComponentName testOverlayComponent =
@@ -127,4 +132,122 @@
         assertEquals(mTask.getTopActivity(true /* includeOverlays */), taskOverlay);
         assertNotNull(result.r);
     }
+
+    @Test
+    public void testShouldBeVisible_Fullscreen() throws Exception {
+        final ActivityDisplay display = mService.mStackSupervisor.getDefaultDisplay();
+        final TestActivityStack homeStack = createStackForShouldBeVisibleTest(display,
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
+        final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(display,
+                WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+
+        assertTrue(homeStack.shouldBeVisible(null /* starting */));
+        assertTrue(pinnedStack.shouldBeVisible(null /* starting */));
+
+        final TestActivityStack fullscreenStack = createStackForShouldBeVisibleTest(display,
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+        // Home stack shouldn't be visible behind an opaque fullscreen stack, but pinned stack
+        // should be visible since it is always on-top.
+        fullscreenStack.setIsTranslucent(false);
+        assertFalse(homeStack.shouldBeVisible(null /* starting */));
+        assertTrue(pinnedStack.shouldBeVisible(null /* starting */));
+        assertTrue(fullscreenStack.shouldBeVisible(null /* starting */));
+
+        // Home stack should be visible behind a translucent fullscreen stack.
+        fullscreenStack.setIsTranslucent(true);
+        assertTrue(homeStack.shouldBeVisible(null /* starting */));
+        assertTrue(pinnedStack.shouldBeVisible(null /* starting */));
+    }
+
+    @Test
+    public void testShouldBeVisible_SplitScreen() throws Exception {
+        final ActivityDisplay display = mService.mStackSupervisor.getDefaultDisplay();
+        final TestActivityStack homeStack = createStackForShouldBeVisibleTest(display,
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
+        final TestActivityStack splitScreenPrimary = createStackForShouldBeVisibleTest(display,
+                WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+        final TestActivityStack splitScreenSecondary = createStackForShouldBeVisibleTest(display,
+                WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+
+        // Home stack shouldn't be visible if both halves of split-screen are opaque.
+        splitScreenPrimary.setIsTranslucent(false);
+        splitScreenSecondary.setIsTranslucent(false);
+        assertFalse(homeStack.shouldBeVisible(null /* starting */));
+        assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
+        assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
+
+        // Home stack should be visible if one of the halves of split-screen is translucent.
+        splitScreenPrimary.setIsTranslucent(true);
+        assertTrue(homeStack.shouldBeVisible(null /* starting */));
+        assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
+        assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
+
+        final TestActivityStack splitScreenSecondary2 = createStackForShouldBeVisibleTest(display,
+                WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+        // First split-screen secondary shouldn't be visible behind another opaque split-split
+        // secondary.
+        splitScreenSecondary2.setIsTranslucent(false);
+        assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */));
+        assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
+
+        // First split-screen secondary should be visible behind another translucent split-split
+        // secondary.
+        splitScreenSecondary2.setIsTranslucent(true);
+        assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
+        assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
+
+        final TestActivityStack assistantStack = createStackForShouldBeVisibleTest(display,
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, true /* onTop */);
+
+        // Split-screen stacks shouldn't be visible behind an opaque fullscreen stack.
+        assistantStack.setIsTranslucent(false);
+        assertTrue(assistantStack.shouldBeVisible(null /* starting */));
+        assertFalse(splitScreenPrimary.shouldBeVisible(null /* starting */));
+        assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */));
+        assertFalse(splitScreenSecondary2.shouldBeVisible(null /* starting */));
+
+        // Split-screen stacks should be visible behind a translucent fullscreen stack.
+        assistantStack.setIsTranslucent(true);
+        assertTrue(assistantStack.shouldBeVisible(null /* starting */));
+        assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
+        assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
+        assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
+    }
+
+    @Test
+    public void testShouldBeVisible_Finishing() throws Exception {
+        final ActivityDisplay display = mService.mStackSupervisor.getDefaultDisplay();
+        final TestActivityStack homeStack = createStackForShouldBeVisibleTest(display,
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
+        final TestActivityStack translucentStack = createStackForShouldBeVisibleTest(display,
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+        translucentStack.setIsTranslucent(true);
+
+        assertTrue(homeStack.shouldBeVisible(null /* starting */));
+        assertTrue(translucentStack.shouldBeVisible(null /* starting */));
+
+        final ActivityRecord topRunningHomeActivity = homeStack.topRunningActivityLocked();
+        topRunningHomeActivity.finishing = true;
+        final ActivityRecord topRunningTranslucentActivity =
+                translucentStack.topRunningActivityLocked();
+        topRunningTranslucentActivity.finishing = true;
+
+        // Home shouldn't be visible since its activity is marked as finishing and it isn't the top
+        // of the stack list.
+        assertFalse(homeStack.shouldBeVisible(null /* starting */));
+        // Home should be visible if we are starting an activity within it.
+        assertTrue(homeStack.shouldBeVisible(topRunningHomeActivity /* starting */));
+        // The translucent stack should be visible since it is the top of the stack list even though
+        // it has its activity marked as finishing.
+        assertTrue(translucentStack.shouldBeVisible(null /* starting */));
+    }
+
+    private <T extends ActivityStack> T createStackForShouldBeVisibleTest(
+            ActivityDisplay display, int windowingMode, int activityType, boolean onTop) {
+        final T stack = display.createStack(windowingMode, activityType, onTop);
+        // Create a task and activity in the stack so that it has a top running activity.
+        final TaskRecord task = createTask(mSupervisor, testActivityComponent, stack);
+        final ActivityRecord r = createActivity(mService, testActivityComponent, task, 0);
+        return stack;
+    }
 }
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 d36f9d3..f5cdf21 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -276,20 +276,21 @@
         return service;
     }
 
-    protected interface ActivityStackReporter {
-        int onActivityRemovedFromStackInvocationCount();
-    }
-
     /**
      * Overrided of {@link ActivityStack} that tracks test metrics, such as the number of times a
      * method is called. Note that its functionality depends on the implementations of the
      * construction arguments.
      */
     protected static class TestActivityStack<T extends StackWindowController>
-            extends ActivityStack<T> implements ActivityStackReporter {
+            extends ActivityStack<T> {
         private int mOnActivityRemovedFromStackCount = 0;
         private T mContainerController;
 
+        static final int IS_TRANSLUCENT_UNSET = 0;
+        static final int IS_TRANSLUCENT_FALSE = 1;
+        static final int IS_TRANSLUCENT_TRUE = 2;
+        private int mIsTranslucent = IS_TRANSLUCENT_UNSET;
+
         TestActivityStack(ActivityDisplay display, int stackId, ActivityStackSupervisor supervisor,
                 int windowingMode, int activityType, boolean onTop) {
             super(display, stackId, supervisor, windowingMode, activityType, onTop);
@@ -302,8 +303,7 @@
         }
 
         // Returns the number of times {@link #onActivityRemovedFromStack} has been called
-        @Override
-        public int onActivityRemovedFromStackInvocationCount() {
+        int onActivityRemovedFromStackInvocationCount() {
             return mOnActivityRemovedFromStackCount;
         }
 
@@ -317,5 +317,22 @@
         T getWindowContainerController() {
             return mContainerController;
         }
+
+        void setIsTranslucent(boolean isTranslucent) {
+            mIsTranslucent = isTranslucent ? IS_TRANSLUCENT_TRUE : IS_TRANSLUCENT_FALSE;
+        }
+
+        @Override
+        boolean isStackTranslucent(ActivityRecord starting, ActivityStack stackBehind) {
+            switch (mIsTranslucent) {
+                case IS_TRANSLUCENT_TRUE:
+                    return true;
+                case IS_TRANSLUCENT_FALSE:
+                    return false;
+                case IS_TRANSLUCENT_UNSET:
+                default:
+                    return super.isStackTranslucent(starting, stackBehind);
+            }
+        }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserDataPreparerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserDataPreparerTest.java
index 7a676e25..bb35beb 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserDataPreparerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserDataPreparerTest.java
@@ -154,9 +154,6 @@
         File systemDeDir = mUserDataPreparer.getDataSystemDeDirectory(TEST_USER_ID);
         systemDeDir.mkdirs();
         writeFile(new File(systemDeDir, "file"), "-----" );
-        File miscDeDir = mUserDataPreparer.getDataMiscDeDirectory(TEST_USER_ID);
-        miscDeDir.mkdirs();
-        writeFile(new File(miscDeDir, "file"), "-----" );
 
         mUserDataPreparer.destroyUserData(TEST_USER_ID, StorageManager.FLAG_STORAGE_DE);
 
@@ -168,8 +165,6 @@
         assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty(systemDir)));
         assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty(
                 systemDeDir)));
-        assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty(
-                miscDeDir)));
     }
 
     @Test
@@ -177,9 +172,6 @@
         File systemCeDir = mUserDataPreparer.getDataSystemCeDirectory(TEST_USER_ID);
         systemCeDir.mkdirs();
         writeFile(new File(systemCeDir, "file"), "-----" );
-        File miscCeDir = mUserDataPreparer.getDataMiscCeDirectory(TEST_USER_ID);
-        miscCeDir.mkdirs();
-        writeFile(new File(miscCeDir, "file"), "-----" );
 
         mUserDataPreparer.destroyUserData(TEST_USER_ID, StorageManager.FLAG_STORAGE_CE);
 
@@ -190,8 +182,6 @@
 
         assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty(
                 systemCeDir)));
-        assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty(
-                miscCeDir)));
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index b8e8946..0980f7e 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -63,7 +63,7 @@
 class WindowTestsBase {
     static WindowManagerService sWm = null;
     private static final IWindow sIWindow = new TestIWindow();
-    private static final Session sMockSession = mock(Session.class);
+    private static Session sMockSession;
     // The default display is removed in {@link #setUp} and then we iterate over all displays to
     // make sure we don't collide with any existing display. If we run into no other display, the
     // added display should be treated as default. This cannot be the default display
@@ -93,6 +93,7 @@
             // Allows to mock package local classes and methods
             System.setProperty("dexmaker.share_classloader", "true");
             MockitoAnnotations.initMocks(this);
+            sMockSession = mock(Session.class);
         }
 
         final Context context = InstrumentationRegistry.getTargetContext();
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 6029995..98195ad 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -390,20 +390,23 @@
      * Inject an SMS PDU into the android application framework.
      *
      * <p>Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} or carrier
-     * privileges. @see android.telephony.TelephonyManager#hasCarrierPrivileges
+     * privileges per {@link android.telephony.TelephonyManager#hasCarrierPrivileges}.
      *
      * @param pdu is the byte array of pdu to be injected into android application framework
-     * @param format is the format of SMS pdu (3gpp or 3gpp2)
+     * @param format is the format of SMS pdu ({@link SmsMessage#FORMAT_3GPP} or
+     *  {@link SmsMessage#FORMAT_3GPP2})
      * @param receivedIntent if not NULL this <code>PendingIntent</code> is
      *  broadcast when the message is successfully received by the
      *  android application framework, or failed. This intent is broadcasted at
      *  the same time an SMS received from radio is acknowledged back.
-     *  The result code will be <code>RESULT_SMS_HANDLED</code> for success, or
-     *  <code>RESULT_SMS_GENERIC_ERROR</code> for error.
+     *  The result code will be {@link android.provider.Telephony.Sms.Intents#RESULT_SMS_HANDLED}
+     *  for success, or {@link android.provider.Telephony.Sms.Intents#RESULT_SMS_GENERIC_ERROR} for
+     *  error.
      *
-     * @throws IllegalArgumentException if format is not one of 3gpp and 3gpp2.
+     * @throws IllegalArgumentException if the format is invalid.
      */
-    public void injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent) {
+    public void injectSmsPdu(
+            byte[] pdu, @SmsMessage.Format String format, PendingIntent receivedIntent) {
         if (!format.equals(SmsMessage.FORMAT_3GPP) && !format.equals(SmsMessage.FORMAT_3GPP2)) {
             // Format must be either 3gpp or 3gpp2.
             throw new IllegalArgumentException(
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index dcdda86..df41233 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -16,24 +16,25 @@
 
 package android.telephony;
 
-import android.os.Binder;
-import android.os.Parcel;
+import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA;
+
+import android.annotation.StringDef;
 import android.content.res.Resources;
+import android.os.Binder;
 import android.text.TextUtils;
 
 import com.android.internal.telephony.GsmAlphabet;
 import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
+import com.android.internal.telephony.Sms7BitEncodingTranslator;
 import com.android.internal.telephony.SmsConstants;
 import com.android.internal.telephony.SmsMessageBase;
 import com.android.internal.telephony.SmsMessageBase.SubmitPduBase;
-import com.android.internal.telephony.Sms7BitEncodingTranslator;
 
-import java.lang.Math;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Arrays;
 
-import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA;
-
 
 /**
  * A Short Message Service message.
@@ -81,15 +82,18 @@
      */
     public static final int MAX_USER_DATA_SEPTETS_WITH_HEADER = 153;
 
+    /** @hide */
+    @StringDef({FORMAT_3GPP, FORMAT_3GPP2})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Format {}
+
     /**
      * Indicates a 3GPP format SMS message.
-     * @hide pending API council approval
      */
     public static final String FORMAT_3GPP = "3gpp";
 
     /**
      * Indicates a 3GPP2 format SMS message.
-     * @hide pending API council approval
      */
     public static final String FORMAT_3GPP2 = "3gpp2";
 
diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java
index 83ee361..7b07038 100644
--- a/tests/net/java/com/android/server/IpSecServiceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceTest.java
@@ -21,6 +21,7 @@
 import static android.system.OsConstants.IPPROTO_UDP;
 import static android.system.OsConstants.SOCK_DGRAM;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
 import static org.mockito.Mockito.mock;
@@ -174,6 +175,7 @@
                 mIpSecService.openUdpEncapsulationSocket(0, new Binder());
         assertNotNull(udpEncapResp);
         assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
+        assertNotEquals(0, udpEncapResp.port);
         mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
         udpEncapResp.fileDescriptor.close();
     }
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 0c02ec7..551e4df 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -128,8 +128,6 @@
 
     void releaseMulticastLock();
 
-    void setWifiApEnabled(in WifiConfiguration wifiConfig, boolean enable);
-
     void updateInterfaceIpState(String ifaceName, int mode);
 
     boolean startSoftAp(in WifiConfiguration wifiConfig);
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 649b0ce..b72df07 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1877,32 +1877,6 @@
     }
 
     /**
-     * This call is deprecated and removed.  It is no longer used to
-     * start WiFi Tethering.  Please use {@link ConnectivityManager#startTethering(int, boolean,
-     * ConnectivityManager#OnStartTetheringCallback)} if
-     * the caller has proper permissions.  Callers can also use the LocalOnlyHotspot feature for a
-     * hotspot capable of communicating with co-located devices {@link
-     * WifiManager#startLocalOnlyHotspot(LocalOnlyHotspotCallback)}.
-     *
-     * @param wifiConfig SSID, security and channel details as
-     *        part of WifiConfiguration
-     * @return {@code false}
-     *
-     * @hide
-     * @deprecated This API is nolonger supported.
-     * @removed
-     */
-    @SystemApi
-    @Deprecated
-    @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
-    public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
-        String packageName = mContext.getOpPackageName();
-
-        Log.w(TAG, packageName + " attempted call to setWifiApEnabled: enabled = " + enabled);
-        return false;
-    }
-
-    /**
      * Call allowing ConnectivityService to update WifiService with interface mode changes.
      *
      * The possible modes include: {@link IFACE_IP_MODE_TETHERED},
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index b235ccc7..ee6f12b 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -777,14 +777,4 @@
         mWifiManager.unregisterLocalOnlyHotspotObserver();
         verify(mWifiService).stopWatchLocalOnlyHotspot();
     }
-
-    /**
-     * Verify that calls to setWifiApEnabled return false.
-     */
-    @Test
-    public void testSetWifiApEnabledReturnsFalse() throws Exception {
-        assertFalse(mWifiManager.setWifiApEnabled(null, true));
-        assertFalse(mWifiManager.setWifiApEnabled(null, false));
-        verify(mWifiService, never()).setWifiApEnabled(any(), anyBoolean());
-    }
 }