Merge "pull resource power manager stats into statsd"
diff --git a/Android.mk b/Android.mk
index 1ed8a25..a7cb362 100644
--- a/Android.mk
+++ b/Android.mk
@@ -218,6 +218,7 @@
 	core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl \
 	core/java/android/hardware/location/IContextHubCallback.aidl \
 	core/java/android/hardware/location/IContextHubService.aidl \
+	core/java/android/hardware/location/IContextHubTransactionCallback.aidl \
 	core/java/android/hardware/radio/IRadioService.aidl \
 	core/java/android/hardware/radio/ITuner.aidl \
 	core/java/android/hardware/radio/ITunerCallback.aidl \
diff --git a/api/current.txt b/api/current.txt
index 5a947dd..f5f4bf4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -484,6 +484,7 @@
     field public static final int detailSocialSummary = 16843428; // 0x10102a4
     field public static final int detailsElementBackground = 16843598; // 0x101034e
     field public static final int dial = 16843010; // 0x1010102
+    field public static final int dialogCornerRadius = 16844145; // 0x1010571
     field public static final int dialogIcon = 16843252; // 0x10101f4
     field public static final int dialogLayout = 16843255; // 0x10101f7
     field public static final int dialogMessage = 16843251; // 0x10101f3
diff --git a/api/system-current.txt b/api/system-current.txt
index c0d106f..d50fb4ec 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -616,6 +616,7 @@
     field public static final int detailSocialSummary = 16843428; // 0x10102a4
     field public static final int detailsElementBackground = 16843598; // 0x101034e
     field public static final int dial = 16843010; // 0x1010102
+    field public static final int dialogCornerRadius = 16844145; // 0x1010571
     field public static final int dialogIcon = 16843252; // 0x10101f4
     field public static final int dialogLayout = 16843255; // 0x10101f7
     field public static final int dialogMessage = 16843251; // 0x10101f3
@@ -10234,6 +10235,7 @@
     field public static final java.lang.String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY";
     field public static final java.lang.String EXTRA_QUICK_VIEW_FEATURES = "android.intent.extra.QUICK_VIEW_FEATURES";
     field public static final java.lang.String EXTRA_QUIET_MODE = "android.intent.extra.QUIET_MODE";
+    field public static final java.lang.String EXTRA_REASON = "android.intent.extra.REASON";
     field public static final java.lang.String EXTRA_REFERRER = "android.intent.extra.REFERRER";
     field public static final java.lang.String EXTRA_REFERRER_NAME = "android.intent.extra.REFERRER_NAME";
     field public static final java.lang.String EXTRA_REMOTE_CALLBACK = "android.intent.extra.REMOTE_CALLBACK";
diff --git a/api/test-current.txt b/api/test-current.txt
index c32ca21..cee4789 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -484,6 +484,7 @@
     field public static final int detailSocialSummary = 16843428; // 0x10102a4
     field public static final int detailsElementBackground = 16843598; // 0x101034e
     field public static final int dial = 16843010; // 0x1010102
+    field public static final int dialogCornerRadius = 16844145; // 0x1010571
     field public static final int dialogIcon = 16843252; // 0x10101f4
     field public static final int dialogLayout = 16843255; // 0x10101f7
     field public static final int dialogMessage = 16843251; // 0x10101f3
@@ -3873,6 +3874,7 @@
     method public void resizeStack(int, android.graphics.Rect) throws java.lang.SecurityException;
     method public deprecated void restartPackage(java.lang.String);
     method public void setTaskWindowingMode(int, int, boolean) throws java.lang.SecurityException;
+    method public void setTaskWindowingModeSplitScreenPrimary(int, int, boolean, boolean, android.graphics.Rect) throws java.lang.SecurityException;
     method public static void setVrThread(int);
     method public void setWatchHeapLimit(long);
     method public static boolean supportsMultiWindow(android.content.Context);
@@ -3886,6 +3888,8 @@
     field public static final int MOVE_TASK_WITH_HOME = 1; // 0x1
     field public static final int RECENT_IGNORE_UNAVAILABLE = 2; // 0x2
     field public static final int RECENT_WITH_EXCLUDED = 1; // 0x1
+    field public static final int SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT = 1; // 0x1
+    field public static final int SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT = 0; // 0x0
   }
 
   public static class ActivityManager.AppTask {
@@ -44977,25 +44981,25 @@
     field public static final long FIELD_COUNT_UNKNOWN = 0L; // 0x0L
     field public static final int FIELD_ID_MASK = -8; // 0xfffffff8
     field public static final int FIELD_ID_SHIFT = 3; // 0x3
-    field public static final long FIELD_TYPE_BOOL = 55834574848L; // 0xd00000000L
-    field public static final long FIELD_TYPE_BYTES = 64424509440L; // 0xf00000000L
+    field public static final long FIELD_TYPE_BOOL = 34359738368L; // 0x800000000L
+    field public static final long FIELD_TYPE_BYTES = 51539607552L; // 0xc00000000L
     field public static final long FIELD_TYPE_DOUBLE = 4294967296L; // 0x100000000L
-    field public static final long FIELD_TYPE_ENUM = 68719476736L; // 0x1000000000L
-    field public static final long FIELD_TYPE_FIXED32 = 38654705664L; // 0x900000000L
-    field public static final long FIELD_TYPE_FIXED64 = 42949672960L; // 0xa00000000L
+    field public static final long FIELD_TYPE_ENUM = 60129542144L; // 0xe00000000L
+    field public static final long FIELD_TYPE_FIXED32 = 30064771072L; // 0x700000000L
+    field public static final long FIELD_TYPE_FIXED64 = 25769803776L; // 0x600000000L
     field public static final long FIELD_TYPE_FLOAT = 8589934592L; // 0x200000000L
-    field public static final long FIELD_TYPE_INT32 = 12884901888L; // 0x300000000L
-    field public static final long FIELD_TYPE_INT64 = 17179869184L; // 0x400000000L
+    field public static final long FIELD_TYPE_INT32 = 21474836480L; // 0x500000000L
+    field public static final long FIELD_TYPE_INT64 = 12884901888L; // 0x300000000L
     field public static final long FIELD_TYPE_MASK = 1095216660480L; // 0xff00000000L
-    field public static final long FIELD_TYPE_OBJECT = 73014444032L; // 0x1100000000L
-    field public static final long FIELD_TYPE_SFIXED32 = 47244640256L; // 0xb00000000L
-    field public static final long FIELD_TYPE_SFIXED64 = 51539607552L; // 0xc00000000L
+    field public static final long FIELD_TYPE_MESSAGE = 47244640256L; // 0xb00000000L
+    field public static final long FIELD_TYPE_SFIXED32 = 64424509440L; // 0xf00000000L
+    field public static final long FIELD_TYPE_SFIXED64 = 68719476736L; // 0x1000000000L
     field public static final int FIELD_TYPE_SHIFT = 32; // 0x20
-    field public static final long FIELD_TYPE_SINT32 = 30064771072L; // 0x700000000L
-    field public static final long FIELD_TYPE_SINT64 = 34359738368L; // 0x800000000L
-    field public static final long FIELD_TYPE_STRING = 60129542144L; // 0xe00000000L
-    field public static final long FIELD_TYPE_UINT32 = 21474836480L; // 0x500000000L
-    field public static final long FIELD_TYPE_UINT64 = 25769803776L; // 0x600000000L
+    field public static final long FIELD_TYPE_SINT32 = 73014444032L; // 0x1100000000L
+    field public static final long FIELD_TYPE_SINT64 = 77309411328L; // 0x1200000000L
+    field public static final long FIELD_TYPE_STRING = 38654705664L; // 0x900000000L
+    field public static final long FIELD_TYPE_UINT32 = 55834574848L; // 0xd00000000L
+    field public static final long FIELD_TYPE_UINT64 = 17179869184L; // 0x400000000L
     field public static final long FIELD_TYPE_UNKNOWN = 0L; // 0x0L
     field public static final java.lang.String TAG = "ProtoOutputStream";
     field public static final int WIRE_TYPE_END_GROUP = 4; // 0x4
diff --git a/cmds/incidentd/src/PrivacyBuffer.cpp b/cmds/incidentd/src/PrivacyBuffer.cpp
index d926ea7..77ae1a7 100644
--- a/cmds/incidentd/src/PrivacyBuffer.cpp
+++ b/cmds/incidentd/src/PrivacyBuffer.cpp
@@ -87,12 +87,12 @@
     // current field is message type and its sub-fields have extra privacy policies
     uint32_t msgSize = mData.readRawVarint();
     EncodedBuffer::Pointer start = mData.rp()->copy();
+    long long token = mProto.start(policy->EncodedFieldId());
     while (mData.rp()->pos() - start.pos() != msgSize) {
-        long long token = mProto.start(policy->EncodedFieldId());
         status_t err = stripField(policy, spec);
         if (err != NO_ERROR) return err;
-        mProto.end(token);
     }
+    mProto.end(token);
     return NO_ERROR;
 }
 
diff --git a/cmds/incidentd/src/section_list.h b/cmds/incidentd/src/section_list.h
index da82b00..dfd2312 100644
--- a/cmds/incidentd/src/section_list.h
+++ b/cmds/incidentd/src/section_list.h
@@ -30,7 +30,7 @@
  * This is the mapping of section IDs to each section's privacy policy.
  * The section IDs are guaranteed in ascending order, not NULL-terminated since size is provided.
  */
-extern const Privacy* PRIVACY_POLICY_LIST[];
+extern const Privacy** PRIVACY_POLICY_LIST;
 
 extern const int PRIVACY_POLICY_COUNT;
 
diff --git a/cmds/incidentd/tests/PrivacyBuffer_test.cpp b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
index 8f6e355..84a2a82 100644
--- a/cmds/incidentd/tests/PrivacyBuffer_test.cpp
+++ b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
@@ -260,3 +260,13 @@
     PrivacySpec spec;
     ASSERT_EQ(privacyBuf.strip(spec), BAD_VALUE);
 }
+
+TEST_F(PrivacyBufferTest, SelfRecursionMessage) {
+    string input = "\x2a\"" + VARINT_FIELD_1 + STRING_FIELD_2 + MESSAGE_FIELD_5;
+    writeToFdBuffer(input);
+    Privacy* field5 = create_message_privacy(5, NULL);
+    Privacy* list[] = { create_privacy(1, OTHER_TYPE, LOCAL), field5, NULL };
+    field5->children = list;
+    string expected = "\x2a\x1c" + STRING_FIELD_2 + "\x2a\xd" + STRING_FIELD_2;
+    assertStrip(EXPLICIT, expected, field5);
+}
diff --git a/cmds/incidentd/tests/section_list.cpp b/cmds/incidentd/tests/section_list.cpp
index e47b61cf..4acc429 100644
--- a/cmds/incidentd/tests/section_list.cpp
+++ b/cmds/incidentd/tests/section_list.cpp
@@ -20,9 +20,11 @@
 Privacy field_0 { 0, 11, list, EXPLICIT, NULL };
 Privacy field_1 { 1, 9, NULL, AUTOMATIC, NULL };
 
-const Privacy* PRIVACY_POLICY_LIST[] = {
+Privacy* final_list[] = {
     &field_0,
     &field_1
 };
 
-const int PRIVACY_POLICY_COUNT = 2;
\ No newline at end of file
+const Privacy** PRIVACY_POLICY_LIST = const_cast<const Privacy**>(final_list);
+
+const int PRIVACY_POLICY_COUNT = 2;
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 26a82cb..8220fcb 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -24,6 +24,7 @@
 namespace os {
 namespace statsd {
 
+using namespace android::util;
 using std::ostringstream;
 using std::string;
 using android::util::ProtoOutputStream;
@@ -207,20 +208,20 @@
 }
 
 void LogEvent::ToProto(ProtoOutputStream& proto) const {
-    long long atomToken = proto.start(TYPE_MESSAGE + mTagId);
+    long long atomToken = proto.start(FIELD_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(TYPE_INT32 + key, elem.data.int32);
+            proto.write(FIELD_TYPE_INT32 | key, elem.data.int32);
         } else if (elem.type == EVENT_TYPE_LONG) {
-            proto.write(TYPE_INT64 + key, (long long)elem.data.int64);
+            proto.write(FIELD_TYPE_INT64 | key, (long long)elem.data.int64);
         } else if (elem.type == EVENT_TYPE_FLOAT) {
-            proto.write(TYPE_FLOAT + key, elem.data.float32);
+            proto.write(FIELD_TYPE_FLOAT | key, elem.data.float32);
         } else if (elem.type == EVENT_TYPE_STRING) {
-            proto.write(TYPE_STRING + key, elem.data.string);
+            proto.write(FIELD_TYPE_STRING | key, elem.data.string);
         }
     }
     proto.end(atomToken);
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 9f8558d..71cb7717 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -24,6 +24,8 @@
 #include <limits.h>
 #include <stdlib.h>
 
+using namespace android::util;
+using android::util::ProtoOutputStream;
 using std::map;
 using std::string;
 using std::unordered_map;
@@ -33,6 +35,27 @@
 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 = 3;
+const int FIELD_ID_COUNT_METRICS = 5;
+// for CountMetricDataWrapper
+const int FIELD_ID_DATA = 1;
+// for CountMetricData
+const int FIELD_ID_DIMENSION = 1;
+const int FIELD_ID_BUCKET_INFO = 2;
+// for KeyValuePair
+const int FIELD_ID_KEY = 1;
+const int FIELD_ID_VALUE_STR = 2;
+const int FIELD_ID_VALUE_INT = 3;
+const int FIELD_ID_VALUE_BOOL = 4;
+const int FIELD_ID_VALUE_FLOAT = 5;
+// for CountBucketInfo
+const int FIELD_ID_START_BUCKET_NANOS = 1;
+const int FIELD_ID_END_BUCKET_NANOS = 2;
+const int FIELD_ID_COUNT = 3;
+
 // TODO: add back AnomalyTracker.
 CountMetricProducer::CountMetricProducer(const CountMetric& metric, const int conditionIndex,
                                          const sp<ConditionWizard>& wizard)
@@ -66,6 +89,8 @@
         mConditionSliced = true;
     }
 
+    startNewProtoOutputStream(mStartTimeNs);
+
     VLOG("metric %lld created. bucket size %lld start_time: %lld", metric.metric_id(),
          (long long)mBucketSizeNs, (long long)mStartTimeNs);
 }
@@ -74,23 +99,14 @@
     VLOG("~CountMetricProducer() called");
 }
 
-void CountMetricProducer::finish() {
-    // TODO: write the StatsLogReport to dropbox using
-    // DropboxWriter.
+void CountMetricProducer::startNewProtoOutputStream(long long startTime) {
+    mProto = std::make_unique<ProtoOutputStream>();
+    mProto->write(FIELD_TYPE_INT32 | FIELD_ID_METRIC_ID, mMetric.metric_id());
+    mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, startTime);
+    mProtoToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_COUNT_METRICS);
 }
 
-static void addSlicedCounterToReport(StatsLogReport_CountMetricDataWrapper& wrapper,
-                                     const vector<KeyValuePair>& key,
-                                     const vector<CountBucketInfo>& buckets) {
-    CountMetricData* data = wrapper.add_data();
-    for (const auto& kv : key) {
-        data->add_dimension()->CopyFrom(kv);
-    }
-    for (const auto& bucket : buckets) {
-        data->add_bucket_info()->CopyFrom(bucket);
-        VLOG("\t bucket [%lld - %lld] count: %lld", bucket.start_bucket_nanos(),
-             bucket.end_bucket_nanos(), bucket.count());
-    }
+void CountMetricProducer::finish() {
 }
 
 void CountMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
@@ -98,33 +114,81 @@
 }
 
 StatsLogReport CountMetricProducer::onDumpReport() {
-    VLOG("metric %lld dump report now...", mMetric.metric_id());
-
-    StatsLogReport report;
-    report.set_metric_id(mMetric.metric_id());
-    report.set_start_report_nanos(mStartTimeNs);
+    long long endTime = time(nullptr) * NANO_SECONDS_IN_A_SECOND;
 
     // Dump current bucket if it's stale.
     // If current bucket is still on-going, don't force dump current bucket.
     // In finish(), We can force dump current bucket.
-    flushCounterIfNeeded(time(nullptr) * NANO_SECONDS_IN_A_SECOND);
-    report.set_end_report_nanos(mCurrentBucketStartTimeNs);
+    flushCounterIfNeeded(endTime);
 
-    StatsLogReport_CountMetricDataWrapper* wrapper = report.mutable_count_metrics();
-
-    for (const auto& pair : mPastBuckets) {
-        const HashableDimensionKey& hashableKey = pair.first;
+    for (const auto& counter : mPastBucketProtos) {
+        const HashableDimensionKey& hashableKey = counter.first;
         auto it = mDimensionKeyMap.find(hashableKey);
         if (it == mDimensionKeyMap.end()) {
             ALOGE("Dimension key %s not found?!?! skip...", hashableKey.c_str());
             continue;
         }
+        long long wrapperToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_DATA);
 
-        VLOG("  dimension key %s", hashableKey.c_str());
-        addSlicedCounterToReport(*wrapper, it->second, pair.second);
+        // First fill dimension (KeyValuePairs).
+        for (const auto& kv : it->second) {
+            long long dimensionToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION);
+            mProto->write(FIELD_TYPE_INT32 | FIELD_ID_KEY, kv.key());
+            if (kv.has_value_str()) {
+                mProto->write(FIELD_TYPE_INT32 | FIELD_ID_VALUE_STR, kv.value_str());
+            } else if (kv.has_value_int()) {
+                mProto->write(FIELD_TYPE_INT64 | FIELD_ID_VALUE_INT, kv.value_int());
+            } else if (kv.has_value_bool()) {
+                mProto->write(FIELD_TYPE_BOOL | FIELD_ID_VALUE_BOOL, kv.value_bool());
+            } else if (kv.has_value_float()) {
+                mProto->write(FIELD_TYPE_FLOAT | FIELD_ID_VALUE_FLOAT, kv.value_float());
+            }
+            mProto->end(dimensionToken);
+        }
+
+        // Then fill bucket_info (CountBucketInfo).
+        for (const auto& proto : counter.second) {
+            size_t bufferSize = proto->size();
+            char* buffer(new char[bufferSize]);
+            size_t pos = 0;
+            auto it = proto->data();
+            while (it.readBuffer() != NULL) {
+                size_t toRead = it.currentToRead();
+                std::memcpy(&buffer[pos], it.readBuffer(), toRead);
+                pos += toRead;
+                it.rp()->move(toRead);
+            }
+            mProto->write(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION, buffer, bufferSize);
+        }
+
+        mProto->end(wrapperToken);
     }
-    return report;
-    // TODO: Clear mPastBuckets, mDimensionKeyMap once the report is dumped.
+
+    mProto->end(mProtoToken);
+    mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS,
+                  (long long)mCurrentBucketStartTimeNs);
+
+    size_t bufferSize = mProto->size();
+    VLOG("metric %lld dump report now...", mMetric.metric_id());
+    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);
+    mPastBucketProtos.clear();
+    mByteSize = 0;
+
+    // TODO: Once we migrate all MetricProducers to use ProtoOutputStream, we should return this:
+    // return std::move(buffer);
+    return StatsLogReport();
+
+    // TODO: Clear mDimensionKeyMap once the report is dumped.
 }
 
 void CountMetricProducer::onConditionChanged(const bool conditionMet, const uint64_t eventTime) {
@@ -175,15 +239,17 @@
     // adjust the bucket start time
     int64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs;
 
-    CountBucketInfo info;
-    info.set_start_bucket_nanos(mCurrentBucketStartTimeNs);
-    info.set_end_bucket_nanos(mCurrentBucketStartTimeNs + mBucketSizeNs);
-
     for (const auto& counter : mCurrentSlicedCounter) {
-        info.set_count(counter.second);
-        // it will auto create new vector of CountbucketInfo if the key is not found.
-        auto& bucketList = mPastBuckets[counter.first];
-        bucketList.push_back(info);
+        unique_ptr<ProtoOutputStream> proto = make_unique<ProtoOutputStream>();
+        proto->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_NANOS,
+                     (long long)mCurrentBucketStartTimeNs);
+        proto->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_NANOS,
+                      (long long)mCurrentBucketStartTimeNs + mBucketSizeNs);
+        proto->write(FIELD_TYPE_INT64 | FIELD_ID_COUNT, (long long)counter.second);
+
+        auto& bucketList = mPastBucketProtos[counter.first];
+        bucketList.push_back(std::move(proto));
+        mByteSize += proto->size();
 
         VLOG("metric %lld, dump key value: %s -> %d", mMetric.metric_id(), counter.first.c_str(),
              counter.second);
@@ -202,11 +268,11 @@
          (long long)mCurrentBucketStartTimeNs);
 }
 
+// Rough estimate of CountMetricProducer buffer stored. This number will be
+// greater than actual data size as it contains each dimension of
+// CountMetricData is  duplicated.
 size_t CountMetricProducer::byteSize() {
-// TODO: return actual proto size when ProtoOutputStream is ready for use for
-// CountMetricsProducer.
-//    return mProto->size();
-    return 0;
+    return mByteSize;
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index 80e80d9..473a4ba 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -19,6 +19,7 @@
 
 #include <unordered_map>
 
+#include <android/util/ProtoOutputStream.h>
 #include "../condition/ConditionTracker.h"
 #include "../matchers/matcher_util.h"
 #include "CountAnomalyTracker.h"
@@ -65,8 +66,10 @@
 private:
     const CountMetric mMetric;
 
-    // Save the past buckets and we can clear when the StatsLogReport is dumped.
-    std::unordered_map<HashableDimensionKey, std::vector<CountBucketInfo>> mPastBuckets;
+    std::unordered_map<HashableDimensionKey,
+        std::vector<unique_ptr<android::util::ProtoOutputStream>>> mPastBucketProtos;
+
+    size_t mByteSize;
 
     // The current bucket.
     std::unordered_map<HashableDimensionKey, int> mCurrentSlicedCounter;
@@ -74,6 +77,12 @@
     vector<unique_ptr<CountAnomalyTracker>> mAnomalyTrackers;
 
     void flushCounterIfNeeded(const uint64_t newEventTime);
+
+    std::unique_ptr<android::util::ProtoOutputStream> mProto;
+
+    long long mProtoToken;
+
+    void startNewProtoOutputStream(long long timestamp);
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index d714179..cbae1d3 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -23,6 +23,7 @@
 #include <limits.h>
 #include <stdlib.h>
 
+using namespace android::util;
 using android::util::ProtoOutputStream;
 using std::map;
 using std::string;
@@ -36,13 +37,13 @@
 // 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_END_REPORT_NANOS = 3;
 const int FIELD_ID_EVENT_METRICS = 4;
+// for EventMetricDataWrapper
+const int FIELD_ID_DATA = 1;
 // 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)
@@ -69,9 +70,9 @@
     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);
+    mProto->write(FIELD_TYPE_INT32 | FIELD_ID_METRIC_ID, mMetric.metric_id());
+    mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, startTime);
+    mProtoToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_EVENT_METRICS);
 }
 
 void EventMetricProducer::finish() {
@@ -83,7 +84,7 @@
 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);
+    mProto->write(FIELD_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);
@@ -118,9 +119,9 @@
         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);
+    long long wrapperToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_DATA);
+    mProto->write(FIELD_TYPE_INT64 | FIELD_ID_TIMESTAMP_NANOS, (long long)event.GetTimestampNs());
+    long long eventToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_STATS_EVENTS);
     event.ToProto(*mProto);
     mProto->end(eventToken);
     mProto->end(wrapperToken);
diff --git a/cmds/statsd/src/stats_util.h b/cmds/statsd/src/stats_util.h
index a428752..d3d7e37 100644
--- a/cmds/statsd/src/stats_util.h
+++ b/cmds/statsd/src/stats_util.h
@@ -30,14 +30,6 @@
 #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;
 
 typedef std::map<std::string, HashableDimensionKey> ConditionKey;
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 2305957..064e978 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -687,6 +687,7 @@
      * in portrait mode or at the left half of the screen if in landscape mode.
      * @hide
      */
+    @TestApi
     public static final int SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT = 0;
 
     /**
@@ -696,6 +697,7 @@
      * in portrait mode or at the right half of the screen if in landscape mode.
      * @hide
      */
+    @TestApi
     public static final int SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT = 1;
 
     /**
@@ -1926,6 +1928,33 @@
     }
 
     /**
+     * Moves the input task to the primary-split-screen stack.
+     * @param taskId Id of task to move.
+     * @param createMode The mode the primary split screen stack should be created in if it doesn't
+     *                  exist already. See
+     *                   {@link android.app.ActivityManager#SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT}
+     *                   and
+     *                   {@link android.app.ActivityManager
+     *                        #SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT}
+     * @param toTop If the task and stack should be moved to the top.
+     * @param animate Whether we should play an animation for the moving the task
+     * @param initialBounds If the primary stack gets created, it will use these bounds for the
+     *                      docked stack. Pass {@code null} to use default bounds.
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
+    public void setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, boolean toTop,
+            boolean animate, Rect initialBounds) throws SecurityException {
+        try {
+            getService().setTaskWindowingModeSplitScreenPrimary(taskId, createMode, toTop, animate,
+                    initialBounds);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Resizes the input stack id to the given bounds.
      * @param stackId Id of the stack to resize.
      * @param bounds Bounds to resize the stack to or {@code null} for fullscreen.
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 388459f..bbc90c8 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -232,7 +232,7 @@
             boolean requireFull, in String name, in String callerPackage);
     void addPackageDependency(in String packageName);
     void killApplication(in String pkg, int appId, int userId, in String reason);
-    oneway void closeSystemDialogs(in String reason);
+    void closeSystemDialogs(in String reason);
     Debug.MemoryInfo[] getProcessMemoryInfo(in int[] pids);
     void killApplicationProcess(in String processName, int uid);
     int startActivityIntentSender(in IApplicationThread caller,
diff --git a/core/java/android/app/VrManager.java b/core/java/android/app/VrManager.java
index 5c6ffa3..392387a 100644
--- a/core/java/android/app/VrManager.java
+++ b/core/java/android/app/VrManager.java
@@ -198,4 +198,20 @@
             e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Sets the current standby status of the VR device. Standby mode is only used on standalone vr
+     * devices. Standby mode is a deep sleep state where it's appropriate to turn off vr mode.
+     *
+     * @param standby True if the device is entering standby, false if it's exiting standby.
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_VR_MANAGER)
+    public void setStandbyEnabled(boolean standby) {
+        try {
+            mService.setStandbyEnabled(standby);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index e47de75..dd729a3 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3444,11 +3444,12 @@
     /**
      * A broadcast action to trigger a factory reset.
      *
-     * <p> The sender must hold the {@link android.Manifest.permission#MASTER_CLEAR} permission.
+     * <p>The sender must hold the {@link android.Manifest.permission#MASTER_CLEAR} permission. The
+     * reason for the factory reset should be specified as {@link #EXTRA_REASON}.
      *
      * <p>Not for use by third-party applications.
      *
-     * @see #EXTRA_FORCE_MASTER_CLEAR
+     * @see #EXTRA_FORCE_FACTORY_RESET
      *
      * {@hide}
      */
@@ -4827,7 +4828,13 @@
     /** @hide */
     public static final int EXTRA_TIME_PREF_VALUE_USE_LOCALE_DEFAULT = 2;
 
-    /** {@hide} */
+    /**
+     * Intent extra: the reason that the operation associated with this intent is being performed.
+     *
+     * <p>Type: String
+     * @hide
+     */
+    @SystemApi
     public static final String EXTRA_REASON = "android.intent.extra.REASON";
 
     /**
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index b94a410..05c5556 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -671,9 +671,13 @@
     }
 
     /**
-     * Returns whether the caller can access the shortcut information.
+     * Returns whether the caller can access the shortcut information.  Access is currently
+     * available to:
      *
-     * <p>Only the default launcher can access the shortcut information.
+     * <ul>
+     *     <li>The current launcher (or default launcher if there is no set current launcher).</li>
+     *     <li>The currently active voice interaction service.</li>
+     * </ul>
      *
      * <p>Note when this method returns {@code false}, it may be a temporary situation because
      * the user is trying a new launcher application.  The user may decide to change the default
diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java
index 7fc25d8..dadfaa9 100644
--- a/core/java/android/content/pm/ShortcutServiceInternal.java
+++ b/core/java/android/content/pm/ShortcutServiceInternal.java
@@ -73,6 +73,9 @@
     public abstract boolean hasShortcutHostPermission(int launcherUserId,
             @NonNull String callingPackage, int callingPid, int callingUid);
 
+    public abstract void setShortcutHostPackage(@NonNull String type, @Nullable String packageName,
+            int userId);
+
     public abstract boolean requestPinAppWidget(@NonNull String callingPackage,
             @NonNull AppWidgetProviderInfo appWidget, @Nullable Bundle extras,
             @Nullable IntentSender resultIntent, int userId);
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index 7cbb436..2411727 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -271,6 +271,59 @@
         throw new UnsupportedOperationException("TODO: Implement this");
     }
 
+    /*
+     * Helper function to generate a stub for a non-query transaction callback.
+     *
+     * @param transaction the transaction to unblock when complete
+     *
+     * @return the callback
+     *
+     * @hide
+     */
+    private IContextHubTransactionCallback createTransactionCallback(
+            ContextHubTransaction<Void> transaction) {
+        return new IContextHubTransactionCallback.Stub() {
+            @Override
+            public void onQueryResponse(int result, List<NanoAppState> nanoappList) {
+                Log.e(TAG, "Received a query callback on a non-query request");
+                transaction.setResponse(new ContextHubTransaction.Response<Void>(
+                        ContextHubTransaction.TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE, null));
+            }
+
+            @Override
+            public void onTransactionComplete(int result) {
+                transaction.setResponse(new ContextHubTransaction.Response<Void>(result, null));
+            }
+        };
+    }
+
+   /*
+    * Helper function to generate a stub for a query transaction callback.
+    *
+    * @param transaction the transaction to unblock when complete
+    *
+    * @return the callback
+    *
+    * @hide
+    */
+    private IContextHubTransactionCallback createQueryCallback(
+            ContextHubTransaction<List<NanoAppState>> transaction) {
+        return new IContextHubTransactionCallback.Stub() {
+            @Override
+            public void onQueryResponse(int result, List<NanoAppState> nanoappList) {
+                transaction.setResponse(new ContextHubTransaction.Response<List<NanoAppState>>(
+                        result, nanoappList));
+            }
+
+            @Override
+            public void onTransactionComplete(int result) {
+                Log.e(TAG, "Received a non-query callback on a query request");
+                transaction.setResponse(new ContextHubTransaction.Response<List<NanoAppState>>(
+                        ContextHubTransaction.TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE, null));
+            }
+        };
+    }
+
     /**
      * Loads a nanoapp at the specified Context Hub.
      *
@@ -411,7 +464,7 @@
      *
      * @param callback the notification callback to register
      * @param hubInfo the hub to attach this client to
-     * @param handler the handler to invoke the callback, if null uses the current thread Looper
+     * @param handler the handler to invoke the callback, if null uses the main thread's Looper
      *
      * @return the registered client object
      *
diff --git a/core/java/android/hardware/location/ContextHubTransaction.java b/core/java/android/hardware/location/ContextHubTransaction.java
index 4877d38..a8569ef 100644
--- a/core/java/android/hardware/location/ContextHubTransaction.java
+++ b/core/java/android/hardware/location/ContextHubTransaction.java
@@ -16,11 +16,16 @@
 package android.hardware.location;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 /**
  * A class describing a request sent to the Context Hub Service.
@@ -29,17 +34,15 @@
  * through the ContextHubManager APIs. The caller can either retrieve the result
  * synchronously through a blocking call ({@link #waitForResponse(long, TimeUnit)}) or
  * asynchronously through a user-defined callback
- * ({@link #onComplete(ContextHubTransaction.Callback<T>, Handler)}).
- *
- * A transaction can be invalidated if the caller of the transaction is no longer active
- * and the reference to this object is lost, or if timeout period has passed in
- * {@link #waitForResponse(long, TimeUnit)}.
+ * ({@link #setCallbackOnComplete(ContextHubTransaction.Callback, Handler)}).
  *
  * @param <T> the type of the contents in the transaction response
  *
  * @hide
  */
 public class ContextHubTransaction<T> {
+    private static final String TAG = "ContextHubTransaction";
+
     /**
      * Constants describing the type of a transaction through the Context Hub Service.
      */
@@ -68,7 +71,8 @@
             TRANSACTION_FAILED_UNINITIALIZED,
             TRANSACTION_FAILED_PENDING,
             TRANSACTION_FAILED_AT_HUB,
-            TRANSACTION_FAILED_TIMEOUT})
+            TRANSACTION_FAILED_TIMEOUT,
+            TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE})
     public @interface Result {}
     public static final int TRANSACTION_SUCCESS = 0;
     /**
@@ -95,6 +99,10 @@
      * Failure mode when the transaction has timed out.
      */
     public static final int TRANSACTION_FAILED_TIMEOUT = 6;
+    /**
+     * Failure mode when the transaction has failed internally at the service.
+     */
+    public static final int TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE = 7;
 
     /**
      * A class describing the response for a ContextHubTransaction.
@@ -146,11 +154,6 @@
     }
 
     /*
-     * The unique identifier representing the transaction.
-     */
-    private int mTransactionId;
-
-    /*
      * The type of the transaction.
      */
     @Type
@@ -171,8 +174,17 @@
      */
     private ContextHubTransaction.Callback<T> mCallback = null;
 
-    ContextHubTransaction(int id, @Type int type) {
-        mTransactionId = id;
+    /*
+     * Synchronization latch used to block on response.
+     */
+    private final CountDownLatch mDoneSignal = new CountDownLatch(1);
+
+    /*
+     * true if the response has been set throught setResponse, false otherwise.
+     */
+    private boolean mIsResponseSet = false;
+
+    ContextHubTransaction(@Type int type) {
         mTransactionType = type;
     }
 
@@ -191,17 +203,26 @@
      * for the transaction represented by this object by the Context Hub, or a
      * specified timeout period has elapsed.
      *
-     * If the specified timeout has passed, the transaction represented by this object
-     * is invalidated by the Context Hub Service (resulting in a timeout failure in the
-     * response).
+     * If the specified timeout has passed, a TimeoutException will be thrown and the caller may
+     * retry the invocation of this method at a later time.
      *
      * @param timeout the timeout duration
      * @param unit the unit of the timeout
      *
      * @return the transaction response
+     *
+     * @throws InterruptedException if the current thread is interrupted while waiting for response
+     * @throws TimeoutException if the timeout period has passed
      */
-    public ContextHubTransaction.Response<T> waitForResponse(long timeout, TimeUnit unit) {
-        throw new UnsupportedOperationException("TODO: Implement this");
+    public ContextHubTransaction.Response<T> waitForResponse(
+            long timeout, TimeUnit unit) throws InterruptedException, TimeoutException {
+        boolean success = mDoneSignal.await(timeout, unit);
+
+        if (!success) {
+            throw new TimeoutException("Timed out while waiting for transaction");
+        }
+
+        return mResponse;
     }
 
     /**
@@ -215,15 +236,100 @@
      * will be immediately posted by the handler. If the transaction has been invalidated,
      * the callback will never be invoked.
      *
+     * A transaction can be invalidated if the process owning the transaction is no longer active
+     * and the reference to this object is lost.
+     *
+     * This method or {@link #setCallbackOnCompletecan(ContextHubTransaction.Callback)} can only be
+     * invoked once, or an IllegalStateException will be thrown.
+     *
      * @param callback the callback to be invoked upon completion
      * @param handler the handler to post the callback
+     *
+     * @throws IllegalStateException if this method is called multiple times
+     * @throws NullPointerException if the callback or handler is null
      */
-    public void onComplete(ContextHubTransaction.Callback<T> callback, Handler handler) {
-        throw new UnsupportedOperationException("TODO: Implement this");
+    public void setCallbackOnComplete(
+            @NonNull ContextHubTransaction.Callback<T> callback, @NonNull Handler handler) {
+        synchronized (this) {
+            if (callback == null) {
+                throw new NullPointerException("Callback cannot be null");
+            }
+            if (handler == null) {
+                throw new NullPointerException("Handler cannot be null");
+            }
+            if (mCallback != null) {
+                throw new IllegalStateException(
+                        "Cannot set ContextHubTransaction callback multiple times");
+            }
+
+            mCallback = callback;
+            mHandler = handler;
+
+            if (mDoneSignal.getCount() == 0) {
+                boolean callbackPosted = mHandler.post(() -> {
+                    mCallback.onComplete(this, mResponse);
+                });
+
+                if (!callbackPosted) {
+                    Log.e(TAG, "Failed to post callback to Handler");
+                }
+            }
+        }
     }
 
-    private void setResponse(ContextHubTransaction.Response<T> response) {
-        mResponse = response;
-        throw new UnsupportedOperationException("TODO: Unblock waitForResponse");
+    /**
+     * Sets a callback to be invoked when the transaction completes.
+     *
+     * Equivalent to {@link #setCallbackOnComplete(ContextHubTransaction.Callback, Handler)}
+     * with the handler being that of the main thread's Looper.
+     *
+     * This method or {@link #setCallbackOnComplete(ContextHubTransaction.Callback, Handler)}
+     * can only be invoked once, or an IllegalStateException will be thrown.
+     *
+     * @param callback the callback to be invoked upon completion
+     *
+     * @throws IllegalStateException if this method is called multiple times
+     * @throws NullPointerException if the callback is null
+     */
+    public void setCallbackOnComplete(@NonNull ContextHubTransaction.Callback<T> callback) {
+        setCallbackOnComplete(callback, new Handler(Looper.getMainLooper()));
+    }
+
+    /**
+     * Sets the response of the transaction.
+     *
+     * This method should only be invoked by ContextHubManager as a result of a callback from
+     * the Context Hub Service indicating the response from a transaction. This method should not be
+     * invoked more than once.
+     *
+     * @param response the response to set
+     *
+     * @throws IllegalStateException if this method is invoked multiple times
+     * @throws NullPointerException if the response is null
+     */
+    void setResponse(ContextHubTransaction.Response<T> response) {
+        synchronized (this) {
+            if (response == null) {
+                throw new NullPointerException("Response cannot be null");
+            }
+            if (mIsResponseSet) {
+                throw new IllegalStateException(
+                        "Cannot set response of ContextHubTransaction multiple times");
+            }
+
+            mResponse = response;
+            mIsResponseSet = true;
+
+            mDoneSignal.countDown();
+            if (mCallback != null) {
+                boolean callbackPosted = mHandler.post(() -> {
+                    mCallback.onComplete(this, mResponse);
+                });
+
+                if (!callbackPosted) {
+                    Log.e(TAG, "Failed to post callback to Handler");
+                }
+            }
+        }
     }
 }
diff --git a/core/java/android/hardware/location/IContextHubTransactionCallback.aidl b/core/java/android/hardware/location/IContextHubTransactionCallback.aidl
new file mode 100644
index 0000000..5419cd7
--- /dev/null
+++ b/core/java/android/hardware/location/IContextHubTransactionCallback.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.location;
+
+import android.hardware.location.NanoAppState;
+
+/**
+ * An interface used by the Context Hub Service to invoke callbacks notifying the complete of a
+ * transaction. The callbacks are unique for each type of transaction, and the service is
+ * responsible for invoking the correct callback.
+ *
+ * @hide
+ */
+oneway interface IContextHubTransactionCallback {
+
+    // Callback to be invoked when a query request completes
+    void onQueryResponse(int result, in List<NanoAppState> nanoappList);
+
+    // Callback to be invoked when a non-query request completes
+    void onTransactionComplete(int result);
+}
diff --git a/core/java/android/hardware/location/NanoAppBinary.java b/core/java/android/hardware/location/NanoAppBinary.java
index 5454227..934e9e4 100644
--- a/core/java/android/hardware/location/NanoAppBinary.java
+++ b/core/java/android/hardware/location/NanoAppBinary.java
@@ -22,6 +22,7 @@
 import java.nio.BufferUnderflowException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+import java.util.Arrays;
 
 /**
  * @hide
@@ -57,7 +58,7 @@
     private static final int EXPECTED_HEADER_VERSION = 1;
 
     /*
-     * The magic value expected in the header.
+     * The magic value expected in the header as defined in context_hub.h.
      */
     private static final int EXPECTED_MAGIC_VALUE =
             (((int) 'N' <<  0) | ((int) 'A' <<  8) | ((int) 'N' << 16) | ((int) 'O' << 24));
@@ -67,6 +68,17 @@
      */
     private static final ByteOrder HEADER_ORDER = ByteOrder.LITTLE_ENDIAN;
 
+    /*
+     * The size of the header in bytes as defined in context_hub.h.
+     */
+    private static final int HEADER_SIZE_BYTES = 40;
+
+    /*
+     * The bit fields for mFlags as defined in context_hub.h.
+     */
+    private static final int NANOAPP_SIGNED_FLAG_BIT = 0x1;
+    private static final int NANOAPP_ENCRYPTED_FLAG_BIT = 0x2;
+
     public NanoAppBinary(byte[] appBinary) {
         mNanoAppBinary = appBinary;
         parseBinaryHeader();
@@ -111,11 +123,26 @@
     /**
      * @return the app binary byte array
      */
-    public byte[] getNanoAppBinary() {
+    public byte[] getBinary() {
         return mNanoAppBinary;
     }
 
     /**
+     * @return the app binary byte array without the leading header
+     *
+     * @throws IndexOutOfBoundsException if the nanoapp binary size is smaller than the header size
+     * @throws NullPointerException if the nanoapp binary is null
+     */
+    public byte[] getBinaryNoHeader() {
+        if (mNanoAppBinary.length < HEADER_SIZE_BYTES) {
+            throw new IndexOutOfBoundsException("NanoAppBinary binary byte size ("
+                + mNanoAppBinary.length + ") is less than header size (" + HEADER_SIZE_BYTES + ")");
+        }
+
+        return Arrays.copyOfRange(mNanoAppBinary, HEADER_SIZE_BYTES, mNanoAppBinary.length);
+    }
+
+    /**
      * @return {@code true} if the header is valid, {@code false} otherwise
      */
     public boolean hasValidHeader() {
@@ -164,6 +191,31 @@
         return mTargetChreApiMinorVersion;
     }
 
+    /**
+     * Returns the flags for the nanoapp as defined in context_hub.h.
+     *
+     * This method is meant to be used by the Context Hub Service.
+     *
+     * @return the flags for the nanoapp
+     */
+    public int getFlags() {
+        return mFlags;
+    }
+
+    /**
+     * @return {@code true} if the nanoapp binary is signed, {@code false} otherwise
+     */
+    public boolean isSigned() {
+        return (mFlags & NANOAPP_SIGNED_FLAG_BIT) != 0;
+    }
+
+    /**
+     * @return {@code true} if the nanoapp binary is encrypted, {@code false} otherwise
+     */
+    public boolean isEncrypted() {
+        return (mFlags & NANOAPP_ENCRYPTED_FLAG_BIT) != 0;
+    }
+
     private NanoAppBinary(Parcel in) {
         int binaryLength = in.readInt();
         mNanoAppBinary = new byte[binaryLength];
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 7f4dee6..01b6535 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -513,6 +513,34 @@
      */
     public static final int SHUTDOWN_REASON_BATTERY_THERMAL = 6;
 
+    /**
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({ServiceType.GPS,
+            ServiceType.VIBRATION,
+            ServiceType.ANIMATION,
+            ServiceType.FULL_BACKUP,
+            ServiceType.KEYVALUE_BACKUP,
+            ServiceType.NETWORK_FIREWALL,
+            ServiceType.SCREEN_BRIGHTNESS,
+            ServiceType.SOUND,
+            ServiceType.BATTERY_STATS,
+            ServiceType.DATA_SAVER})
+    public @interface ServiceType {
+        int NULL = 0;
+        int GPS = 1;
+        int VIBRATION = 2;
+        int ANIMATION = 3;
+        int FULL_BACKUP = 4;
+        int KEYVALUE_BACKUP = 5;
+        int NETWORK_FIREWALL = 6;
+        int SCREEN_BRIGHTNESS = 7;
+        int SOUND = 8;
+        int BATTERY_STATS = 9;
+        int DATA_SAVER = 10;
+    }
+
     final Context mContext;
     final IPowerManager mService;
     final Handler mHandler;
@@ -1055,15 +1083,14 @@
 
     /**
      * Get data about the battery saver mode for a specific service
-     * @param serviceType unique key for the service, one of
-     *             {@link com.android.server.power.BatterySaverPolicy.ServiceType}
+     * @param serviceType unique key for the service, one of {@link ServiceType}
      * @return Battery saver state data.
      *
      * @hide
      * @see com.android.server.power.BatterySaverPolicy
      * @see PowerSaveState
      */
-    public PowerSaveState getPowerSaveState(int serviceType) {
+    public PowerSaveState getPowerSaveState(@ServiceType int serviceType) {
         try {
             return mService.getPowerSaveState(serviceType);
         } catch (RemoteException e) {
diff --git a/core/java/android/os/PowerSaveState.java b/core/java/android/os/PowerSaveState.java
index 7058a1d..de1128df 100644
--- a/core/java/android/os/PowerSaveState.java
+++ b/core/java/android/os/PowerSaveState.java
@@ -27,7 +27,7 @@
     /**
      * Whether we should enable battery saver for this service.
      *
-     * @see com.android.server.power.BatterySaverPolicy.ServiceType
+     * @see com.android.server.power.BatterySaverPolicy
      */
     public final boolean batterySaverEnabled;
     /**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2d6a7b0..433878e 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8012,28 +8012,40 @@
         public static final String HDMI_SYSTEM_AUDIO_CONTROL_ENABLED =
                 "hdmi_system_audio_control_enabled";
 
-       /**
-        * Whether TV will automatically turn on upon reception of the CEC command
-        * &lt;Text View On&gt; or &lt;Image View On&gt;. (0 = false, 1 = true)
-        * @hide
-        */
-       public static final String HDMI_CONTROL_AUTO_WAKEUP_ENABLED =
-               "hdmi_control_auto_wakeup_enabled";
+        /**
+         * Whether TV will automatically turn on upon reception of the CEC command
+         * &lt;Text View On&gt; or &lt;Image View On&gt;. (0 = false, 1 = true)
+         *
+         * @hide
+         */
+        public static final String HDMI_CONTROL_AUTO_WAKEUP_ENABLED =
+                "hdmi_control_auto_wakeup_enabled";
 
-       /**
-        * Whether TV will also turn off other CEC devices when it goes to standby mode.
-        * (0 = false, 1 = true)
-        * @hide
-        */
-       public static final String HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED =
-               "hdmi_control_auto_device_off_enabled";
+        /**
+         * Whether TV will also turn off other CEC devices when it goes to standby mode.
+         * (0 = false, 1 = true)
+         *
+         * @hide
+         */
+        public static final String HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED =
+                "hdmi_control_auto_device_off_enabled";
 
-       /**
-        * The interval in milliseconds at which location requests will be throttled when they are
-        * coming from the background.
-        * @hide
-        */
-       public static final String LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS =
+        /**
+         * If <b>true</b>, enables out-of-the-box execution for priv apps.
+         * Default: false
+         * Values: 0 = false, 1 = true
+         *
+         * @hide
+         */
+        public static final String PRIV_APP_OOB_ENABLED = "priv_app_oob_enabled";
+
+        /**
+         * The interval in milliseconds at which location requests will be throttled when they are
+         * coming from the background.
+         *
+         * @hide
+         */
+        public static final String LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS =
                 "location_background_throttle_interval_ms";
 
         /**
diff --git a/core/java/android/service/vr/IVrManager.aidl b/core/java/android/service/vr/IVrManager.aidl
index fef9223..7285fb4 100644
--- a/core/java/android/service/vr/IVrManager.aidl
+++ b/core/java/android/service/vr/IVrManager.aidl
@@ -101,5 +101,13 @@
      * application's compositor process to bind to, or null to clear the current binding.
      */
     void setAndBindCompositor(in String componentName);
+
+    /**
+     * Sets the current standby status of the VR device. Standby mode is only used on standalone vr
+     * devices. Standby mode is a deep sleep state where it's appropriate to turn off vr mode.
+     *
+     * @param standy True if the device is entering standby, false if it's exiting standby.
+     */
+    void setStandbyEnabled(boolean standby);
 }
 
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
index a9ccae1..1808123 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -16,9 +16,6 @@
 
 package android.util.apk;
 
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.OsConstants;
 import android.util.ArrayMap;
 import android.util.Pair;
 
@@ -30,7 +27,6 @@
 import java.nio.BufferUnderflowException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
-import java.nio.DirectByteBuffer;
 import java.security.DigestException;
 import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
@@ -122,40 +118,6 @@
     }
 
     /**
-     * APK Signature Scheme v2 block and additional information relevant to verifying the signatures
-     * contained in the block against the file.
-     */
-    private static class SignatureInfo {
-        /** Contents of APK Signature Scheme v2 block. */
-        private final ByteBuffer signatureBlock;
-
-        /** Position of the APK Signing Block in the file. */
-        private final long apkSigningBlockOffset;
-
-        /** Position of the ZIP Central Directory in the file. */
-        private final long centralDirOffset;
-
-        /** Position of the ZIP End of Central Directory (EoCD) in the file. */
-        private final long eocdOffset;
-
-        /** Contents of ZIP End of Central Directory (EoCD) of the file. */
-        private final ByteBuffer eocd;
-
-        private SignatureInfo(
-                ByteBuffer signatureBlock,
-                long apkSigningBlockOffset,
-                long centralDirOffset,
-                long eocdOffset,
-                ByteBuffer eocd) {
-            this.signatureBlock = signatureBlock;
-            this.apkSigningBlockOffset = apkSigningBlockOffset;
-            this.centralDirOffset = centralDirOffset;
-            this.eocdOffset = eocdOffset;
-            this.eocd = eocd;
-        }
-    }
-
-    /**
      * Returns the APK Signature Scheme v2 block contained in the provided APK file and the
      * additional information relevant for verifying the block against the file.
      *
@@ -497,6 +459,7 @@
         // TODO: Compute digests of chunks in parallel when beneficial. This requires some research
         // into how to parallelize (if at all) based on the capabilities of the hardware on which
         // this code is running and based on the size of input.
+        DataDigester digester = new MultipleDigestDataDigester(mds);
         int dataSourceIndex = 0;
         for (DataSource input : contents) {
             long inputOffset = 0;
@@ -508,7 +471,7 @@
                     mds[i].update(chunkContentPrefix);
                 }
                 try {
-                    input.feedIntoMessageDigests(mds, inputOffset, chunkSize);
+                    input.feedIntoDataDigester(digester, inputOffset, chunkSize);
                 } catch (IOException e) {
                     throw new DigestException(
                             "Failed to digest chunk #" + chunkIndex + " of section #"
@@ -967,155 +930,26 @@
     }
 
     /**
-     * Source of data to be digested.
+     * {@link DataDigester} that updates multiple {@link MessageDigest}s whenever data is feeded.
      */
-    private static interface DataSource {
+    private static class MultipleDigestDataDigester implements DataDigester {
+        private final MessageDigest[] mMds;
 
-        /**
-         * Returns the size (in bytes) of the data offered by this source.
-         */
-        long size();
-
-        /**
-         * Feeds the specified region of this source's data into the provided digests. Each digest
-         * instance gets the same data.
-         *
-         * @param offset offset of the region inside this data source.
-         * @param size size (in bytes) of the region.
-         */
-        void feedIntoMessageDigests(MessageDigest[] mds, long offset, int size) throws IOException;
-    }
-
-    /**
-     * {@link DataSource} which provides data from a file descriptor by memory-mapping the sections
-     * of the file requested by
-     * {@link DataSource#feedIntoMessageDigests(MessageDigest[], long, int) feedIntoMessageDigests}.
-     */
-    private static final class MemoryMappedFileDataSource implements DataSource {
-        private static final long MEMORY_PAGE_SIZE_BYTES = Os.sysconf(OsConstants._SC_PAGESIZE);
-
-        private final FileDescriptor mFd;
-        private final long mFilePosition;
-        private final long mSize;
-
-        /**
-         * Constructs a new {@code MemoryMappedFileDataSource} for the specified region of the file.
-         *
-         * @param position start position of the region in the file.
-         * @param size size (in bytes) of the region.
-         */
-        public MemoryMappedFileDataSource(FileDescriptor fd, long position, long size) {
-            mFd = fd;
-            mFilePosition = position;
-            mSize = size;
+        MultipleDigestDataDigester(MessageDigest[] mds) {
+            mMds = mds;
         }
 
         @Override
-        public long size() {
-            return mSize;
-        }
-
-        @Override
-        public void feedIntoMessageDigests(
-                MessageDigest[] mds, long offset, int size) throws IOException {
-            // IMPLEMENTATION NOTE: After a lot of experimentation, the implementation of this
-            // method was settled on a straightforward mmap with prefaulting.
-            //
-            // This method is not using FileChannel.map API because that API does not offset a way
-            // to "prefault" the resulting memory pages. Without prefaulting, performance is about
-            // 10% slower on small to medium APKs, but is significantly worse for APKs in 500+ MB
-            // range. FileChannel.load (which currently uses madvise) doesn't help. Finally,
-            // invoking madvise (MADV_SEQUENTIAL) after mmap with prefaulting wastes quite a bit of
-            // time, which is not compensated for by faster reads.
-
-            // We mmap the smallest region of the file containing the requested data. mmap requires
-            // that the start offset in the file must be a multiple of memory page size. We thus may
-            // need to mmap from an offset less than the requested offset.
-            long filePosition = mFilePosition + offset;
-            long mmapFilePosition =
-                    (filePosition / MEMORY_PAGE_SIZE_BYTES) * MEMORY_PAGE_SIZE_BYTES;
-            int dataStartOffsetInMmapRegion = (int) (filePosition - mmapFilePosition);
-            long mmapRegionSize = size + dataStartOffsetInMmapRegion;
-            long mmapPtr = 0;
-            try {
-                mmapPtr = Os.mmap(
-                        0, // let the OS choose the start address of the region in memory
-                        mmapRegionSize,
-                        OsConstants.PROT_READ,
-                        OsConstants.MAP_SHARED | OsConstants.MAP_POPULATE, // "prefault" all pages
-                        mFd,
-                        mmapFilePosition);
-                // Feeding a memory region into MessageDigest requires the region to be represented
-                // as a direct ByteBuffer.
-                ByteBuffer buf = new DirectByteBuffer(
-                        size,
-                        mmapPtr + dataStartOffsetInMmapRegion,
-                        mFd,  // not really needed, but just in case
-                        null, // no need to clean up -- it's taken care of by the finally block
-                        true  // read only buffer
-                        );
-                for (MessageDigest md : mds) {
-                    buf.position(0);
-                    md.update(buf);
-                }
-            } catch (ErrnoException e) {
-                throw new IOException("Failed to mmap " + mmapRegionSize + " bytes", e);
-            } finally {
-                if (mmapPtr != 0) {
-                    try {
-                        Os.munmap(mmapPtr, mmapRegionSize);
-                    } catch (ErrnoException ignored) {}
-                }
+        public void consume(ByteBuffer buffer) {
+            buffer = buffer.slice();
+            for (MessageDigest md : mMds) {
+                buffer.position(0);
+                md.update(buffer);
             }
         }
-    }
-
-    /**
-     * {@link DataSource} which provides data from a {@link ByteBuffer}.
-     */
-    private static final class ByteBufferDataSource implements DataSource {
-        /**
-         * Underlying buffer. The data is stored between position 0 and the buffer's capacity.
-         * The buffer's position is 0 and limit is equal to capacity.
-         */
-        private final ByteBuffer mBuf;
-
-        public ByteBufferDataSource(ByteBuffer buf) {
-            // Defensive copy, to avoid changes to mBuf being visible in buf.
-            mBuf = buf.slice();
-        }
 
         @Override
-        public long size() {
-            return mBuf.capacity();
-        }
-
-        @Override
-        public void feedIntoMessageDigests(
-                MessageDigest[] mds, long offset, int size) throws IOException {
-            // There's no way to tell MessageDigest to read data from ByteBuffer from a position
-            // other than the buffer's current position. We thus need to change the buffer's
-            // position to match the requested offset.
-            //
-            // In the future, it may be necessary to compute digests of multiple regions in
-            // parallel. Given that digest computation is a slow operation, we enable multiple
-            // such requests to be fulfilled by this instance. This is achieved by serially
-            // creating a new ByteBuffer corresponding to the requested data range and then,
-            // potentially concurrently, feeding these buffers into MessageDigest instances.
-            ByteBuffer region;
-            synchronized (mBuf) {
-                mBuf.position((int) offset);
-                mBuf.limit((int) offset + size);
-                region = mBuf.slice();
-            }
-
-            for (MessageDigest md : mds) {
-                // Need to reset position to 0 at the start of each iteration because
-                // MessageDigest.update below sets it to the buffer's limit.
-                region.position(0);
-                md.update(region);
-            }
-        }
+        public void finish() {}
     }
 
     /**
diff --git a/core/java/android/util/apk/ApkVerityBuilder.java b/core/java/android/util/apk/ApkVerityBuilder.java
new file mode 100644
index 0000000..0b9552e
--- /dev/null
+++ b/core/java/android/util/apk/ApkVerityBuilder.java
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.apk;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+
+/**
+ * ApkVerityBuilder builds the APK verity tree and the verity header, which will be used by the
+ * kernel to verity the APK content on access.
+ *
+ * <p>Unlike a regular Merkle tree, APK verity tree does not cover the content fully. Due to
+ * the existing APK format, it has to skip APK Signing Block and also has some special treatment for
+ * the "Central Directory offset" field of ZIP End of Central Directory.
+ *
+ * @hide
+ */
+abstract class ApkVerityBuilder {
+    private ApkVerityBuilder() {}
+
+    private static final int CHUNK_SIZE_BYTES = 4096;  // Typical Linux block size
+    private static final int DIGEST_SIZE_BYTES = 32;  // SHA-256 size
+    private static final int FSVERITY_HEADER_SIZE_BYTES = 64;
+    private static final int ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE = 4;
+    private static final int ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_OFFSET = 16;
+    private static final String JCA_DIGEST_ALGORITHM = "SHA-256";
+    private static final byte[] DEFAULT_SALT = new byte[8];
+
+    static class ApkVerityResult {
+        public final ByteBuffer fsverityData;
+        public final byte[] rootHash;
+
+        ApkVerityResult(ByteBuffer fsverityData, byte[] rootHash) {
+            this.fsverityData = fsverityData;
+            this.rootHash = rootHash;
+        }
+    }
+
+    /**
+     * Generates fsverity metadata and the Merkle tree into the {@link ByteBuffer} created by the
+     * {@link ByteBufferFactory}. The bytes layout in the buffer will be used by the kernel and is
+     * ready to be appended to the target file to set up fsverity. For fsverity to work, this data
+     * must be placed at the next page boundary, and the caller must add additional padding in that
+     * case.
+     *
+     * @return ApkVerityResult containing the fsverity data and the root hash of the Merkle tree.
+     */
+    static ApkVerityResult generateApkVerity(RandomAccessFile apk,
+            SignatureInfo signatureInfo, ByteBufferFactory bufferFactory)
+            throws IOException, SecurityException, NoSuchAlgorithmException {
+        assertSigningBlockAlignedAndHasFullPages(signatureInfo);
+
+        long signingBlockSize =
+                signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset;
+        long dataSize = apk.length() - signingBlockSize - ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE;
+        int[] levelOffset = calculateVerityLevelOffset(dataSize);
+        ByteBuffer output = bufferFactory.create(
+                CHUNK_SIZE_BYTES +  // fsverity header + extensions + padding
+                levelOffset[levelOffset.length - 1] +  // Merkle tree size
+                FSVERITY_HEADER_SIZE_BYTES);  // second fsverity header (verbatim copy)
+
+        // Start generating the tree from the block boundary as the kernel will expect.
+        ByteBuffer treeOutput = slice(output, CHUNK_SIZE_BYTES,
+                output.limit() - FSVERITY_HEADER_SIZE_BYTES);
+        byte[] rootHash = generateApkVerityTree(apk, signatureInfo, DEFAULT_SALT, levelOffset,
+                treeOutput);
+
+        ByteBuffer integrityHeader = generateFsverityHeader(apk.length(), DEFAULT_SALT);
+        output.put(integrityHeader);
+        output.put(generateFsverityExtensions());
+
+        integrityHeader.rewind();
+        output.put(integrityHeader);
+        output.rewind();
+        return new ApkVerityResult(output, rootHash);
+    }
+
+    /**
+     * A helper class to consume and digest data by block continuously, and write into a buffer.
+     */
+    private static class BufferedDigester implements DataDigester {
+        /** Amount of the data to digest in each cycle before writting out the digest. */
+        private static final int BUFFER_SIZE = CHUNK_SIZE_BYTES;
+
+        /**
+         * Amount of data the {@link MessageDigest} has consumed since the last reset. This must be
+         * always less than BUFFER_SIZE since {@link MessageDigest} is reset whenever it has
+         * consumed BUFFER_SIZE of data.
+         */
+        private int mBytesDigestedSinceReset;
+
+        /** The final output {@link ByteBuffer} to write the digest to sequentially. */
+        private final ByteBuffer mOutput;
+
+        private final MessageDigest mMd;
+        private final byte[] mSalt;
+
+        private BufferedDigester(byte[] salt, ByteBuffer output) throws NoSuchAlgorithmException {
+            mSalt = salt;
+            mOutput = output.slice();
+            mMd = MessageDigest.getInstance(JCA_DIGEST_ALGORITHM);
+            mMd.update(mSalt);
+            mBytesDigestedSinceReset = 0;
+        }
+
+        /**
+         * Consumes and digests data up to BUFFER_SIZE (may continue from the previous remaining),
+         * then writes the final digest to the output buffer.  Repeat until all data are consumed.
+         * If the last consumption is not enough for BUFFER_SIZE, the state will stay and future
+         * consumption will continuous from there.
+         */
+        @Override
+        public void consume(ByteBuffer buffer) {
+            int offset = buffer.position();
+            int remaining = buffer.remaining();
+            while (remaining > 0) {
+                int allowance = (int) Math.min(remaining, BUFFER_SIZE - mBytesDigestedSinceReset);
+                mMd.update(slice(buffer, offset, offset + allowance));
+                offset += allowance;
+                remaining -= allowance;
+                mBytesDigestedSinceReset += allowance;
+
+                if (mBytesDigestedSinceReset == BUFFER_SIZE) {
+                    byte[] digest = mMd.digest();
+                    mOutput.put(digest);
+
+                    mMd.reset();
+                    mMd.update(mSalt);
+                    mBytesDigestedSinceReset = 0;
+                }
+            }
+        }
+
+        /** Finish the current digestion if any. */
+        @Override
+        public void finish() {
+            if (mBytesDigestedSinceReset == 0) {
+                return;
+            }
+            byte[] digest = mMd.digest();
+            mOutput.put(digest);
+        }
+
+        private void fillUpLastOutputChunk() {
+            int extra = (int) (BUFFER_SIZE - mOutput.position() % BUFFER_SIZE);
+            if (extra == 0) {
+                return;
+            }
+            mOutput.put(ByteBuffer.allocate(extra));
+        }
+    }
+
+    /**
+     * Digest the source by chunk in the given range.  If the last chunk is not a full chunk,
+     * digest the remaining.
+     */
+    private static void consumeByChunk(DataDigester digester, DataSource source, int chunkSize)
+            throws IOException {
+        long inputRemaining = source.size();
+        long inputOffset = 0;
+        while (inputRemaining > 0) {
+            int size = (int) Math.min(inputRemaining, chunkSize);
+            source.feedIntoDataDigester(digester, inputOffset, size);
+            inputOffset += size;
+            inputRemaining -= size;
+        }
+    }
+
+    // Rationale: 1) 1 MB should fit in memory space on all devices. 2) It is not too granular
+    // thus the syscall overhead is not too big.
+    private static final int MMAP_REGION_SIZE_BYTES = 1024 * 1024;
+
+    private static void generateApkVerityDigestAtLeafLevel(RandomAccessFile apk,
+            SignatureInfo signatureInfo, byte[] salt, ByteBuffer output)
+            throws IOException, NoSuchAlgorithmException {
+        BufferedDigester digester = new BufferedDigester(salt, output);
+
+        // 1. Digest from the beginning of the file, until APK Signing Block is reached.
+        consumeByChunk(digester,
+                new MemoryMappedFileDataSource(apk.getFD(), 0, signatureInfo.apkSigningBlockOffset),
+                MMAP_REGION_SIZE_BYTES);
+
+        // 2. Skip APK Signing Block and continue digesting, until the Central Directory offset
+        // field in EoCD is reached.
+        long eocdCdOffsetFieldPosition =
+                signatureInfo.eocdOffset + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_OFFSET;
+        consumeByChunk(digester,
+                new MemoryMappedFileDataSource(apk.getFD(), signatureInfo.centralDirOffset,
+                    eocdCdOffsetFieldPosition - signatureInfo.centralDirOffset),
+                MMAP_REGION_SIZE_BYTES);
+
+        // 3. Fill up the rest of buffer with 0s.
+        ByteBuffer alternativeCentralDirOffset = ByteBuffer.allocate(
+                ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE).order(ByteOrder.LITTLE_ENDIAN);
+        alternativeCentralDirOffset.putInt(Math.toIntExact(signatureInfo.apkSigningBlockOffset));
+        alternativeCentralDirOffset.flip();
+        digester.consume(alternativeCentralDirOffset);
+
+        // 4. Read from end of the Central Directory offset field in EoCD to the end of the file.
+        long offsetAfterEocdCdOffsetField =
+                eocdCdOffsetFieldPosition + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE;
+        consumeByChunk(digester,
+                new MemoryMappedFileDataSource(apk.getFD(), offsetAfterEocdCdOffsetField,
+                    apk.length() - offsetAfterEocdCdOffsetField),
+                MMAP_REGION_SIZE_BYTES);
+        digester.finish();
+
+        // 5. Fill up the rest of buffer with 0s.
+        digester.fillUpLastOutputChunk();
+    }
+
+    private static byte[] generateApkVerityTree(RandomAccessFile apk, SignatureInfo signatureInfo,
+            byte[] salt, int[] levelOffset, ByteBuffer output)
+            throws IOException, NoSuchAlgorithmException {
+        // 1. Digest the apk to generate the leaf level hashes.
+        generateApkVerityDigestAtLeafLevel(apk, signatureInfo, salt, slice(output,
+                    levelOffset[levelOffset.length - 2], levelOffset[levelOffset.length - 1]));
+
+        // 2. Digest the lower level hashes bottom up.
+        for (int level = levelOffset.length - 3; level >= 0; level--) {
+            ByteBuffer inputBuffer = slice(output, levelOffset[level + 1], levelOffset[level + 2]);
+            ByteBuffer outputBuffer = slice(output, levelOffset[level], levelOffset[level + 1]);
+
+            DataSource source = new ByteBufferDataSource(inputBuffer);
+            BufferedDigester digester = new BufferedDigester(salt, outputBuffer);
+            consumeByChunk(digester, source, CHUNK_SIZE_BYTES);
+            digester.finish();
+
+            digester.fillUpLastOutputChunk();
+        }
+
+        // 3. Digest the first block (i.e. first level) to generate the root hash.
+        byte[] rootHash = new byte[DIGEST_SIZE_BYTES];
+        BufferedDigester digester = new BufferedDigester(salt, ByteBuffer.wrap(rootHash));
+        digester.consume(slice(output, 0, CHUNK_SIZE_BYTES));
+        return rootHash;
+    }
+
+    private static ByteBuffer generateFsverityHeader(long fileSize, byte[] salt) {
+        if (salt.length != 8) {
+            throw new IllegalArgumentException("salt is not 8 bytes long");
+        }
+
+        ByteBuffer buffer = ByteBuffer.allocate(FSVERITY_HEADER_SIZE_BYTES);
+        buffer.order(ByteOrder.LITTLE_ENDIAN);
+
+        // TODO(b/30972906): insert a reference when there is a public one.
+        buffer.put("TrueBrew".getBytes());  // magic
+        buffer.put((byte) 1);        // major version
+        buffer.put((byte) 0);        // minor version
+        buffer.put((byte) 12);       // log2(block-size) == log2(4096)
+        buffer.put((byte) 7);        // log2(leaves-per-node) == log2(block-size / digest-size)
+                                     //                       == log2(4096 / 32)
+        buffer.putShort((short) 1);  // meta algorithm, 1: SHA-256 FIXME finalize constant
+        buffer.putShort((short) 1);  // data algorithm, 1: SHA-256 FIXME finalize constant
+        buffer.putInt(0x1);          // flags, 0x1: has extension, FIXME also hide it
+        buffer.putInt(0);            // reserved
+        buffer.putLong(fileSize);    // original i_size
+        buffer.put(salt);            // salt (8 bytes)
+
+        // TODO(b/30972906): Add extension.
+
+        buffer.rewind();
+        return buffer;
+    }
+
+    private static ByteBuffer generateFsverityExtensions() {
+        return ByteBuffer.allocate(64); // TODO(b/30972906): implement this.
+    }
+
+    /**
+     * Returns an array of summed area table of level size in the verity tree.  In other words, the
+     * returned array is offset of each level in the verity tree file format, plus an additional
+     * offset of the next non-existing level (i.e. end of the last level + 1).  Thus the array size
+     * is level + 1.  Thus, the returned array is guarantee to have at least 2 elements.
+     */
+    private static int[] calculateVerityLevelOffset(long fileSize) {
+        ArrayList<Long> levelSize = new ArrayList<>();
+        while (true) {
+            long levelDigestSize = divideRoundup(fileSize, CHUNK_SIZE_BYTES) * DIGEST_SIZE_BYTES;
+            long chunksSize = CHUNK_SIZE_BYTES * divideRoundup(levelDigestSize, CHUNK_SIZE_BYTES);
+            levelSize.add(chunksSize);
+            if (levelDigestSize <= CHUNK_SIZE_BYTES) {
+                break;
+            }
+            fileSize = levelDigestSize;
+        }
+
+        // Reverse and convert to summed area table.
+        int[] levelOffset = new int[levelSize.size() + 1];
+        levelOffset[0] = 0;
+        for (int i = 0; i < levelSize.size(); i++) {
+            // We don't support verity tree if it is larger then Integer.MAX_VALUE.
+            levelOffset[i + 1] = levelOffset[i]
+                    + Math.toIntExact(levelSize.get(levelSize.size() - i - 1));
+        }
+        return levelOffset;
+    }
+
+    private static void assertSigningBlockAlignedAndHasFullPages(SignatureInfo signatureInfo) {
+        if (signatureInfo.apkSigningBlockOffset % CHUNK_SIZE_BYTES != 0) {
+            throw new IllegalArgumentException(
+                    "APK Signing Block does not start at the page  boundary: "
+                    + signatureInfo.apkSigningBlockOffset);
+        }
+
+        if ((signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset)
+                % CHUNK_SIZE_BYTES != 0) {
+            throw new IllegalArgumentException(
+                    "Size of APK Signing Block is not a multiple of 4096: "
+                    + (signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset));
+        }
+    }
+
+    /** Returns a slice of the buffer which shares content with the provided buffer. */
+    private static ByteBuffer slice(ByteBuffer buffer, int begin, int end) {
+        ByteBuffer b = buffer.duplicate();
+        b.position(0);  // to ensure position <= limit invariant.
+        b.limit(end);
+        b.position(begin);
+        return b.slice();
+    }
+
+    /** Divides a number and round up to the closest integer. */
+    private static long divideRoundup(long dividend, long divisor) {
+        return (dividend + divisor - 1) / divisor;
+    }
+}
diff --git a/core/java/android/util/apk/ByteBufferDataSource.java b/core/java/android/util/apk/ByteBufferDataSource.java
new file mode 100644
index 0000000..c2b9eff
--- /dev/null
+++ b/core/java/android/util/apk/ByteBufferDataSource.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.apk;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * {@link DataSource} which provides data from a {@link ByteBuffer}.
+ */
+class ByteBufferDataSource implements DataSource {
+    /**
+     * Underlying buffer. The data is stored between position 0 and the buffer's capacity.
+     * The buffer's position is 0 and limit is equal to capacity.
+     */
+    private final ByteBuffer mBuf;
+
+    ByteBufferDataSource(ByteBuffer buf) {
+        // Defensive copy, to avoid changes to mBuf being visible in buf, and to ensure position is
+        // 0 and limit == capacity.
+        mBuf = buf.slice();
+    }
+
+    @Override
+    public long size() {
+        return mBuf.capacity();
+    }
+
+    @Override
+    public void feedIntoDataDigester(DataDigester md, long offset, int size)
+            throws IOException {
+        // There's no way to tell MessageDigest to read data from ByteBuffer from a position
+        // other than the buffer's current position. We thus need to change the buffer's
+        // position to match the requested offset.
+        //
+        // In the future, it may be necessary to compute digests of multiple regions in
+        // parallel. Given that digest computation is a slow operation, we enable multiple
+        // such requests to be fulfilled by this instance. This is achieved by serially
+        // creating a new ByteBuffer corresponding to the requested data range and then,
+        // potentially concurrently, feeding these buffers into MessageDigest instances.
+        ByteBuffer region;
+        synchronized (mBuf) {
+            mBuf.position(0);
+            mBuf.limit((int) offset + size);
+            mBuf.position((int) offset);
+            region = mBuf.slice();
+        }
+
+        md.consume(region);
+    }
+}
diff --git a/core/java/android/util/apk/ByteBufferFactory.java b/core/java/android/util/apk/ByteBufferFactory.java
new file mode 100644
index 0000000..7a99882
--- /dev/null
+++ b/core/java/android/util/apk/ByteBufferFactory.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.apk;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Provider of {@link ByteBuffer} instances.
+ * @hide
+ */
+public interface ByteBufferFactory {
+    /** Initiates a {@link ByteBuffer} with the given size. */
+    ByteBuffer create(int capacity);
+}
diff --git a/core/java/android/util/apk/DataDigester.java b/core/java/android/util/apk/DataDigester.java
new file mode 100644
index 0000000..74dce7e
--- /dev/null
+++ b/core/java/android/util/apk/DataDigester.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.apk;
+
+import java.nio.ByteBuffer;
+
+interface DataDigester {
+    /** Consumes the {@link ByteBuffer}. */
+    void consume(ByteBuffer buffer);
+
+    /** Finishes the digestion. Must be called after the last {@link #consume(ByteBuffer)}. */
+    void finish();
+}
diff --git a/core/java/android/util/apk/DataSource.java b/core/java/android/util/apk/DataSource.java
new file mode 100644
index 0000000..2b39f49
--- /dev/null
+++ b/core/java/android/util/apk/DataSource.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.apk;
+
+import java.io.IOException;
+
+/** Source of data to be digested. */
+interface DataSource {
+
+    /**
+     * Returns the size (in bytes) of the data offered by this source.
+     */
+    long size();
+
+    /**
+     * Feeds the specified region of this source's data into the provided digester.
+     *
+     * @param offset offset of the region inside this data source.
+     * @param size size (in bytes) of the region.
+     */
+    void feedIntoDataDigester(DataDigester md, long offset, int size) throws IOException;
+}
diff --git a/core/java/android/util/apk/MemoryMappedFileDataSource.java b/core/java/android/util/apk/MemoryMappedFileDataSource.java
new file mode 100644
index 0000000..04a1c6b
--- /dev/null
+++ b/core/java/android/util/apk/MemoryMappedFileDataSource.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.apk;
+
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.DirectByteBuffer;
+
+/**
+ * {@link DataSource} which provides data from a file descriptor by memory-mapping the sections
+ * of the file.
+ */
+class MemoryMappedFileDataSource implements DataSource {
+    private static final long MEMORY_PAGE_SIZE_BYTES = Os.sysconf(OsConstants._SC_PAGESIZE);
+
+    private final FileDescriptor mFd;
+    private final long mFilePosition;
+    private final long mSize;
+
+    /**
+     * Constructs a new {@code MemoryMappedFileDataSource} for the specified region of the file.
+     *
+     * @param position start position of the region in the file.
+     * @param size size (in bytes) of the region.
+     */
+    MemoryMappedFileDataSource(FileDescriptor fd, long position, long size) {
+        mFd = fd;
+        mFilePosition = position;
+        mSize = size;
+    }
+
+    @Override
+    public long size() {
+        return mSize;
+    }
+
+    @Override
+    public void feedIntoDataDigester(DataDigester md, long offset, int size)
+            throws IOException {
+        // IMPLEMENTATION NOTE: After a lot of experimentation, the implementation of this
+        // method was settled on a straightforward mmap with prefaulting.
+        //
+        // This method is not using FileChannel.map API because that API does not offset a way
+        // to "prefault" the resulting memory pages. Without prefaulting, performance is about
+        // 10% slower on small to medium APKs, but is significantly worse for APKs in 500+ MB
+        // range. FileChannel.load (which currently uses madvise) doesn't help. Finally,
+        // invoking madvise (MADV_SEQUENTIAL) after mmap with prefaulting wastes quite a bit of
+        // time, which is not compensated for by faster reads.
+
+        // We mmap the smallest region of the file containing the requested data. mmap requires
+        // that the start offset in the file must be a multiple of memory page size. We thus may
+        // need to mmap from an offset less than the requested offset.
+        long filePosition = mFilePosition + offset;
+        long mmapFilePosition =
+                (filePosition / MEMORY_PAGE_SIZE_BYTES) * MEMORY_PAGE_SIZE_BYTES;
+        int dataStartOffsetInMmapRegion = (int) (filePosition - mmapFilePosition);
+        long mmapRegionSize = size + dataStartOffsetInMmapRegion;
+        long mmapPtr = 0;
+        try {
+            mmapPtr = Os.mmap(
+                    0, // let the OS choose the start address of the region in memory
+                    mmapRegionSize,
+                    OsConstants.PROT_READ,
+                    OsConstants.MAP_SHARED | OsConstants.MAP_POPULATE, // "prefault" all pages
+                    mFd,
+                    mmapFilePosition);
+            ByteBuffer buf = new DirectByteBuffer(
+                    size,
+                    mmapPtr + dataStartOffsetInMmapRegion,
+                    mFd,  // not really needed, but just in case
+                    null, // no need to clean up -- it's taken care of by the finally block
+                    true  // read only buffer
+                    );
+            md.consume(buf);
+        } catch (ErrnoException e) {
+            throw new IOException("Failed to mmap " + mmapRegionSize + " bytes", e);
+        } finally {
+            if (mmapPtr != 0) {
+                try {
+                    Os.munmap(mmapPtr, mmapRegionSize);
+                } catch (ErrnoException ignored) { }
+            }
+        }
+    }
+}
diff --git a/core/java/android/util/apk/SignatureInfo.java b/core/java/android/util/apk/SignatureInfo.java
new file mode 100644
index 0000000..8e1233a
--- /dev/null
+++ b/core/java/android/util/apk/SignatureInfo.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.apk;
+
+import java.nio.ByteBuffer;
+
+/**
+ * APK Signature Scheme v2 block and additional information relevant to verifying the signatures
+ * contained in the block against the file.
+ */
+class SignatureInfo {
+    /** Contents of APK Signature Scheme v2 block. */
+    public final ByteBuffer signatureBlock;
+
+    /** Position of the APK Signing Block in the file. */
+    public final long apkSigningBlockOffset;
+
+    /** Position of the ZIP Central Directory in the file. */
+    public final long centralDirOffset;
+
+    /** Position of the ZIP End of Central Directory (EoCD) in the file. */
+    public final long eocdOffset;
+
+    /** Contents of ZIP End of Central Directory (EoCD) of the file. */
+    public final ByteBuffer eocd;
+
+    SignatureInfo(ByteBuffer signatureBlock, long apkSigningBlockOffset, long centralDirOffset,
+            long eocdOffset, ByteBuffer eocd) {
+        this.signatureBlock = signatureBlock;
+        this.apkSigningBlockOffset = apkSigningBlockOffset;
+        this.centralDirOffset = centralDirOffset;
+        this.eocdOffset = eocdOffset;
+        this.eocd = eocd;
+    }
+}
diff --git a/core/java/android/util/proto/ProtoOutputStream.java b/core/java/android/util/proto/ProtoOutputStream.java
index 43a9789..a94806a 100644
--- a/core/java/android/util/proto/ProtoOutputStream.java
+++ b/core/java/android/util/proto/ProtoOutputStream.java
@@ -127,42 +127,48 @@
 
     public static final long FIELD_TYPE_UNKNOWN = 0;
 
+    /**
+     * The types are copied from external/protobuf/src/google/protobuf/descriptor.h directly,
+     * so no extra mapping needs to be maintained in this case.
+     */
     public static final long FIELD_TYPE_DOUBLE = 1L << FIELD_TYPE_SHIFT;
     public static final long FIELD_TYPE_FLOAT = 2L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_INT32 = 3L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_INT64 = 4L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_UINT32 = 5L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_UINT64 = 6L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_SINT32 = 7L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_SINT64 = 8L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_FIXED32 = 9L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_FIXED64 = 10L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_SFIXED32 = 11L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_SFIXED64 = 12L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_BOOL = 13L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_STRING = 14L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_BYTES = 15L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_ENUM = 16L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_OBJECT = 17L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_INT64 = 3L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_UINT64 = 4L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_INT32 = 5L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_FIXED64 = 6L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_FIXED32 = 7L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_BOOL = 8L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_STRING = 9L << FIELD_TYPE_SHIFT;
+//  public static final long FIELD_TYPE_GROUP = 10L << FIELD_TYPE_SHIFT; // Deprecated.
+    public static final long FIELD_TYPE_MESSAGE = 11L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_BYTES = 12L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_UINT32 = 13L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_ENUM = 14L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_SFIXED32 = 15L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_SFIXED64 = 16L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_SINT32 = 17L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_SINT64 = 18L << FIELD_TYPE_SHIFT;
 
     private static final String[] FIELD_TYPE_NAMES = new String[] {
         "Double",
         "Float",
-        "Int32",
         "Int64",
-        "UInt32",
         "UInt64",
-        "SInt32",
-        "SInt64",
-        "Fixed32",
+        "Int32",
         "Fixed64",
-        "SFixed32",
-        "SFixed64",
+        "Fixed32",
         "Bool",
         "String",
+        "Group",  // This field is deprecated but reserved here for indexing.
+        "Message",
         "Bytes",
+        "UInt32",
         "Enum",
-        "Object",
+        "SFixed32",
+        "SFixed64",
+        "SInt32",
+        "SInt64",
     };
 
     //
@@ -867,21 +873,21 @@
         assertNotCompacted();
         final int id = (int)fieldId;
 
-        switch ((int)((fieldId & (FIELD_TYPE_MASK | FIELD_COUNT_MASK)) >> FIELD_TYPE_SHIFT)) {
+        switch ((int) ((fieldId & (FIELD_TYPE_MASK | FIELD_COUNT_MASK)) >> FIELD_TYPE_SHIFT)) {
             // bytes
-            case (int)((FIELD_TYPE_BYTES | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
+            case (int) ((FIELD_TYPE_BYTES | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
                 writeBytesImpl(id, val);
                 break;
-            case (int)((FIELD_TYPE_BYTES | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
-            case (int)((FIELD_TYPE_BYTES | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
+            case (int) ((FIELD_TYPE_BYTES | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
+            case (int) ((FIELD_TYPE_BYTES | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
                 writeRepeatedBytesImpl(id, val);
                 break;
             // Object
-            case (int)((FIELD_TYPE_OBJECT | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
+            case (int) ((FIELD_TYPE_MESSAGE | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
                 writeObjectImpl(id, val);
                 break;
-            case (int)((FIELD_TYPE_OBJECT | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
-            case (int)((FIELD_TYPE_OBJECT | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
+            case (int) ((FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
+            case (int) ((FIELD_TYPE_MESSAGE | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
                 writeRepeatedObjectImpl(id, val);
                 break;
             // nothing else allowed
@@ -899,7 +905,7 @@
         assertNotCompacted();
         final int id = (int)fieldId;
 
-        if ((fieldId & FIELD_TYPE_MASK) == FIELD_TYPE_OBJECT) {
+        if ((fieldId & FIELD_TYPE_MASK) == FIELD_TYPE_MESSAGE) {
             final long count = fieldId & FIELD_COUNT_MASK;
             if (count == FIELD_COUNT_SINGLE) {
                 return startObjectImpl(id, false);
@@ -2091,7 +2097,7 @@
     @Deprecated
     public long startObject(long fieldId) {
         assertNotCompacted();
-        final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_OBJECT);
+        final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_MESSAGE);
 
         return startObjectImpl(id, false);
     }
@@ -2119,7 +2125,7 @@
     @Deprecated
     public long startRepeatedObject(long fieldId) {
         assertNotCompacted();
-        final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_OBJECT);
+        final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_MESSAGE);
 
         return startObjectImpl(id, true);
     }
@@ -2217,7 +2223,7 @@
     @Deprecated
     public void writeObject(long fieldId, byte[] value) {
         assertNotCompacted();
-        final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_OBJECT);
+        final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_MESSAGE);
 
         writeObjectImpl(id, value);
     }
@@ -2237,7 +2243,7 @@
     @Deprecated
     public void writeRepeatedObject(long fieldId, byte[] value) {
         assertNotCompacted();
-        final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_OBJECT);
+        final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_MESSAGE);
 
         writeRepeatedObjectImpl(id, value);
     }
@@ -2296,7 +2302,7 @@
             final String typeString = getFieldTypeString(fieldType);
             if (typeString != null && countString != null) {
                 final StringBuilder sb = new StringBuilder();
-                if (expectedType == FIELD_TYPE_OBJECT) {
+                if (expectedType == FIELD_TYPE_MESSAGE) {
                     sb.append("start");
                 } else {
                     sb.append("write");
@@ -2306,7 +2312,7 @@
                 sb.append(" called for field ");
                 sb.append((int)fieldId);
                 sb.append(" which should be used with ");
-                if (fieldType == FIELD_TYPE_OBJECT) {
+                if (fieldType == FIELD_TYPE_MESSAGE) {
                     sb.append("start");
                 } else {
                     sb.append("write");
@@ -2321,7 +2327,7 @@
                 throw new IllegalArgumentException(sb.toString());
             } else {
                 final StringBuilder sb = new StringBuilder();
-                if (expectedType == FIELD_TYPE_OBJECT) {
+                if (expectedType == FIELD_TYPE_MESSAGE) {
                     sb.append("start");
                 } else {
                     sb.append("write");
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index 5804560..ab0b3ee 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -20,6 +20,7 @@
 import android.app.Notification;
 import android.content.Context;
 import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Outline;
 import android.graphics.Rect;
@@ -43,6 +44,7 @@
     public static final int NO_COLOR = Notification.COLOR_INVALID;
     private final int mChildMinWidth;
     private final int mContentEndMargin;
+    private final int mGravity;
     private View mAppName;
     private View mHeaderText;
     private OnClickListener mExpandClickListener;
@@ -50,7 +52,6 @@
     private ImageView mExpandButton;
     private CachingIconView mIcon;
     private View mProfileBadge;
-    private View mInfo;
     private int mIconColor;
     private int mOriginalNotificationColor;
     private boolean mExpanded;
@@ -61,6 +62,7 @@
     private boolean mEntireHeaderClickable;
     private boolean mExpandOnlyOnButton;
     private boolean mAcceptAllTouches;
+    private int mTotalWidth;
 
     ViewOutlineProvider mProvider = new ViewOutlineProvider() {
         @Override
@@ -92,6 +94,11 @@
         mHeaderBackgroundHeight = res.getDimensionPixelSize(
                 R.dimen.notification_header_background_height);
         mEntireHeaderClickable = res.getBoolean(R.bool.config_notificationHeaderClickableForExpand);
+
+        int[] attrIds = { android.R.attr.gravity };
+        TypedArray ta = context.obtainStyledAttributes(attrs, attrIds, defStyleAttr, defStyleRes);
+        mGravity = ta.getInt(0, 0);
+        ta.recycle();
     }
 
     @Override
@@ -146,6 +153,7 @@
                 mHeaderText.measure(childWidthSpec, wrapContentHeightSpec);
             }
         }
+        mTotalWidth = Math.min(totalWidth, givenWidth);
         setMeasuredDimension(givenWidth, givenHeight);
     }
 
@@ -153,6 +161,10 @@
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         int left = getPaddingStart();
         int end = getMeasuredWidth();
+        final boolean centerAligned = (mGravity & Gravity.CENTER_HORIZONTAL) != 0;
+        if (centerAligned) {
+            left += getMeasuredWidth() / 2 - mTotalWidth / 2;
+        }
         int childCount = getChildCount();
         int ownHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
         for (int i = 0; i < childCount; i++) {
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 19213ca..c3d6c69 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -187,8 +187,11 @@
                     Log.i(LOG_TAG, "Window cache miss");
                 }
                 final long identityToken = Binder.clearCallingIdentity();
-                window = connection.getWindow(accessibilityWindowId);
-                Binder.restoreCallingIdentity(identityToken);
+                try {
+                    window = connection.getWindow(accessibilityWindowId);
+                } finally {
+                    Binder.restoreCallingIdentity(identityToken);
+                }
                 if (window != null) {
                     sAccessibilityCache.addWindow(window);
                     return window;
@@ -225,8 +228,11 @@
                     Log.i(LOG_TAG, "Windows cache miss");
                 }
                 final long identityToken = Binder.clearCallingIdentity();
-                windows = connection.getWindows();
-                Binder.restoreCallingIdentity(identityToken);
+                try {
+                    windows = connection.getWindows();
+                } finally {
+                    Binder.restoreCallingIdentity(identityToken);
+                }
                 if (windows != null) {
                     sAccessibilityCache.setWindows(windows);
                     return windows;
@@ -283,10 +289,14 @@
                 }
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 final long identityToken = Binder.clearCallingIdentity();
-                final boolean success = connection.findAccessibilityNodeInfoByAccessibilityId(
-                        accessibilityWindowId, accessibilityNodeId, interactionId, this,
-                        prefetchFlags, Thread.currentThread().getId(), arguments);
-                Binder.restoreCallingIdentity(identityToken);
+                final boolean success;
+                try {
+                    success = connection.findAccessibilityNodeInfoByAccessibilityId(
+                            accessibilityWindowId, accessibilityNodeId, interactionId, this,
+                            prefetchFlags, Thread.currentThread().getId(), arguments);
+                } finally {
+                    Binder.restoreCallingIdentity(identityToken);
+                }
                 if (success) {
                     List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
                             interactionId);
@@ -333,10 +343,15 @@
             if (connection != null) {
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 final long identityToken = Binder.clearCallingIdentity();
-                final boolean success = connection.findAccessibilityNodeInfosByViewId(
-                        accessibilityWindowId, accessibilityNodeId, viewId, interactionId, this,
-                        Thread.currentThread().getId());
-                Binder.restoreCallingIdentity(identityToken);
+                final boolean success;
+                try {
+                    success = connection.findAccessibilityNodeInfosByViewId(
+                            accessibilityWindowId, accessibilityNodeId, viewId, interactionId, this,
+                            Thread.currentThread().getId());
+                } finally {
+                    Binder.restoreCallingIdentity(identityToken);
+                }
+
                 if (success) {
                     List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
                             interactionId);
@@ -381,10 +396,15 @@
             if (connection != null) {
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 final long identityToken = Binder.clearCallingIdentity();
-                final boolean success = connection.findAccessibilityNodeInfosByText(
-                        accessibilityWindowId, accessibilityNodeId, text, interactionId, this,
-                        Thread.currentThread().getId());
-                Binder.restoreCallingIdentity(identityToken);
+                final boolean success;
+                try {
+                    success = connection.findAccessibilityNodeInfosByText(
+                            accessibilityWindowId, accessibilityNodeId, text, interactionId, this,
+                            Thread.currentThread().getId());
+                } finally {
+                    Binder.restoreCallingIdentity(identityToken);
+                }
+
                 if (success) {
                     List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
                             interactionId);
@@ -428,10 +448,15 @@
             if (connection != null) {
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 final long identityToken = Binder.clearCallingIdentity();
-                final boolean success = connection.findFocus(accessibilityWindowId,
-                        accessibilityNodeId, focusType, interactionId, this,
-                        Thread.currentThread().getId());
-                Binder.restoreCallingIdentity(identityToken);
+                final boolean success;
+                try {
+                    success = connection.findFocus(accessibilityWindowId,
+                            accessibilityNodeId, focusType, interactionId, this,
+                            Thread.currentThread().getId());
+                } finally {
+                    Binder.restoreCallingIdentity(identityToken);
+                }
+
                 if (success) {
                     AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
                             interactionId);
@@ -472,10 +497,15 @@
             if (connection != null) {
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 final long identityToken = Binder.clearCallingIdentity();
-                final boolean success = connection.focusSearch(accessibilityWindowId,
-                        accessibilityNodeId, direction, interactionId, this,
-                        Thread.currentThread().getId());
-                Binder.restoreCallingIdentity(identityToken);
+                final boolean success;
+                try {
+                    success = connection.focusSearch(accessibilityWindowId,
+                            accessibilityNodeId, direction, interactionId, this,
+                            Thread.currentThread().getId());
+                } finally {
+                    Binder.restoreCallingIdentity(identityToken);
+                }
+
                 if (success) {
                     AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
                             interactionId);
@@ -515,10 +545,15 @@
             if (connection != null) {
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 final long identityToken = Binder.clearCallingIdentity();
-                final boolean success = connection.performAccessibilityAction(
-                        accessibilityWindowId, accessibilityNodeId, action, arguments,
-                        interactionId, this, Thread.currentThread().getId());
-                Binder.restoreCallingIdentity(identityToken);
+                final boolean success;
+                try {
+                    success = connection.performAccessibilityAction(
+                            accessibilityWindowId, accessibilityNodeId, action, arguments,
+                            interactionId, this, Thread.currentThread().getId());
+                } finally {
+                    Binder.restoreCallingIdentity(identityToken);
+                }
+
                 if (success) {
                     return getPerformAccessibilityActionResultAndClear(interactionId);
                 }
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 0b9bc57..35f6acb 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -436,8 +436,11 @@
             // client using it is called through Binder from another process. Example: MMS
             // app adds a SMS notification and the NotificationManagerService calls this method
             long identityToken = Binder.clearCallingIdentity();
-            service.sendAccessibilityEvent(event, userId);
-            Binder.restoreCallingIdentity(identityToken);
+            try {
+                service.sendAccessibilityEvent(event, userId);
+            } finally {
+                Binder.restoreCallingIdentity(identityToken);
+            }
             if (DEBUG) {
                 Log.i(LOG_TAG, event + " sent");
             }
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 6a0669b..a56f86d 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -1897,7 +1897,7 @@
     public abstract static class AutofillCallback {
 
         /** @hide */
-        @IntDef({EVENT_INPUT_SHOWN, EVENT_INPUT_HIDDEN})
+        @IntDef({EVENT_INPUT_SHOWN, EVENT_INPUT_HIDDEN, EVENT_INPUT_UNAVAILABLE})
         @Retention(RetentionPolicy.SOURCE)
         public @interface AutofillEventType {}
 
diff --git a/core/java/com/android/internal/colorextraction/types/Tonal.java b/core/java/com/android/internal/colorextraction/types/Tonal.java
index e6ef10b..71baaf1 100644
--- a/core/java/com/android/internal/colorextraction/types/Tonal.java
+++ b/core/java/com/android/internal/colorextraction/types/Tonal.java
@@ -51,9 +51,11 @@
 
     private static final boolean DEBUG = true;
 
+    public static final int THRESHOLD_COLOR_LIGHT = 0xffe0e0e0;
     public static final int MAIN_COLOR_LIGHT = 0xffe0e0e0;
     public static final int SECONDARY_COLOR_LIGHT = 0xff9e9e9e;
-    public static final int MAIN_COLOR_DARK = 0xff212121;
+    public static final int THRESHOLD_COLOR_DARK = 0xff212121;
+    public static final int MAIN_COLOR_DARK = 0xff000000;
     public static final int SECONDARY_COLOR_DARK = 0xff000000;
 
     private final TonalPalette mGreyPalette;
@@ -197,12 +199,12 @@
         // light fallback or darker than our dark fallback.
         ColorUtils.colorToHSL(mainColor, mTmpHSL);
         final float mainLuminosity = mTmpHSL[2];
-        ColorUtils.colorToHSL(MAIN_COLOR_LIGHT, mTmpHSL);
+        ColorUtils.colorToHSL(THRESHOLD_COLOR_LIGHT, mTmpHSL);
         final float lightLuminosity = mTmpHSL[2];
         if (mainLuminosity > lightLuminosity) {
             return false;
         }
-        ColorUtils.colorToHSL(MAIN_COLOR_DARK, mTmpHSL);
+        ColorUtils.colorToHSL(THRESHOLD_COLOR_DARK, mTmpHSL);
         final float darkLuminosity = mTmpHSL[2];
         if (mainLuminosity < darkLuminosity) {
             return false;
diff --git a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
index fb6b8b0..3af3e2a 100644
--- a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
@@ -16,6 +16,10 @@
 
 package com.android.internal.policy;
 
+import static android.view.WindowManager.DOCKED_INVALID;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_RIGHT;
+
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -99,11 +103,12 @@
 
     public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize,
             boolean isHorizontalDivision, Rect insets) {
-        this(res, displayWidth, displayHeight, dividerSize, isHorizontalDivision, insets, false);
+        this(res, displayWidth, displayHeight, dividerSize, isHorizontalDivision, insets,
+                DOCKED_INVALID, false);
     }
 
     public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize,
-            boolean isHorizontalDivision, Rect insets, boolean isMinimizedMode) {
+            boolean isHorizontalDivision, Rect insets, int dockSide, boolean isMinimizedMode) {
         mMinFlingVelocityPxPerSecond =
                 MIN_FLING_VELOCITY_DP_PER_SECOND * res.getDisplayMetrics().density;
         mMinDismissVelocityPxPerSecond =
@@ -121,7 +126,7 @@
                 com.android.internal.R.dimen.default_minimal_size_resizable_task);
         mTaskHeightInMinimizedMode = res.getDimensionPixelSize(
                 com.android.internal.R.dimen.task_height_of_minimized_mode);
-        calculateTargets(isHorizontalDivision);
+        calculateTargets(isHorizontalDivision, dockSide);
         mFirstSplitTarget = mTargets.get(1);
         mLastSplitTarget = mTargets.get(mTargets.size() - 2);
         mDismissStartTarget = mTargets.get(0);
@@ -254,7 +259,7 @@
         return mTargets.get(minIndex);
     }
 
-    private void calculateTargets(boolean isHorizontalDivision) {
+    private void calculateTargets(boolean isHorizontalDivision, int dockedSide) {
         mTargets.clear();
         int dividerMax = isHorizontalDivision
                 ? mDisplayHeight
@@ -273,7 +278,7 @@
                 addMiddleTarget(isHorizontalDivision);
                 break;
             case SNAP_MODE_MINIMIZED:
-                addMinimizedTarget(isHorizontalDivision);
+                addMinimizedTarget(isHorizontalDivision, dockedSide);
                 break;
         }
         mTargets.add(new SnapTarget(dividerMax - navBarSize, dividerMax,
@@ -331,12 +336,16 @@
         mTargets.add(new SnapTarget(position, position, SnapTarget.FLAG_NONE));
     }
 
-    private void addMinimizedTarget(boolean isHorizontalDivision) {
+    private void addMinimizedTarget(boolean isHorizontalDivision, int dockedSide) {
         // In portrait offset the position by the statusbar height, in landscape add the statusbar
         // height as well to match portrait offset
         int position = mTaskHeightInMinimizedMode + mInsets.top;
         if (!isHorizontalDivision) {
-            position += mInsets.left;
+            if (dockedSide == DOCKED_LEFT) {
+                position += mInsets.left;
+            } else if (dockedSide == DOCKED_RIGHT) {
+                position = mDisplayWidth - position - mInsets.right;
+            }
         }
         mTargets.add(new SnapTarget(position, position, SnapTarget.FLAG_NONE));
     }
diff --git a/core/java/com/android/internal/widget/NotificationActionListLayout.java b/core/java/com/android/internal/widget/NotificationActionListLayout.java
index 073aac5..26023b4 100644
--- a/core/java/com/android/internal/widget/NotificationActionListLayout.java
+++ b/core/java/com/android/internal/widget/NotificationActionListLayout.java
@@ -16,7 +16,10 @@
 
 package com.android.internal.widget;
 
+import android.annotation.Nullable;
 import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.Pair;
@@ -37,6 +40,7 @@
 @RemoteViews.RemoteView
 public class NotificationActionListLayout extends LinearLayout {
 
+    private final int mGravity;
     private int mTotalWidth = 0;
     private ArrayList<Pair<Integer, TextView>> mMeasureOrderTextViews = new ArrayList<>();
     private ArrayList<View> mMeasureOrderOther = new ArrayList<>();
@@ -45,7 +49,20 @@
     private Drawable mDefaultBackground;
 
     public NotificationActionListLayout(Context context, AttributeSet attrs) {
-        super(context, attrs);
+        this(context, attrs, 0);
+    }
+
+    public NotificationActionListLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public NotificationActionListLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+
+        int[] attrIds = { android.R.attr.gravity };
+        TypedArray ta = context.obtainStyledAttributes(attrs, attrIds, defStyleAttr, defStyleRes);
+        mGravity = ta.getInt(0, 0);
+        ta.recycle();
     }
 
     @Override
@@ -95,6 +112,7 @@
 
         final boolean constrained =
                 MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED;
+        final boolean centerAligned = (mGravity & Gravity.CENTER_HORIZONTAL) != 0;
 
         final int innerWidth = MeasureSpec.getSize(widthMeasureSpec) - mPaddingLeft - mPaddingRight;
         final int otherSize = mMeasureOrderOther.size();
@@ -137,7 +155,7 @@
 
         // Make sure to measure the last child full-width if we didn't use up the entire width,
         // or we didn't measure yet because there's just one child.
-        if (lastNotGoneChild != null && (constrained && usedWidth < innerWidth
+        if (lastNotGoneChild != null && !centerAligned && (constrained && usedWidth < innerWidth
                 || notGoneChildren == 1)) {
             MarginLayoutParams lp = (MarginLayoutParams) lastNotGoneChild.getLayoutParams();
             if (notGoneChildren > 1) {
@@ -201,9 +219,10 @@
         }
         final boolean isLayoutRtl = isLayoutRtl();
         final int paddingTop = mPaddingTop;
+        final boolean centerAligned = (mGravity & Gravity.CENTER_HORIZONTAL) != 0;
 
         int childTop;
-        int childLeft;
+        int childLeft = centerAligned ? left + (right - left) / 2 - mTotalWidth / 2 : 0;
 
         // Where bottom of child should go
         final int height = bottom - top;
@@ -216,13 +235,12 @@
         final int layoutDirection = getLayoutDirection();
         switch (Gravity.getAbsoluteGravity(Gravity.START, layoutDirection)) {
             case Gravity.RIGHT:
-                // mTotalWidth contains the padding already
-                childLeft = mPaddingLeft + right - left - mTotalWidth;
+                childLeft += mPaddingLeft + right - left - mTotalWidth;
                 break;
 
             case Gravity.LEFT:
             default:
-                childLeft = mPaddingLeft;
+                childLeft += mPaddingLeft;
                 break;
         }
 
diff --git a/core/jni/android_os_HwBlob.cpp b/core/jni/android_os_HwBlob.cpp
index 737ec47..bb916d2 100644
--- a/core/jni/android_os_HwBlob.cpp
+++ b/core/jni/android_os_HwBlob.cpp
@@ -26,6 +26,7 @@
 #include <android_runtime/AndroidRuntime.h>
 #include <hidl/Status.h>
 #include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
 
 #include "core_jni_helpers.h"
 
@@ -349,6 +350,13 @@
                 static_cast<const uint8_t *>(blob->data()) + offset));         \
 }
 
+DEFINE_BLOB_ARRAY_COPIER(Int8,jbyte,Byte)
+DEFINE_BLOB_ARRAY_COPIER(Int16,jshort,Short)
+DEFINE_BLOB_ARRAY_COPIER(Int32,jint,Int)
+DEFINE_BLOB_ARRAY_COPIER(Int64,jlong,Long)
+DEFINE_BLOB_ARRAY_COPIER(Float,jfloat,Float)
+DEFINE_BLOB_ARRAY_COPIER(Double,jdouble,Double)
+
 static void JHwBlob_native_copyToBoolArray(
         JNIEnv *env,
         jobject thiz,
@@ -386,13 +394,6 @@
     dst = nullptr;
 }
 
-DEFINE_BLOB_ARRAY_COPIER(Int8,jbyte,Byte)
-DEFINE_BLOB_ARRAY_COPIER(Int16,jshort,Short)
-DEFINE_BLOB_ARRAY_COPIER(Int32,jint,Int)
-DEFINE_BLOB_ARRAY_COPIER(Int64,jlong,Long)
-DEFINE_BLOB_ARRAY_COPIER(Float,jfloat,Float)
-DEFINE_BLOB_ARRAY_COPIER(Double,jdouble,Double)
-
 #define DEFINE_BLOB_PUTTER(Suffix,Type)                                        \
 static void JHwBlob_native_put ## Suffix(                                      \
         JNIEnv *env, jobject thiz, jlong offset, Type x) {                     \
@@ -458,23 +459,17 @@
 #define DEFINE_BLOB_ARRAY_PUTTER(Suffix,Type,NewType)                          \
 static void JHwBlob_native_put ## Suffix ## Array(                             \
         JNIEnv *env, jobject thiz, jlong offset, Type ## Array array) {        \
+    Scoped ## NewType ## ArrayRO autoArray(env, array);                        \
                                                                                \
     if (array == nullptr) {                                                    \
-        jniThrowException(env, "java/lang/NullPointerException", nullptr);     \
+        /* NullpointerException already pending */                             \
         return;                                                                \
     }                                                                          \
                                                                                \
     sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);                   \
                                                                                \
-    jsize len = env->GetArrayLength(array);                                    \
-                                                                               \
-    Type *src =                                                                \
-        env->Get ## NewType ## ArrayElements(array, nullptr /* isCopy */);     \
-                                                                               \
-    status_t err = blob->write(offset, src, len * sizeof(Type));               \
-                                                                               \
-    env->Release ## NewType ## ArrayElements(array, src, 0 /* mode */);        \
-    src = nullptr;                                                             \
+    status_t err = blob->write(                                                \
+            offset, autoArray.get(), autoArray.size() * sizeof(Type));         \
                                                                                \
     if (err != OK) {                                                           \
         signalExceptionForError(env, err);                                     \
@@ -490,35 +485,28 @@
 
 static void JHwBlob_native_putBoolArray(
         JNIEnv *env, jobject thiz, jlong offset, jbooleanArray array) {
+    ScopedBooleanArrayRO autoArray(env, array);
 
     if (array == nullptr) {
-        jniThrowException(env, "java/lang/NullPointerException", nullptr);
+        /* NullpointerException already pending */
         return;
     }
 
     sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
 
-    jsize len = env->GetArrayLength(array);
-
-    if ((offset + len * sizeof(bool)) > blob->size()) {
+    if ((offset + autoArray.size() * sizeof(bool)) > blob->size()) {
         signalExceptionForError(env, -ERANGE);
         return;
     }
 
-    const jboolean *src =
-        env->GetBooleanArrayElements(array, nullptr /* isCopy */);
+    const jboolean *src = autoArray.get();
 
     bool *dst = reinterpret_cast<bool *>(
             static_cast<uint8_t *>(blob->data()) + offset);
 
-    for (jsize i = 0; i < len; ++i) {
+    for (size_t i = 0; i < autoArray.size(); ++i) {
         dst[i] = src[i];
     }
-
-    env->ReleaseBooleanArrayElements(
-            array, const_cast<jboolean *>(src), 0 /* mode */);
-
-    src = nullptr;
 }
 
 static void JHwBlob_native_putBlob(
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 50e811d..e998b09 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -27,6 +27,7 @@
 import "frameworks/base/core/proto/android/os/procrank.proto";
 import "frameworks/base/core/proto/android/server/activitymanagerservice.proto";
 import "frameworks/base/core/proto/android/server/alarmmanagerservice.proto";
+import "frameworks/base/core/proto/android/server/windowmanagerservice.proto";
 import "frameworks/base/core/proto/android/server/fingerprint.proto";
 import "frameworks/base/core/proto/android/server/powermanagerservice.proto";
 import "frameworks/base/core/proto/android/service/appwidget.proto";
@@ -135,4 +136,9 @@
         (section).type = SECTION_DUMPSYS,
         (section).args = "alarm --proto"
     ];
+
+    optional com.android.server.wm.proto.WindowManagerServiceProto window = 3017 [
+        (section).type = SECTION_DUMPSYS,
+        (section).args = "window --proto"
+    ];
 }
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 064523a..4d48a42 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -15,6 +15,7 @@
  */
 
 syntax = "proto2";
+
 import "frameworks/base/core/proto/android/content/configuration.proto";
 import "frameworks/base/core/proto/android/graphics/rect.proto";
 import "frameworks/base/core/proto/android/view/displayinfo.proto";
diff --git a/core/res/res/drawable/dialog_background_material.xml b/core/res/res/drawable/dialog_background_material.xml
index 2f8d1fa..e017d3c 100644
--- a/core/res/res/drawable/dialog_background_material.xml
+++ b/core/res/res/drawable/dialog_background_material.xml
@@ -17,7 +17,7 @@
 <inset xmlns:android="http://schemas.android.com/apk/res/android"
     android:inset="16dp">
     <shape android:shape="rectangle">
-        <corners android:radius="2dp" />
+        <corners android:radius="?attr/dialogCornerRadius" />
         <solid android:color="?attr/colorBackground" />
     </shape>
 </inset>
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index f0c980c..3a28f4d 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -37,6 +37,7 @@
         android:textAppearance="?attr/notificationHeaderTextAppearance"
         android:layout_marginStart="@dimen/notification_header_app_name_margin_start"
         android:layout_marginEnd="@dimen/notification_header_separating_margin"
+        android:visibility="?attr/notificationHeaderAppNameVisibility"
         android:singleLine="true"
         />
     <TextView
diff --git a/core/res/res/layout/notification_template_material_ambient.xml b/core/res/res/layout/notification_template_material_ambient.xml
index ee5c758..865685f 100644
--- a/core/res/res/layout/notification_template_material_ambient.xml
+++ b/core/res/res/layout/notification_template_material_ambient.xml
@@ -23,8 +23,8 @@
     android:paddingStart="@dimen/notification_extra_margin_ambient"
     android:paddingEnd="@dimen/notification_extra_margin_ambient"
     >
-    <include layout="@layout/notification_template_header"
-        android:theme="@style/Theme.Material.Notification.Ambient" />
+    <include layout="@layout/notification_template_ambient_header"
+             android:theme="@style/Theme.Material.Notification.Ambient" />
 
     <LinearLayout
             android:id="@+id/notification_action_list_margin_target"
@@ -53,6 +53,7 @@
                 android:textAppearance="@style/TextAppearance.Material.Notification.Title"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
+                android:gravity="top|center_horizontal"
                 android:singleLine="true"
                 android:ellipsize="marquee"
                 android:fadingEdge="horizontal"
@@ -65,7 +66,7 @@
                 android:textAppearance="@style/TextAppearance.Material.Notification"
                 android:singleLine="false"
                 android:layout_weight="1"
-                android:gravity="top"
+                android:gravity="top|center_horizontal"
                 android:visibility="gone"
                 android:textSize="16sp"
                 android:textColor="#eeffffff"
@@ -75,5 +76,19 @@
             />
         </LinearLayout>
     </LinearLayout>
-    <include layout="@layout/notification_material_action_list" />
+    <FrameLayout android:id="@+id/actions_container"
+                 android:layout_width="match_parent"
+                 android:layout_height="wrap_content"
+                 android:layout_gravity="bottom">
+        <com.android.internal.widget.NotificationActionListLayout
+            android:id="@+id/actions"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/notification_action_list_height"
+            android:paddingEnd="4dp"
+            android:orientation="horizontal"
+            android:gravity="center"
+            android:visibility="gone"
+            android:background="@color/notification_action_list"
+        />
+    </FrameLayout>
 </FrameLayout>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index db4dcd2..0eefec9 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -984,6 +984,8 @@
         <attr name="dialogTitleDecorLayout" format="reference" />
         <!-- Preferred padding for dialog content. -->
         <attr name="dialogPreferredPadding" format="dimension" />
+        <!-- Corner radius of dialogs. -->
+        <attr name="dialogCornerRadius" format="dimension" />
 
         <!-- Theme to use for alert dialogs spawned from this theme. -->
         <attr name="alertDialogTheme" format="reference" />
@@ -8713,6 +8715,14 @@
         <attr name="notificationHeaderStyle" format="reference" />
         <attr name="notificationHeaderTextAppearance" format="reference" />
         <attr name="notificationHeaderIconSize" format="dimension" />
+        <attr name="notificationHeaderAppNameVisibility" format="enum">
+            <!-- Visible on screen; the default value. -->
+            <enum name="visible" value="0" />
+            <!-- Not displayed, but taken into account during layout (space is left for it). -->
+            <enum name="invisible" value="1" />
+            <!-- Completely hidden, as if the view had not been added. -->
+            <enum name="gone" value="2" />
+        </attr>
     </declare-styleable>
 
     <attr name="lockPatternStyle" format="reference" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index bce950d..1c2e5a4 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2524,7 +2524,13 @@
 
     <bool name="config_networkSamplingWakesDevice">true</bool>
 
-    <string-array translatable="false" name="config_cdma_home_system" />
+    <!-- Home (non-roaming) values for CDMA roaming indicator.
+         Carriers can override this table by resource overlay. If not,
+         the default values come from 3GPP2 C.R1001 table
+         8.1-1. Enhanced Roaming Indicator Number Assignments -->
+    <string-array translatable="false" name="config_cdma_home_system">
+        <item>1</item>
+    </string-array>
 
     <!--From SmsMessage-->
     <!--Support decoding the user data payload as pack GSM 8-bit (a GSM alphabet
@@ -3152,4 +3158,7 @@
 
     <!-- Component name of media projection permission dialog -->
     <string name="config_mediaProjectionPermissionDialogComponent" translateable="false">com.android.systemui/com.android.systemui.media.MediaProjectionPermissionActivity</string>
+
+    <!-- Corner radius of system dialogs -->
+    <dimen name="config_dialogCornerRadius">2dp</dimen>
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index dc75ba6..947fcf1 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -624,4 +624,7 @@
     <dimen name="slice_icon_size">24dp</dimen>
     <!-- Standard padding used in a slice view -->
     <dimen name="slice_padding">16dp</dimen>
+
+    <!-- Default dialog corner radius -->
+    <dimen name="dialog_corner_radius">2dp</dimen>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 083bf90..fdd56c4 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2847,6 +2847,7 @@
       <public name="cantSaveState" />
       <public name="ttcIndex" />
       <public name="fontVariationSettings" />
+      <public name="dialogCornerRadius" />
     </public-group>
 
     <public-group type="style" first-id="0x010302e0">
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 470ac52..cddf99a 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -1296,6 +1296,11 @@
         <item name="layout_marginBottom">@dimen/notification_header_margin_bottom</item>
         <item name="paddingStart">@dimen/notification_content_margin_start</item>
         <item name="paddingEnd">16dp</item>
+        <item name="gravity">top</item>
+    </style>
+
+    <style name="Notification.Header.Ambient">
+        <item name="gravity">top|center_horizontal</item>
     </style>
 
 </resources>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index bf0c906..68d5523 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -88,6 +88,7 @@
 
         <!-- Dialog attributes -->
         <item name="dialogTheme">@style/Theme.DeviceDefault.Dialog</item>
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
 
         <!-- AlertDialog attributes -->
         <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
@@ -214,6 +215,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar.  This theme
@@ -223,6 +228,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar and
@@ -234,6 +243,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} that has no title bar and translucent
@@ -244,6 +257,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- DeviceDefault theme for dialog windows and activities. This changes the window to be
@@ -263,6 +280,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a
@@ -272,6 +293,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar -->
@@ -280,6 +305,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width
@@ -289,6 +318,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
@@ -314,6 +347,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- DeviceDefault theme for a window without an action bar that will be displayed either
@@ -324,6 +361,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- DeviceDefault theme for a presentation window on a secondary display. -->
@@ -332,6 +373,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- DeviceDefault theme for panel windows. This removes all extraneous window
@@ -342,6 +387,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
@@ -351,6 +400,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
@@ -360,6 +413,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- DeviceDefault style for input methods, which is used by the
@@ -369,6 +426,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <!-- DeviceDefault style for input methods, which is used by the
@@ -378,11 +439,19 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Material.Dialog.Alert">
         <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault</item>
 
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
+
         <!-- Color palette -->
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
@@ -394,6 +463,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Material.Dialog.NoFrame">
@@ -401,6 +474,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} with a light-colored style -->
@@ -441,6 +518,7 @@
 
         <!-- Dialog attributes -->
         <item name="dialogTheme">@style/Theme.DeviceDefault.Light.Dialog</item>
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
 
         <!-- AlertDialog attributes -->
         <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
@@ -562,6 +640,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar -->
@@ -570,6 +652,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar.
@@ -579,6 +665,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar
@@ -590,6 +680,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light} that has no title bar and translucent
@@ -600,6 +694,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <!-- DeviceDefault light theme for dialog windows and activities. This changes the window to be
@@ -609,6 +707,10 @@
         <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault.Light</item>
         <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item>
 
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
         <item name="buttonBarStyle">@style/DeviceDefault.Light.ButtonBar.AlertDialog</item>
         <item name="borderlessButtonStyle">@style/Widget.DeviceDefault.Light.Button.Borderless.Small</item>
 
@@ -628,6 +730,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
      <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} without an action bar -->
@@ -636,6 +742,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog_NoActionBar} that has a nice minimum
@@ -645,6 +755,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
@@ -680,6 +794,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <!-- DeviceDefault light theme for a window without an action bar that will be displayed either
@@ -690,6 +808,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <!-- DeviceDefault light theme for a presentation window on a secondary display. -->
@@ -698,6 +820,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <!-- DeviceDefault light theme for panel windows. This removes all extraneous window
@@ -708,6 +834,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Material.Light.Dialog.Alert">
@@ -717,6 +847,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <style name="Theme.DeviceDefault.Light.SearchBar" parent="Theme.Material.Light.SearchBar">
@@ -724,6 +858,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <style name="Theme.DeviceDefault.Light.Voice" parent="Theme.Material.Light.Voice">
@@ -731,6 +869,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <!-- DeviceDefault theme for a window that should look like the Settings app.  -->
@@ -750,6 +892,10 @@
         <item name="navigationBarDividerColor">#1f000000</item>
         <item name="navigationBarColor">@android:color/white</item>
         <item name="windowLightNavigationBar">true</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <!-- @hide DeviceDefault theme for a window that should use Settings theme colors
@@ -761,6 +907,7 @@
         <item name="colorSecondary">@color/secondary_device_default_settings_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
         <item name="colorControlNormal">?attr/textColorPrimary</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <style name="Theme.DeviceDefault.QuickSettings.Dialog" parent="Theme.DeviceDefault.Light.Dialog">
@@ -769,6 +916,7 @@
         <item name="colorPrimaryDark">@color/primary_dark_device_default_settings_light</item>
         <item name="colorSecondary">@color/secondary_device_default_settings_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Settings_Dark} with no action bar -->
@@ -778,6 +926,10 @@
         <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
         <item name="colorSecondary">@color/secondary_device_default_settings</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <style name="Theme.DeviceDefault.Settings.Dialog" parent="Theme.Material.Settings.Dialog">
@@ -786,6 +938,10 @@
         <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
         <item name="colorSecondary">@color/secondary_device_default_settings</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <style name="Theme.DeviceDefault.Settings.DialogWhenLarge" parent="Theme.Material.Settings.DialogWhenLarge">
@@ -794,6 +950,10 @@
         <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
         <item name="colorSecondary">@color/secondary_device_default_settings</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <style name="Theme.DeviceDefault.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.Alert">
@@ -802,9 +962,13 @@
         <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
         <item name="colorSecondary">@color/secondary_device_default_settings</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
-    <style name="Theme.DeviceDefault.Settings.Dialog.NoActionBar" parent="Theme.DeviceDefault.Light.Dialog.NoActionBar"/>
+    <style name="Theme.DeviceDefault.Settings.Dialog.NoActionBar" parent="Theme.DeviceDefault.Light.Dialog.NoActionBar" />
 
     <!-- Theme used for the intent picker activity. -->
     <style name="Theme.DeviceDefault.Resolver" parent="Theme.Material.Light">
@@ -820,6 +984,10 @@
         <item name="listPreferredItemPaddingStart">?attr/dialogPreferredPadding</item>
         <item name="listPreferredItemPaddingEnd">?attr/dialogPreferredPadding</item>
 
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
         <!-- Color palette -->
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
@@ -831,7 +999,7 @@
 
     <style name="ThemeOverlay.DeviceDefault" />
 
-    <!-- @hide Theme overlay that inherits from material actionbar,  and use accent color for
+    <!-- @hide Theme overlay that inherits from material actionbar, and use accent color for
              primary text -->
     <style name="ThemeOverlay.DeviceDefault.ActionBar.Accent" parent="ThemeOverlay.Material.ActionBar">
         <item name="textColorPrimary">@color/btn_colored_borderless_text_material</item>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 9bea3ee..c317121 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -186,6 +186,7 @@
         <item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_material</item>
         <item name="dialogTitleDecorLayout">@layout/dialog_title_material</item>
         <item name="dialogPreferredPadding">@dimen/dialog_padding_material</item>
+        <item name="dialogCornerRadius">@dimen/dialog_corner_radius</item>
 
         <!-- AlertDialog attributes -->
         <item name="alertDialogTheme">@style/ThemeOverlay.Material.Dialog.Alert</item>
@@ -554,6 +555,7 @@
         <item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_material</item>
         <item name="dialogTitleDecorLayout">@layout/dialog_title_material</item>
         <item name="dialogPreferredPadding">@dimen/dialog_padding_material</item>
+        <item name="dialogCornerRadius">@dimen/dialog_corner_radius</item>
 
         <!-- AlertDialog attributes -->
         <item name="alertDialogTheme">@style/ThemeOverlay.Material.Dialog.Alert</item>
@@ -1325,12 +1327,15 @@
     <style name="Theme.Material.Notification" parent="">
         <item name="notificationHeaderStyle">@style/Notification.Header</item>
         <item name="notificationHeaderTextAppearance">@style/TextAppearance.Material.Notification.Info</item>
+        <item name="notificationHeaderAppNameVisibility">visible</item>
         <item name="notificationHeaderIconSize">@dimen/notification_header_icon_size</item>
     </style>
 
     <!-- Theme for inflating ambient notification -->
     <style name="Theme.Material.Notification.Ambient">
+        <item name="notificationHeaderStyle">@style/Notification.Header.Ambient</item>
         <item name="notificationHeaderTextAppearance">@style/TextAppearance.Material.Notification.Info.Ambient</item>
+        <item name="notificationHeaderAppNameVisibility">gone</item>
         <item name="notificationHeaderIconSize">@dimen/notification_header_icon_size_ambient</item>
     </style>
 
diff --git a/libs/protoutil/include/android/util/ProtoOutputStream.h b/libs/protoutil/include/android/util/ProtoOutputStream.h
index 2155084..ce41849 100644
--- a/libs/protoutil/include/android/util/ProtoOutputStream.h
+++ b/libs/protoutil/include/android/util/ProtoOutputStream.h
@@ -35,6 +35,10 @@
  */
 const uint64_t FIELD_TYPE_MASK = 0x0ffULL << FIELD_TYPE_SHIFT;
 
+/**
+ * The types are copied from external/protobuf/src/google/protobuf/descriptor.h directly,
+ * so no extra mapping needs to be maintained in this case.
+ */
 const uint64_t FIELD_TYPE_UNKNOWN  = 0;
 const uint64_t FIELD_TYPE_DOUBLE   = 1ULL << FIELD_TYPE_SHIFT;   // double, exactly eight bytes on the wire.
 const uint64_t FIELD_TYPE_FLOAT    = 2ULL << FIELD_TYPE_SHIFT;   // float, exactly four bytes on the wire.
@@ -49,7 +53,7 @@
 const uint64_t FIELD_TYPE_FIXED32  = 7ULL << FIELD_TYPE_SHIFT;   // uint32, exactly four bytes on the wire.
 const uint64_t FIELD_TYPE_BOOL     = 8ULL << FIELD_TYPE_SHIFT;   // bool, varint on the wire.
 const uint64_t FIELD_TYPE_STRING   = 9ULL << FIELD_TYPE_SHIFT;   // UTF-8 text.
-const uint64_t FIELD_TYPE_GROUP    = 10ULL << FIELD_TYPE_SHIFT;  // Tag-delimited message.  Deprecated.
+// const uint64_t FIELD_TYPE_GROUP = 10ULL << FIELD_TYPE_SHIFT;  // Tag-delimited message.  Deprecated.
 const uint64_t FIELD_TYPE_MESSAGE  = 11ULL << FIELD_TYPE_SHIFT;  // Length-delimited message.
 
 const uint64_t FIELD_TYPE_BYTES    = 12ULL << FIELD_TYPE_SHIFT;  // Arbitrary byte array.
@@ -69,7 +73,7 @@
 const uint64_t FIELD_COUNT_UNKNOWN = 0;
 const uint64_t FIELD_COUNT_SINGLE = 1ULL << FIELD_COUNT_SHIFT;
 const uint64_t FIELD_COUNT_REPEATED = 2ULL << FIELD_COUNT_SHIFT;
-const uint64_t FIELD_COUNT_PACKED = 4ULL << FIELD_COUNT_SHIFT;
+const uint64_t FIELD_COUNT_PACKED = 5ULL << FIELD_COUNT_SHIFT;
 
 /**
  * Class to write to a protobuf stream.
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
index 32e6389..c3a36e9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
@@ -28,6 +28,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.graphics.drawable.Drawable;
 import android.os.RemoteException;
@@ -343,7 +344,8 @@
         }
         DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
                 Context.DEVICE_POLICY_SERVICE);
-        if (dpm == null) {
+        PackageManager pm = context.getPackageManager();
+        if (!pm.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN) || dpm == null) {
             return null;
         }
         boolean isAccountTypeDisabled = false;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
index ca366ea..64de635 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
@@ -33,6 +33,7 @@
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.os.UserManager;
 
@@ -56,6 +57,8 @@
     private DevicePolicyManager mDevicePolicyManager;
     @Mock
     private UserManager mUserManager;
+    @Mock
+    private PackageManager mPackageManager;
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private RestrictedLockUtils.Proxy mProxy;
 
@@ -72,11 +75,32 @@
                 .thenReturn(mDevicePolicyManager);
         when(mContext.getSystemService(Context.USER_SERVICE))
                 .thenReturn(mUserManager);
+        when(mContext.getPackageManager())
+                .thenReturn(mPackageManager);
 
         RestrictedLockUtils.sProxy = mProxy;
     }
 
     @Test
+    public void checkIfDevicePolicyServiceDisabled_noEnforceAdminForManagedProfile() {
+        when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(null);
+        final EnforcedAdmin enforcedAdmin = RestrictedLockUtils.checkIfAccountManagementDisabled(
+                mContext, "account_type", mUserId);
+
+        assertThat(enforcedAdmin).isEqualTo(null);
+    }
+
+    @Test
+    public void checkIfDeviceAdminFeatureDisabled_noEnforceAdminForManagedProfile() {
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN))
+                .thenReturn(false);
+        final EnforcedAdmin enforcedAdmin = RestrictedLockUtils.checkIfAccountManagementDisabled(
+                mContext, "account_type", mUserId);
+
+        assertThat(enforcedAdmin).isEqualTo(null);
+    }
+
+    @Test
     public void checkIfKeyguardFeaturesDisabled_noEnforcedAdminForManagedProfile() {
         setUpManagedProfile(mUserId, new ComponentName[] {mAdmin1, mAdmin2});
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java
index 806a073..f92509d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java
@@ -70,21 +70,6 @@
     }
 
     /**
-     * An optimization to preload the raw list of tasks. The raw tasks are saved in least-recent
-     * to most-recent order.
-     *
-     * Note: Do not lock, callers should synchronize on the loader before making this call.
-     */
-    void preloadRawTasks() {
-        int currentUserId = ActivityManagerWrapper.getInstance().getCurrentUserId();
-        mRawTasks = ActivityManagerWrapper.getInstance().getRecentTasks(
-                ActivityManager.getMaxRecentTasksStatic(), currentUserId);
-
-        // Since the raw tasks are given in most-recent to least-recent order, we need to reverse it
-        Collections.reverse(mRawTasks);
-    }
-
-    /**
      * Preloads the list of recent tasks from the system. After this call, the TaskStack will
      * have a list of all the recent tasks with their metadata, not including icons or
      * thumbnails which were not cached and have to be loaded.
@@ -95,11 +80,15 @@
      * Note: Do not lock, since this can be calling back to the loader, which separately also drives
      * this call (callers should synchronize on the loader before making this call).
      */
-    void preloadPlan(RecentsTaskLoader loader, int runningTaskId) {
+    public void preloadPlan(RecentsTaskLoader loader, int runningTaskId, int currentUserId) {
         Resources res = mContext.getResources();
         ArrayList<Task> allTasks = new ArrayList<>();
         if (mRawTasks == null) {
-            preloadRawTasks();
+            mRawTasks = ActivityManagerWrapper.getInstance().getRecentTasks(
+                    ActivityManager.getMaxRecentTasksStatic(), currentUserId);
+
+            // Since the raw tasks are given in most-recent to least-recent order, we need to reverse it
+            Collections.reverse(mRawTasks);
         }
 
         int taskCount = mRawTasks.size();
@@ -160,7 +149,7 @@
      * Note: Do not lock, since this can be calling back to the loader, which separately also drives
      * this call (callers should synchronize on the loader before making this call).
      */
-    void executePlan(Options opts, RecentsTaskLoader loader) {
+    public void executePlan(Options opts, RecentsTaskLoader loader) {
         Resources res = mContext.getResources();
 
         // Iterate through each of the tasks and load them according to the load conditions.
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java
index de4c72c..9a991cf 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java
@@ -147,9 +147,15 @@
 
     /** Preloads recents tasks using the specified plan to store the output. */
     public synchronized void preloadTasks(RecentsTaskLoadPlan plan, int runningTaskId) {
+        preloadTasks(plan, runningTaskId, ActivityManagerWrapper.getInstance().getCurrentUserId());
+    }
+
+    /** Preloads recents tasks using the specified plan to store the output. */
+    public synchronized void preloadTasks(RecentsTaskLoadPlan plan, int runningTaskId,
+            int currentUserId) {
         try {
             Trace.beginSection("preloadPlan");
-            plan.preloadPlan(this, runningTaskId);
+            plan.preloadPlan(this, runningTaskId, currentUserId);
         } finally {
             Trace.endSection();
         }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java
index 9a1ff54..5f3dcd1 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java
@@ -21,7 +21,7 @@
 /**
  * An interface for a task filter to query whether a particular task should show in a stack.
  */
-interface TaskFilter {
+public interface TaskFilter {
     /** Returns whether the filter accepts the specified task */
     boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index);
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 090617d..db1583a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -17,10 +17,17 @@
 package com.android.systemui.shared.system;
 
 import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 
 import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.ActivityManager.RecentTaskInfo;
+import android.app.ActivityOptions;
 import android.app.AppGlobals;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
@@ -32,15 +39,19 @@
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.os.Handler;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.IconDrawableFactory;
 import android.util.Log;
 
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.Task.TaskKey;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.function.Consumer;
 
 public class ActivityManagerWrapper {
 
@@ -77,6 +88,25 @@
     }
 
     /**
+     * @return the top running task (can be {@code null}).
+     */
+    public ActivityManager.RunningTaskInfo getRunningTask() {
+        // Note: The set of running tasks from the system is ordered by recency
+        try {
+            List<ActivityManager.RunningTaskInfo> tasks =
+                    ActivityManager.getService().getFilteredTasks(1,
+                            ACTIVITY_TYPE_RECENTS /* ignoreActivityType */,
+                            WINDOWING_MODE_PINNED /* ignoreWindowingMode */);
+            if (tasks.isEmpty()) {
+                return null;
+            }
+            return tasks.get(0);
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
      * @return a list of the recents tasks.
      */
     public List<RecentTaskInfo> getRecentTasks(int numTasks, int userId) {
@@ -202,6 +232,60 @@
     }
 
     /**
+     * Starts a task from Recents.
+     *
+     * @see {@link #startActivityFromRecents(TaskKey, ActivityOptions, int, int, Consumer, Handler)}
+     */
+    public void startActivityFromRecents(Task.TaskKey taskKey, ActivityOptions options,
+            Consumer<Boolean> resultCallback, Handler resultCallbackHandler) {
+        startActivityFromRecents(taskKey, options, WINDOWING_MODE_UNDEFINED,
+                ACTIVITY_TYPE_UNDEFINED, resultCallback, resultCallbackHandler);
+    }
+
+    /**
+     * Starts a task from Recents.
+     *
+     * @param resultCallback The result success callback
+     * @param resultCallbackHandler The handler to receive the result callback
+     */
+    public void startActivityFromRecents(Task.TaskKey taskKey, ActivityOptions options,
+            int windowingMode, int activityType, Consumer<Boolean> resultCallback,
+            Handler resultCallbackHandler) {
+        if (taskKey.windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+            // We show non-visible docked tasks in Recents, but we always want to launch
+            // them in the fullscreen stack.
+            if (options == null) {
+                options = ActivityOptions.makeBasic();
+            }
+            options.setLaunchWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+        } else if (windowingMode != WINDOWING_MODE_UNDEFINED
+                || activityType != ACTIVITY_TYPE_UNDEFINED) {
+            if (options == null) {
+                options = ActivityOptions.makeBasic();
+            }
+            options.setLaunchWindowingMode(windowingMode);
+            options.setLaunchActivityType(activityType);
+        }
+        final ActivityOptions finalOptions = options;
+
+        // Execute this from another thread such that we can do other things (like caching the
+        // bitmap for the thumbnail) while AM is busy starting our activity.
+        mBackgroundExecutor.submit(() -> {
+            try {
+                ActivityManager.getService().startActivityFromRecents(taskKey.id,
+                        finalOptions == null ? null : finalOptions.toBundle());
+                if (resultCallback != null) {
+                    resultCallbackHandler.post(() -> resultCallback.accept(true));
+                }
+            } catch (Exception e) {
+                if (resultCallback != null) {
+                    resultCallbackHandler.post(() -> resultCallback.accept(false));
+                }
+            }
+        });
+    }
+
+    /**
      * Requests that the system close any open system windows (including other SystemUI).
      */
     public void closeSystemWindows(String reason) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 61c5167..5b62c7d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -411,12 +411,12 @@
         }
 
         int currentUser = sSystemServicesProxy.getCurrentUser();
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
+        ActivityManager.RunningTaskInfo runningTask =
+                ActivityManagerWrapper.getInstance().getRunningTask();
         final int activityType = runningTask != null
                 ? runningTask.configuration.windowConfiguration.getActivityType()
                 : ACTIVITY_TYPE_UNDEFINED;
-        boolean screenPinningActive = ssp.isScreenPinningActive();
+        boolean screenPinningActive = sSystemServicesProxy.isScreenPinningActive();
         boolean isRunningTaskInHomeOrRecentsStack =
                 activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS;
         if (runningTask != null && !isRunningTaskInHomeOrRecentsStack && !screenPinningActive) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 96fae35..0b816b5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -138,8 +138,8 @@
                 }
 
                 // Load the next task only if we aren't svelte
-                SystemServicesProxy ssp = Recents.getSystemServices();
-                ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getRunningTask();
+                ActivityManager.RunningTaskInfo runningTaskInfo =
+                        ActivityManagerWrapper.getInstance().getRunningTask();
                 RecentsTaskLoader loader = Recents.getTaskLoader();
                 RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(mContext);
                 loader.preloadTasks(plan, -1);
@@ -353,7 +353,8 @@
             boolean forceVisible = launchedWhileDockingTask || draggingInRecents;
             MutableBoolean isHomeStackVisible = new MutableBoolean(forceVisible);
             if (forceVisible || !ssp.isRecentsActivityVisible(isHomeStackVisible)) {
-                ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
+                ActivityManager.RunningTaskInfo runningTask =
+                        ActivityManagerWrapper.getInstance().getRunningTask();
                 startRecentsActivity(runningTask, isHomeStackVisible.value || fromHome, animate,
                         growTarget);
             }
@@ -444,7 +445,8 @@
                 }
 
                 // Otherwise, start the recents activity
-                ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
+                ActivityManager.RunningTaskInfo runningTask =
+                        ActivityManagerWrapper.getInstance().getRunningTask();
                 startRecentsActivity(runningTask, isHomeStackVisible.value, true /* animate */,
                         growTarget);
 
@@ -470,7 +472,8 @@
         // don't block the touch feedback on the nav bar button which triggers this.
         mHandler.post(() -> {
             if (!ssp.isRecentsActivityVisible(null)) {
-                ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
+                ActivityManager.RunningTaskInfo runningTask =
+                        ActivityManagerWrapper.getInstance().getRunningTask();
                 if (runningTask == null) {
                     return;
                 }
@@ -524,7 +527,8 @@
         if (focusedStack == null || focusedStack.getTaskCount() == 0) return;
 
         // Return early if there is no running task
-        ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
+        ActivityManager.RunningTaskInfo runningTask =
+                ActivityManagerWrapper.getInstance().getRunningTask();
         if (runningTask == null) return;
 
         // Find the task in the recents list
@@ -561,8 +565,8 @@
         }
 
         // Launch the task
-        ssp.startActivityFromRecents(
-                mContext, toTask.key, toTask.title, launchOpts, null /* resultListener */);
+        ActivityManagerWrapper.getInstance().startActivityFromRecents(toTask.key, launchOpts,
+                null /* resultCallback */, null /* resultCallbackHandler */);
     }
 
     /**
@@ -579,7 +583,8 @@
         if (focusedStack == null || focusedStack.getTaskCount() == 0) return;
 
         // Return early if there is no running task (can't determine affiliated tasks in this case)
-        ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
+        ActivityManager.RunningTaskInfo runningTask =
+                ActivityManagerWrapper.getInstance().getRunningTask();
         final int activityType = runningTask.configuration.windowConfiguration.getActivityType();
         if (runningTask == null) return;
         // Return early if the running task is in the home/recents stack (optimization)
@@ -630,8 +635,8 @@
         MetricsLogger.count(mContext, "overview_affiliated_task_launch", 1);
 
         // Launch the task
-        ssp.startActivityFromRecents(
-                mContext, toTask.key, toTask.title, launchOpts, null /* resultListener */);
+        ActivityManagerWrapper.getInstance().startActivityFromRecents(toTask.key, launchOpts,
+                null /* resultListener */, null /* resultCallbackHandler */);
     }
 
     public void showNextAffiliatedTask() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 14b91f7..a436e17 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -83,6 +83,7 @@
 import com.android.systemui.statusbar.policy.UserInfoController;
 
 import java.util.List;
+import java.util.function.Consumer;
 
 /**
  * Acts as a shim around the real system services that we need to access data from, and provides
@@ -123,7 +124,6 @@
     Paint mBgProtectionPaint;
     Canvas mBgProtectionCanvas;
 
-    private final Handler mHandler = new Handler();
     private final Runnable mGcRunnable = new Runnable() {
         @Override
         public void run() {
@@ -197,24 +197,6 @@
     }
 
     /**
-     * Returns the top running task.
-     */
-    public ActivityManager.RunningTaskInfo getRunningTask() {
-        // Note: The set of running tasks from the system is ordered by recency
-        try {
-            List<ActivityManager.RunningTaskInfo> tasks = mIam.getFilteredTasks(1,
-                    ACTIVITY_TYPE_RECENTS /* ignoreActivityType */,
-                    WINDOWING_MODE_PINNED /* ignoreWindowingMode */);
-            if (tasks.isEmpty()) {
-                return null;
-            }
-            return tasks.get(0);
-        } catch (RemoteException e) {
-            return null;
-        }
-    }
-
-    /**
      * Returns whether the recents activity is currently visible.
      */
     public boolean isRecentsActivityVisible() {
@@ -376,28 +358,6 @@
         }
     }
 
-    /** Removes the task */
-    public void removeTask(final int taskId) {
-        if (mAm == null) return;
-
-        // Remove the task.
-        mUiOffloadThread.submit(() -> {
-            try {
-                mIam.removeTask(taskId);
-            } catch (RemoteException e) {
-                e.printStackTrace();
-            }
-        });
-    }
-
-    public ActivityManager.TaskDescription getTaskDescription(int taskId) {
-        try {
-            return mIam.getTaskDescription(taskId);
-        } catch (RemoteException e) {
-            return null;
-        }
-    }
-
     /**
      * Returns whether the provided {@param userId} represents the system user.
      */
@@ -520,56 +480,6 @@
                 opts != null ? opts.toBundle() : null, UserHandle.CURRENT));
     }
 
-    public void startActivityFromRecents(Context context, Task.TaskKey taskKey, String taskName,
-            ActivityOptions options,
-            @Nullable final StartActivityFromRecentsResultListener resultListener) {
-        startActivityFromRecents(context, taskKey, taskName, options,
-                WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED, resultListener);
-    }
-
-    /** Starts an activity from recents. */
-    public void startActivityFromRecents(Context context, Task.TaskKey taskKey, String taskName,
-            ActivityOptions options, int windowingMode, int activityType,
-            @Nullable final StartActivityFromRecentsResultListener resultListener) {
-        if (mIam == null) {
-            return;
-        }
-        if (taskKey.windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
-            // We show non-visible docked tasks in Recents, but we always want to launch
-            // them in the fullscreen stack.
-            if (options == null) {
-                options = ActivityOptions.makeBasic();
-            }
-            options.setLaunchWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
-        } else if (windowingMode != WINDOWING_MODE_UNDEFINED
-                || activityType != ACTIVITY_TYPE_UNDEFINED) {
-            if (options == null) {
-                options = ActivityOptions.makeBasic();
-            }
-            options.setLaunchWindowingMode(windowingMode);
-            options.setLaunchActivityType(activityType);
-        }
-        final ActivityOptions finalOptions = options;
-
-        // Execute this from another thread such that we can do other things (like caching the
-        // bitmap for the thumbnail) while AM is busy starting our activity.
-        mUiOffloadThread.submit(() -> {
-            try {
-                mIam.startActivityFromRecents(
-                        taskKey.id, finalOptions == null ? null : finalOptions.toBundle());
-                if (resultListener != null) {
-                    mHandler.post(() -> resultListener.onStartActivityResult(true));
-                }
-            } catch (Exception e) {
-                Log.e(TAG, context.getString(
-                        R.string.recents_launch_error_message, taskName), e);
-                if (resultListener != null) {
-                    mHandler.post(() -> resultListener.onStartActivityResult(false));
-                }
-            }
-        });
-    }
-
     /** Starts an in-place animation on the front most application windows. */
     public void startInPlaceAnimationOnFrontMostApplication(ActivityOptions opts) {
         if (mIam == null) return;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index f4973d0..b82f15e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -36,6 +36,7 @@
 import android.os.Handler;
 import android.util.ArraySet;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.util.MathUtils;
 import android.view.AppTransitionAnimationSpec;
 import android.view.LayoutInflater;
@@ -1026,29 +1027,30 @@
     private void startTaskActivity(TaskStack stack, Task task, @Nullable TaskView taskView,
             ActivityOptions opts, AppTransitionAnimationSpecsFuture transitionFuture,
             int windowingMode, int activityType) {
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        ssp.startActivityFromRecents(mContext, task.key, task.title, opts, windowingMode,
-                activityType,
-                succeeded -> {
-                    if (succeeded) {
-                        // Keep track of the index of the task launch
-                        int taskIndexFromFront = 0;
-                        int taskIndex = stack.indexOfStackTask(task);
-                        if (taskIndex > -1) {
-                            taskIndexFromFront = stack.getTaskCount() - taskIndex - 1;
-                        }
-                        EventBus.getDefault().send(new LaunchTaskSucceededEvent(
-                                taskIndexFromFront));
-                    } else {
-                        // Dismiss the task if we fail to launch it
-                        if (taskView != null) {
-                            taskView.dismissTask();
-                        }
+        ActivityManagerWrapper.getInstance().startActivityFromRecents(task.key, opts, windowingMode,
+                activityType, succeeded -> {
+            if (succeeded) {
+                // Keep track of the index of the task launch
+                int taskIndexFromFront = 0;
+                int taskIndex = stack.indexOfStackTask(task);
+                if (taskIndex > -1) {
+                    taskIndexFromFront = stack.getTaskCount() - taskIndex - 1;
+                }
+                EventBus.getDefault().send(new LaunchTaskSucceededEvent(
+                        taskIndexFromFront));
+            } else {
+                Log.e(TAG, mContext.getString(R.string.recents_launch_error_message,
+                        task.title));
 
-                        // Keep track of failed launches
-                        EventBus.getDefault().send(new LaunchTaskFailedEvent());
-                    }
-                });
+                // Dismiss the task if we fail to launch it
+                if (taskView != null) {
+                    taskView.dismissTask();
+                }
+
+                // Keep track of failed launches
+                EventBus.getDefault().send(new LaunchTaskFailedEvent());
+            }
+        }, getHandler());
         if (transitionFuture != null) {
             mHandler.post(transitionFuture::composeSpecsSynchronous);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 7bcef57..1596d12 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -439,7 +439,7 @@
         if (mMinimizedSnapAlgorithm == null) {
             mMinimizedSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(),
                     mDisplayWidth, mDisplayHeight, mDividerSize, isHorizontalDivision(),
-                    mStableInsets, mDockedStackMinimized && mHomeStackResizable);
+                    mStableInsets, mDockSide, mDockedStackMinimized && mHomeStackResizable);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 7022c47..41cae6b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -47,6 +47,7 @@
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
 import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.StatusBarState;
@@ -311,8 +312,8 @@
     private class TaskStackListenerImpl extends SysUiTaskStackChangeListener {
         @Override
         public void onTaskStackChanged() {
-            SystemServicesProxy ssp = Recents.getSystemServices();
-            ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getRunningTask();
+            ActivityManager.RunningTaskInfo runningTaskInfo =
+                    ActivityManagerWrapper.getInstance().getRunningTask();
             if (runningTaskInfo != null && runningTaskInfo.baseActivity != null) {
                 mController.taskChanged(runningTaskInfo.baseActivity.getPackageName(),
                         runningTaskInfo);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index d8a9c12..fa34d4a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -5266,7 +5266,8 @@
     boolean isCameraAllowedByAdmin() {
         if (mDevicePolicyManager.getCameraDisabled(null, mCurrentUserId)) {
             return false;
-        } else if (isKeyguardShowing() && isKeyguardSecure()) {
+        } else if (mStatusBarKeyguardViewManager == null ||
+                (isKeyguardShowing() && isKeyguardSecure())) {
             // Check if the admin has disabled the camera specifically for the keyguard
             return (mDevicePolicyManager.getKeyguardDisabledFeatures(null, mCurrentUserId)
                     & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) == 0;
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 2e0f394..fad6bd1 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -4754,6 +4754,16 @@
     // OS: P
     DIALOG_OEM_LOCK_INFO = 1238;
 
+    // ACTION: Settings > Wi-Fi > Click one network > Auto sign in
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_WIFI_AUTO_SIGN_IN = 1239;
+
+    // Open: Settings > System > About phone > IMEI
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_IMEI_INFO = 1240;
+
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
   }
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 622b8423..e92a564 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -80,6 +80,7 @@
 import android.content.pm.Signature;
 import android.database.ContentObserver;
 import android.net.Uri;
+import android.os.PowerManager.ServiceType;
 import android.os.PowerSaveState;
 import android.os.Binder;
 import android.os.Build;
@@ -126,7 +127,6 @@
 import com.android.server.SystemConfig;
 import com.android.server.SystemService;
 import com.android.server.backup.PackageManagerBackupAgent.Metadata;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
 
 import libcore.io.IoUtils;
 
diff --git a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
index 20f2369..a45a4f0 100644
--- a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
@@ -71,6 +71,7 @@
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
 import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
 import android.os.PowerSaveState;
 import android.os.Process;
 import android.os.RemoteException;
@@ -120,7 +121,6 @@
 import com.android.server.backup.utils.BackupManagerMonitorUtils;
 import com.android.server.backup.utils.BackupObserverUtils;
 import com.android.server.backup.utils.SparseArrayUtils;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
 
 import com.google.android.collect.Sets;
 
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 8b79b9d..0e51fda 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -27,6 +27,7 @@
 import android.hardware.input.InputManager;
 import android.hardware.vibrator.V1_0.Constants.EffectStrength;
 import android.media.AudioManager;
+import android.os.PowerManager.ServiceType;
 import android.os.PowerSaveState;
 import android.os.BatteryStats;
 import android.os.Handler;
@@ -56,7 +57,6 @@
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.util.DumpUtils;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 52f9702..a035bd0 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -21,6 +21,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.net.wifi.WifiActivityEnergyInfo;
+import android.os.PowerManager.ServiceType;
 import android.os.PowerSaveState;
 import android.os.BatteryStats;
 import android.os.BatteryStatsInternal;
@@ -53,7 +54,6 @@
 import com.android.internal.os.RpmStats;
 import com.android.internal.util.DumpUtils;
 import com.android.server.LocalServices;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
 import android.util.StatsLog;
 
 import java.io.File;
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 660659f..beb7486 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -48,6 +48,7 @@
 import android.net.NetworkRequest;
 import android.net.Uri;
 import android.os.AsyncTask;
+import android.os.PowerManager.ServiceType;
 import android.os.PowerSaveState;
 import android.os.BatteryStats;
 import android.os.Binder;
@@ -84,7 +85,6 @@
 import com.android.internal.location.ProviderRequest;
 
 import com.android.server.power.BatterySaverPolicy;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
 
 import libcore.io.IoUtils;
 
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index b4056b3..551cb10 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -142,6 +142,7 @@
 import android.os.MessageQueue.IdleHandler;
 import android.os.PersistableBundle;
 import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
 import android.os.PowerManagerInternal;
 import android.os.PowerSaveState;
 import android.os.Process;
@@ -192,7 +193,6 @@
 import com.android.server.LocalServices;
 import com.android.server.ServiceThread;
 import com.android.server.SystemConfig;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
 
 import libcore.io.IoUtils;
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
index cf9e6f3..781216c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
@@ -59,6 +59,8 @@
         // vendor.
         if ("pm.dexopt.inactive".equals(sysPropName)) {
             sysPropValue = "verify";
+        } else if ("pm.dexopt.shared".equals(sysPropName)) {
+            sysPropValue = "speed";
         } else {
             sysPropValue = SystemProperties.get(sysPropName);
         }
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 1c002aa..25e9239 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -2262,6 +2262,10 @@
 
             final ShortcutUser user = getUserShortcutsLocked(userId);
 
+            if (user.hasHostPackage(packageName)) {
+                return true;
+            }
+
             // Always trust the cached component.
             final ComponentName cached = user.getCachedLauncher();
             if (cached != null) {
@@ -2361,6 +2365,16 @@
         }
     }
 
+    public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName,
+            int userId) {
+        synchronized (mLock) {
+            throwIfUserLockedL(userId);
+
+            final ShortcutUser user = getUserShortcutsLocked(userId);
+            user.setShortcutHostPackage(type, packageName);
+        }
+    }
+
     // === House keeping ===
 
     private void cleanUpPackageForAllLoadedUsers(String packageName, @UserIdInt int packageUserId,
@@ -2697,6 +2711,12 @@
         }
 
         @Override
+        public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName,
+                int userId) {
+            ShortcutService.this.setShortcutHostPackage(type, packageName, userId);
+        }
+
+        @Override
         public boolean requestPinAppWidget(@NonNull String callingPackage,
                 @NonNull AppWidgetProviderInfo appWidget, @Nullable Bundle extras,
                 @Nullable IntentSender resultIntent, int userId) {
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index 48eccd0..1efd765 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -23,6 +23,7 @@
 import android.text.TextUtils;
 import android.text.format.Formatter;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Log;
 import android.util.Slog;
 
@@ -123,6 +124,20 @@
     /** In-memory-cached default launcher. */
     private ComponentName mCachedLauncher;
 
+    /**
+     * Keep track of additional packages that other parts of the system have said are
+     * allowed to access shortcuts.  The key is the part of the system it came from,
+     * the value is the package name that has access.  We don't persist these because
+     * at boot all relevant system services will push this data back to us they do their
+     * normal evaluation of the state of the world.
+     */
+    private final ArrayMap<String, String> mHostPackages = new ArrayMap<>();
+
+    /**
+     * Set of package name values from above.
+     */
+    private final ArraySet<String> mHostPackageSet = new ArraySet<>();
+
     private String mKnownLocales;
 
     private long mLastAppScanTime;
@@ -467,6 +482,23 @@
         return mCachedLauncher;
     }
 
+    public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName) {
+        if (packageName != null) {
+            mHostPackages.put(type, packageName);
+        } else {
+            mHostPackages.remove(type);
+        }
+
+        mHostPackageSet.clear();
+        for (int i = 0; i < mHostPackages.size(); i++) {
+            mHostPackageSet.add(mHostPackages.valueAt(i));
+        }
+    }
+
+    public boolean hasHostPackage(@NonNull String packageName) {
+        return mHostPackageSet.contains(packageName);
+    }
+
     public void resetThrottling() {
         for (int i = mPackages.size() - 1; i >= 0; i--) {
             mPackages.valueAt(i).resetThrottling();
@@ -555,6 +587,18 @@
             pw.print("Last known launcher: ");
             pw.print(mLastKnownLauncher);
             pw.println();
+
+            if (mHostPackages.size() > 0) {
+                pw.print(prefix);
+                pw.println("Host packages:");
+                for (int i = 0; i < mHostPackages.size(); i++) {
+                    pw.print(prefix);
+                    pw.print("  ");
+                    pw.print(mHostPackages.keyAt(i));
+                    pw.print(": ");
+                    pw.println(mHostPackages.valueAt(i));
+                }
+            }
         }
 
         for (int i = 0; i < mLaunchers.size(); i++) {
diff --git a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
index edd2fdb..c6ec287 100644
--- a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
@@ -52,6 +52,7 @@
 import android.widget.FrameLayout;
 
 import com.android.internal.R;
+import com.android.server.vr.VrManagerService;
 
 /**
  *  Helper to manage showing/hiding a confirmation prompt when the navigation bar is hidden
@@ -147,7 +148,6 @@
                     && userSetupComplete
                     && !mVrModeEnabled
                     && !navBarEmpty
-                    && !isLockTaskModeLocked()
                     && !UserManager.isDeviceInDemoMode(mContext)) {
                 mHandler.sendEmptyMessageDelayed(H.SHOW, mShowDelayMs);
             }
@@ -156,20 +156,6 @@
         }
     }
 
-    /**
-     * @return {@code true} if and only if the device is currently in LockTask mode managed by
-     * {@link android.app.admin.DevicePolicyManager}. Note that this differs from the screen pinning
-     * mode which is initiated by the user.
-     */
-    private boolean isLockTaskModeLocked() {
-        try {
-            return ActivityManager.getService().getLockTaskModeState()
-                    == ActivityManager.LOCK_TASK_MODE_LOCKED;
-        } catch (RemoteException e) {
-            return false;
-        }
-    }
-
     public boolean onPowerKeyDown(boolean isScreenOn, long time, boolean inImmersiveMode,
             boolean navBarEmpty) {
         if (!isScreenOn && (time - mPanicTime < mPanicThresholdMs)) {
diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java
index 1781d8c..273b945 100644
--- a/services/core/java/com/android/server/power/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java
@@ -20,6 +20,8 @@
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Handler;
+import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
 import android.provider.Settings;
 import android.util.KeyValueListParser;
 import android.util.Slog;
@@ -34,31 +36,6 @@
  * Class to decide whether to turn on battery saver mode for specific service
  */
 public class BatterySaverPolicy extends ContentObserver {
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({ServiceType.GPS,
-            ServiceType.VIBRATION,
-            ServiceType.ANIMATION,
-            ServiceType.FULL_BACKUP,
-            ServiceType.KEYVALUE_BACKUP,
-            ServiceType.NETWORK_FIREWALL,
-            ServiceType.SCREEN_BRIGHTNESS,
-            ServiceType.SOUND,
-            ServiceType.BATTERY_STATS,
-            ServiceType.DATA_SAVER})
-    public @interface ServiceType {
-        int NULL = 0;
-        int GPS = 1;
-        int VIBRATION = 2;
-        int ANIMATION = 3;
-        int FULL_BACKUP = 4;
-        int KEYVALUE_BACKUP = 5;
-        int NETWORK_FIREWALL = 6;
-        int SCREEN_BRIGHTNESS = 7;
-        int SOUND = 8;
-        int BATTERY_STATS = 9;
-        int DATA_SAVER = 10;
-    }
-
     private static final String TAG = "BatterySaverPolicy";
 
     // Value of batterySaverGpsMode such that GPS isn't affected by battery saver mode.
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 2494bde..8f23cf8 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -43,6 +43,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
 import android.os.PowerManagerInternal;
 import android.os.PowerSaveState;
 import android.os.Process;
@@ -89,7 +90,6 @@
 import com.android.server.am.BatteryStatsService;
 import com.android.server.lights.Light;
 import com.android.server.lights.LightsManager;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileReader;
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index e7e4efc..e8ebbe4 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -166,6 +166,8 @@
     private boolean mUserUnlocked;
     private Vr2dDisplay mVr2dDisplay;
     private boolean mBootsToVr;
+    private boolean mStandby;
+    private boolean mUseStandbyToExitVrMode;
 
     // Handles events from the managed services (e.g. VrListenerService and any bound VR compositor
     // service).
@@ -203,7 +205,10 @@
      *
      */
     private void updateVrModeAllowedLocked() {
-        boolean allowed = mSystemSleepFlags == FLAG_ALL && mUserUnlocked;
+        boolean ignoreSleepFlags = mBootsToVr && mUseStandbyToExitVrMode;
+        boolean disallowedByStandby = mStandby && mUseStandbyToExitVrMode;
+        boolean allowed = (mSystemSleepFlags == FLAG_ALL || ignoreSleepFlags) && mUserUnlocked
+                && !disallowedByStandby;
         if (mVrModeAllowed != allowed) {
             mVrModeAllowed = allowed;
             if (DBG) Slog.d(TAG, "VR mode is " + ((allowed) ? "allowed" : "disallowed"));
@@ -273,6 +278,17 @@
         }
     }
 
+    private void setStandbyEnabled(boolean standby) {
+        synchronized(mLock) {
+            if (!mBootsToVr) {
+                Slog.e(TAG, "Attempting to set standby mode on a non-standalone device");
+                return;
+            }
+            mStandby = standby;
+            updateVrModeAllowedLocked();
+        }
+    }
+
     private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
@@ -587,6 +603,12 @@
         }
 
         @Override
+        public void setStandbyEnabled(boolean standby) {
+            enforceCallerPermissionAnyOf(Manifest.permission.ACCESS_VR_MANAGER);
+            VrManagerService.this.setStandbyEnabled(standby);
+        }
+
+        @Override
         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
 
@@ -733,6 +755,8 @@
         }
 
         mBootsToVr = SystemProperties.getBoolean("ro.boot.vr", false);
+        mUseStandbyToExitVrMode = mBootsToVr
+                && SystemProperties.getBoolean("persist.vr.use_standby_to_exit_vr_mode", false);
         publishLocalService(VrManagerInternal.class, new LocalService());
         publishBinderService(Context.VR_SERVICE, mVrManager.asBinder());
     }
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 0ac2cff..6e89e3e 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -523,7 +523,7 @@
         final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm(
                 mService.mContext.getResources(), displayWidth, displayHeight,
                 dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds,
-                isMinimizedDockAndHomeStackResizable());
+                getDockSide(), isMinimizedDockAndHomeStackResizable());
         final SnapTarget target = algorithm.calculateNonDismissingSnapTarget(dividerPosition);
 
         // Recalculate the bounds based on the position of the target.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index bf5f4bc..b28bb71 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -158,6 +158,7 @@
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
 import android.os.PowerManagerInternal;
 import android.os.PowerSaveState;
 import android.os.RemoteException;
@@ -243,7 +244,6 @@
 import com.android.server.UiThread;
 import com.android.server.Watchdog;
 import com.android.server.input.InputManagerService;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
 import com.android.server.power.ShutdownThread;
 import com.android.server.utils.PriorityDump;
 
diff --git a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
index 69589e7..50ac41c 100644
--- a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
@@ -15,13 +15,12 @@
  */
 package com.android.server.power;
 
+import android.os.PowerManager.ServiceType;
 import android.os.PowerSaveState;
 import android.os.Handler;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
-import com.android.server.power.BatterySaverPolicy.ServiceType;
-
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 4559660..b60d5bf 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -66,7 +66,7 @@
                 .setBrightnessFactor(BRIGHTNESS_FACTOR)
                 .build();
         when(mBatterySaverPolicy.getBatterySaverPolicy(
-                eq(BatterySaverPolicy.ServiceType.SCREEN_BRIGHTNESS), anyBoolean()))
+                eq(PowerManager.ServiceType.SCREEN_BRIGHTNESS), anyBoolean()))
                 .thenReturn(mPowerSaveState);
         mDisplayPowerRequest = new DisplayPowerRequest();
         mService = new PowerManagerService(getContext(), mBatterySaverPolicy);
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index f53eb15..25c54b3 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -36,12 +36,12 @@
 import android.hardware.soundtrigger.SoundTriggerModule;
 import android.os.DeadObjectException;
 import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
 import android.os.RemoteException;
 import android.telephony.PhoneStateListener;
 import android.telephony.TelephonyManager;
 import android.util.Slog;
 import com.android.internal.logging.MetricsLogger;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 1569ac3..44e5314 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -30,6 +30,7 @@
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.content.pm.ShortcutServiceInternal;
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.hardware.soundtrigger.IRecognitionStatusCallback;
@@ -44,6 +45,7 @@
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.Settings;
 import android.service.voice.IVoiceInteractionService;
 import android.service.voice.IVoiceInteractionSession;
@@ -53,6 +55,7 @@
 import android.service.voice.VoiceInteractionSession;
 import android.speech.RecognitionService;
 import android.text.TextUtils;
+import android.util.ArraySet;
 import android.util.Log;
 import android.util.Slog;
 
@@ -63,6 +66,7 @@
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.DumpUtils;
+import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.UiThread;
@@ -84,7 +88,9 @@
     final ContentResolver mResolver;
     final DatabaseHelper mDbHelper;
     final ActivityManagerInternal mAmInternal;
-    final TreeSet<Integer> mLoadedKeyphraseIds;
+    final UserManager mUserManager;
+    final ArraySet<Integer> mLoadedKeyphraseIds = new ArraySet<>();
+    ShortcutServiceInternal mShortcutServiceInternal;
     SoundTriggerInternal mSoundTriggerInternal;
 
     private final RemoteCallbackList<IVoiceInteractionSessionListener>
@@ -96,8 +102,10 @@
         mResolver = context.getContentResolver();
         mDbHelper = new DatabaseHelper(context);
         mServiceStub = new VoiceInteractionManagerServiceStub();
-        mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
-        mLoadedKeyphraseIds = new TreeSet<Integer>();
+        mAmInternal = Preconditions.checkNotNull(
+                LocalServices.getService(ActivityManagerInternal.class));
+        mUserManager = Preconditions.checkNotNull(
+                context.getSystemService(UserManager.class));
 
         PackageManagerInternal packageManagerInternal = LocalServices.getService(
                 PackageManagerInternal.class);
@@ -124,6 +132,8 @@
     @Override
     public void onBootPhase(int phase) {
         if (PHASE_SYSTEM_SERVICES_READY == phase) {
+            mShortcutServiceInternal = Preconditions.checkNotNull(
+                    LocalServices.getService(ShortcutServiceInternal.class));
             mSoundTriggerInternal = LocalServices.getService(SoundTriggerInternal.class);
         } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
             mServiceStub.systemRunning(isSafeMode());
@@ -180,6 +190,7 @@
 
         private boolean mSafeMode;
         private int mCurUser;
+        private boolean mCurUserUnlocked;
         private final boolean mEnableService;
 
         VoiceInteractionManagerServiceStub() {
@@ -381,6 +392,7 @@
         public void switchUser(int userHandle) {
             synchronized (this) {
                 mCurUser = userHandle;
+                mCurUserUnlocked = false;
                 switchImplementationIfNeededLocked(false);
             }
         }
@@ -409,13 +421,24 @@
                     }
                 }
 
+                final boolean hasComponent = serviceComponent != null && serviceInfo != null;
+
+                if (mUserManager.isUserUnlockingOrUnlocked(mCurUser)) {
+                    if (hasComponent) {
+                        mShortcutServiceInternal.setShortcutHostPackage(TAG,
+                                serviceComponent.getPackageName(), mCurUser);
+                    } else {
+                        mShortcutServiceInternal.setShortcutHostPackage(TAG, null, mCurUser);
+                    }
+                }
+
                 if (force || mImpl == null || mImpl.mUser != mCurUser
                         || !mImpl.mComponent.equals(serviceComponent)) {
                     unloadAllKeyphraseModels();
                     if (mImpl != null) {
                         mImpl.shutdownLocked();
                     }
-                    if (serviceComponent != null && serviceInfo != null) {
+                    if (hasComponent) {
                         mImpl = new VoiceInteractionManagerServiceImpl(mContext,
                                 UiThread.getHandler(), this, mCurUser, serviceComponent);
                         mImpl.startLocked();
@@ -953,12 +976,14 @@
         }
 
         private synchronized void unloadAllKeyphraseModels() {
-            for (int keyphraseId : mLoadedKeyphraseIds) {
+            for (int i = 0; i < mLoadedKeyphraseIds.size(); i++) {
                 final long caller = Binder.clearCallingIdentity();
                 try {
-                    int status = mSoundTriggerInternal.unloadKeyphraseModel(keyphraseId);
+                    int status = mSoundTriggerInternal.unloadKeyphraseModel(
+                            mLoadedKeyphraseIds.valueAt(i));
                     if (status != SoundTriggerInternal.STATUS_OK) {
-                        Slog.w(TAG, "Failed to unload keyphrase " + keyphraseId + ":" + status);
+                        Slog.w(TAG, "Failed to unload keyphrase " + mLoadedKeyphraseIds.valueAt(i)
+                                + ":" + status);
                     }
                 } finally {
                     Binder.restoreCallingIdentity(caller);
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
new file mode 100644
index 0000000..e0c9d1c
--- /dev/null
+++ b/tools/aapt2/Android.mk
@@ -0,0 +1,7 @@
+include $(CLEAR_VARS)
+
+.PHONY: aapt2_run_host_unit_tests
+aapt2_run_host_unit_tests: PRIVATE_GTEST_OPTIONS := --gtest_output=xml:$(DIST_DIR)/gtest/aapt2_host_unit_tests_result.xml
+aapt2_run_host_unit_tests: $(HOST_OUT_NATIVE_TESTS)/aapt2_tests/aapt2_tests
+	-$(HOST_OUT_NATIVE_TESTS)/aapt2_tests/aapt2_tests $(PRIVATE_GTEST_OPTIONS) > /dev/null 2>&1
+
diff --git a/tools/aapt2/configuration/ConfigurationParser_test.cpp b/tools/aapt2/configuration/ConfigurationParser_test.cpp
index 3654901..afa155f 100644
--- a/tools/aapt2/configuration/ConfigurationParser_test.cpp
+++ b/tools/aapt2/configuration/ConfigurationParser_test.cpp
@@ -423,11 +423,11 @@
 
 TEST_F(ConfigurationParserTest, AndroidSdkGroupAction_NonNumeric) {
   static constexpr const char* xml = R"xml(
-    <android-sdk-group label="O">
+    <android-sdk-group label="P">
       <android-sdk
           minSdkVersion="M"
-          targetSdkVersion="O"
-          maxSdkVersion="O">
+          targetSdkVersion="P"
+          maxSdkVersion="P">
       </android-sdk>
     </android-sdk-group>)xml";
 
@@ -438,14 +438,14 @@
   ASSERT_TRUE(ok);
 
   ASSERT_EQ(1ul, config.android_sdk_groups.size());
-  ASSERT_EQ(1u, config.android_sdk_groups.count("O"));
+  ASSERT_EQ(1u, config.android_sdk_groups.count("P"));
 
-  auto& out = config.android_sdk_groups["O"];
+  auto& out = config.android_sdk_groups["P"];
 
   AndroidSdk sdk;
   sdk.min_sdk_version = {};  // Only the latest development version is supported.
-  sdk.target_sdk_version = 26;
-  sdk.max_sdk_version = 26;
+  sdk.target_sdk_version = 28;
+  sdk.max_sdk_version = 28;
 
   ASSERT_EQ(sdk, out);
 }
diff --git a/tools/incident_section_gen/main.cpp b/tools/incident_section_gen/main.cpp
index 135df40..674bee1 100644
--- a/tools/incident_section_gen/main.cpp
+++ b/tools/incident_section_gen/main.cpp
@@ -18,6 +18,7 @@
 #include <frameworks/base/core/proto/android/os/incident.pb.h>
 
 #include <map>
+#include <set>
 #include <string>
 
 using namespace android;
@@ -27,6 +28,60 @@
 using namespace google::protobuf::internal;
 using namespace std;
 
+/**
+ * Implementation details:
+ * This binary auto generates .cpp files for incident and incidentd.
+ *
+ * When argument "incident" is specified, it generates incident_section.cpp file.
+ *
+ * When argument "incidentd" is specified, it generates section_list.cpp file.
+ *
+ * In section_list.cpp file, it generates a SECTION_LIST array and a PRIVACY_POLICY_LIST array.
+ * For SECTION_LIST, it generates Section.h classes only for proto fields with section option enabled.
+ * For PRIVACY_POLICY_LIST, it generates Privacy.h classes only for proto fields with privacy option enabled.
+ *
+ * For Privacy struct, it is possible to have self recursion definitions since protobuf is defining "classes"
+ * So the logic to handle it becomes very complicated when Privacy tag of a message contains a list of Privacies
+ * of its sub-messages. The code also handles multiple depth of self recursion fields.
+ *
+ * For example here is a one level self recursion message WindowManager:
+ * message WindowState {
+ *     string state = 1 [(privacy).dest = LOCAL];
+ *     int32  display_id = 2;
+ *     repeated WindowState child_windows = 3;
+ * }
+ *
+ * message WindowManager {
+ *     WindowState my_window = 1;
+ * }
+ *
+ * When generating Privacy options for WindowManager, this tool will generate cpp syntax source code:
+ *
+ * #include "section_list.h"
+ * ...
+ * Privacy WindowState_state { 1, 9, NULL, LOCAL, NULL }; // first two integers are values for field id and proto type.
+ * Privacy WindowState_child_windows { 3, 11, NULL, DEFAULT, NULL }; // reserved for WindowState_LIST
+ * Privacy* WindowState_MSG_[] = {
+ *     &WindowState_state,
+ *     // display id is default, nothing is generated.
+ *     &WindowState_child_windows,
+ *     NULL  // terminator of the array
+ * };
+ * Privacy WindowState_my_window { 1, 11, WindowState_my_window_LIST, DEFAULT, NULL };
+ *
+ * createList() {
+ *    ...
+ *    WindowState_child_windows.children = WindowState_my_window_LIST; // point to its own definition after the list is defined.
+ *    ...
+ * }
+ *
+ * const Privacy** PRIVACY_POLICY_LIST = createList();
+ * const int PRIVACY_POLICY_COUNT = 1;
+ */
+
+// The assignments will be called when constructs PRIVACY_POLICY_LIST, has to be global variable
+vector<string> gSelfRecursionAssignments;
+
 static inline void emptyline() {
     printf("\n");
 }
@@ -38,7 +93,7 @@
     emptyline();
 }
 
-// ================================================================================
+// ======================== incident_sections =============================
 static bool generateIncidentSectionsCpp(Descriptor const* descriptor)
 {
     generateHead("incident_sections");
@@ -73,7 +128,7 @@
     return true;
 }
 
-// ================================================================================
+// ========================= section_list ===================================
 static void splitAndPrint(const string& args) {
     size_t base = 0;
     size_t found;
@@ -88,12 +143,12 @@
     }
 }
 
-static const std::string replaceAll(const string& field_name, const char oldC, const string& newS) {
-    if (field_name.find_first_of(oldC) == field_name.npos) return field_name.c_str();
+static string replaceAll(const string& fieldName, const char oldC, const string& newS) {
+    if (fieldName.find_first_of(oldC) == fieldName.npos) return fieldName.c_str();
     size_t pos = 0, idx = 0;
-    char* res = new char[field_name.size() * newS.size() + 1]; // assign a larger buffer
-    while (pos != field_name.size()) {
-        char cur = field_name[pos++];
+    char* res = new char[fieldName.size() * newS.size() + 1]; // assign a larger buffer
+    while (pos != fieldName.size()) {
+        char cur = fieldName[pos++];
         if (cur != oldC) {
             res[idx++] = cur;
             continue;
@@ -104,92 +159,162 @@
         }
     }
     res[idx] = '\0';
-    std::string result(res);
+    string result(res);
     delete [] res;
     return result;
 }
 
-static inline bool isDefaultDest(const FieldDescriptor* field) {
-    return field->options().GetExtension(privacy).dest() == PrivacyFlags::default_instance().dest();
+static string getFieldName(const FieldDescriptor* field) {
+    return replaceAll(field->full_name(), '.', "__");
 }
 
+static string getMessageTypeName(const Descriptor* descriptor) {
+    return replaceAll(descriptor->full_name(), '.', "_") + "_MSG_";
+}
+
+static inline SectionFlags getSectionFlags(const FieldDescriptor* field) {
+    return field->options().GetExtension(section);
+}
+
+static inline PrivacyFlags getPrivacyFlags(const FieldDescriptor* field) {
+    return field->options().GetExtension(privacy);
+}
+
+static inline bool isDefaultField(const FieldDescriptor* field) {
+    return getPrivacyFlags(field).dest() == PrivacyFlags::default_instance().dest();
+}
+
+static bool isDefaultMessageImpl(const Descriptor* descriptor, set<string>* parents) {
+    int N = descriptor->field_count();
+    parents->insert(descriptor->full_name());
+    for (int i=0; i<N; ++i) {
+        const FieldDescriptor* field = descriptor->field(i);
+        // look at if the current field is default or not, return false immediately
+        if (!isDefaultField(field)) return false;
+
+        switch (field->type()) {
+            case FieldDescriptor::TYPE_MESSAGE:
+                // if self recursion, don't go deep.
+                if (parents->find(field->message_type()->full_name()) != parents->end()) break;
+                // if is a default message, just continue
+                if (isDefaultMessageImpl(field->message_type(), parents)) break;
+                // sub message is not default, so this message is always not default
+                return false;
+            case FieldDescriptor::TYPE_STRING:
+                if (getPrivacyFlags(field).patterns_size() != 0) return false;
+            default:
+                continue;
+        }
+    }
+    parents->erase(descriptor->full_name());
+    return true;
+}
+
+static bool isDefaultMessage(const Descriptor* descriptor) {
+    set<string> parents;
+    return isDefaultMessageImpl(descriptor, &parents);
+}
+
+// This function is called for looking at privacy tags for a message type and recursively its sub-messages
+// It prints out each fields's privacy tags and a List of Privacy of the message itself (don't print default values)
 // Returns false if the descriptor doesn't have any non default privacy flags set, including its submessages
-static bool generatePrivacyFlags(const Descriptor* descriptor, const char* alias, map<string, bool> &msgNames) {
+static bool generatePrivacyFlags(const Descriptor* descriptor, map<string, bool> &msgNames, set<string>* parents) {
     bool hasDefaultFlags[descriptor->field_count()];
+
+    string messageTypeName = getMessageTypeName(descriptor);
+    // if the message is already defined, skip it.
+    if (msgNames.find(messageTypeName) != msgNames.end()) {
+        bool hasDefault = msgNames[messageTypeName];
+        return !hasDefault; // don't generate if it has default privacy.
+    }
+    // insert the message type name so sub-message will figure out if self-recursion occurs
+    parents->insert(messageTypeName);
+
     // iterate though its field and generate sub flags first
     for (int i=0; i<descriptor->field_count(); i++) {
         hasDefaultFlags[i] = true; // set default to true
+
         const FieldDescriptor* field = descriptor->field(i);
-        const std::string field_name_str = replaceAll(field->full_name(), '.', "__");
-        const char* field_name = field_name_str.c_str();
-        // check if the same name is already defined
-        if (msgNames.find(field_name) != msgNames.end()) {
-            hasDefaultFlags[i] = msgNames[field_name];
+        const string fieldName = getFieldName(field);
+        // check if the same field name is already defined.
+        if (msgNames.find(fieldName) != msgNames.end()) {
+            hasDefaultFlags[i] = msgNames[fieldName];
             continue;
         };
 
-        PrivacyFlags p = field->options().GetExtension(privacy);
+        PrivacyFlags p = getPrivacyFlags(field);
+        string fieldMessageName;
         switch (field->type()) {
             case FieldDescriptor::TYPE_MESSAGE:
-                if (generatePrivacyFlags(field->message_type(), field_name, msgNames)) {
-                    printf("Privacy %s { %d, %d, %s_LIST, %d, NULL };\n", field_name, field->number(),
-                            field->type(), field_name, p.dest());
-                } else if (isDefaultDest(field)) {
+                fieldMessageName = getMessageTypeName(field->message_type());
+                if (parents->find(fieldMessageName) != parents->end()) { // Self-Recursion proto definition
+                    if (isDefaultField(field)) {
+                        hasDefaultFlags[i] = isDefaultMessage(field->message_type());
+                    } else {
+                        hasDefaultFlags[i] = false;
+                    }
+                    if (!hasDefaultFlags[i]) {
+                        printf("Privacy %s = { %d, %d, NULL, %d, NULL }; // self recursion field of %s\n",
+                                fieldName.c_str(), field->number(), field->type(), p.dest(), fieldMessageName.c_str());
+                        // generate the assignment and used to construct createList function later on.
+                        gSelfRecursionAssignments.push_back(fieldName + ".children = " + fieldMessageName);
+                    }
+                    break;
+                } else if (generatePrivacyFlags(field->message_type(), msgNames, parents)) {
+                    printf("Privacy %s = { %d, %d, %s, %d, NULL };\n", fieldName.c_str(), field->number(),
+                            field->type(), fieldMessageName.c_str(), p.dest());
+                } else if (isDefaultField(field)) {
                     // don't create a new privacy if the value is default.
                     break;
-                } else{
-                    printf("Privacy %s { %d, %d, NULL, %d, NULL };\n", field_name, field->number(),
+                } else {
+                    printf("Privacy %s = { %d, %d, NULL, %d, NULL };\n", fieldName.c_str(), field->number(),
                             field->type(), p.dest());
                 }
                 hasDefaultFlags[i] = false;
                 break;
             case FieldDescriptor::TYPE_STRING:
-                if (isDefaultDest(field) && p.patterns_size() == 0) break;
+                if (isDefaultField(field) && p.patterns_size() == 0) break;
 
-                printf("const char* %s_patterns[] = {\n", field_name);
+                printf("const char* %s_patterns[] = {\n", fieldName.c_str());
                 for (int i=0; i<p.patterns_size(); i++) {
                     // the generated string need to escape backslash as well, need to dup it here
                     printf("    \"%s\",\n", replaceAll(p.patterns(i), '\\', "\\\\").c_str());
                 }
                 printf("    NULL };\n");
-                printf("Privacy %s { %d, %d, NULL, %d, %s_patterns };\n", field_name, field->number(),
-                        field->type(), p.dest(), field_name);
+                printf("Privacy %s = { %d, %d, NULL, %d, %s_patterns };\n", fieldName.c_str(), field->number(),
+                        field->type(), p.dest(), fieldName.c_str());
                 hasDefaultFlags[i] = false;
                 break;
             default:
-                if (isDefaultDest(field)) break;
-                printf("Privacy %s { %d, %d, NULL, %d, NULL };\n", field_name, field->number(),
+                if (isDefaultField(field)) break;
+                printf("Privacy %s = { %d, %d, NULL, %d, NULL };\n", fieldName.c_str(), field->number(),
                         field->type(), p.dest());
                 hasDefaultFlags[i] = false;
         }
         // add the field name to message map, true means it has default flags
-        msgNames[field_name] = hasDefaultFlags[i];
+        msgNames[fieldName] = hasDefaultFlags[i];
     }
 
     bool allDefaults = true;
     for (int i=0; i<descriptor->field_count(); i++) {
         allDefaults &= hasDefaultFlags[i];
     }
+
+    parents->erase(messageTypeName); // erase the message type name when exit the message.
+    msgNames[messageTypeName] = allDefaults; // store the privacy tags of the message here to avoid overhead.
+
     if (allDefaults) return false;
 
     emptyline();
-
-    bool needConst = strcmp(alias, "PRIVACY_POLICY") == 0;
     int policyCount = 0;
-
-    printf("%sPrivacy* %s_LIST[] = {\n", needConst ? "const " : "", alias);
+    printf("Privacy* %s[] = {\n", messageTypeName.c_str());
     for (int i=0; i<descriptor->field_count(); i++) {
         const FieldDescriptor* field = descriptor->field(i);
         if (hasDefaultFlags[i]) continue;
-        printf("    &%s,\n", replaceAll(field->full_name(), '.', "__").c_str());
+        printf("    &%s,\n", getFieldName(field).c_str());
         policyCount++;
     }
-    if (needConst) {
-        printf("};\n\n");
-        printf("const int PRIVACY_POLICY_COUNT = %d;\n", policyCount);
-    } else {
-        printf("    NULL };\n");
-    }
+    printf("    NULL };\n");
     emptyline();
     return true;
 }
@@ -198,6 +323,8 @@
     generateHead("section_list");
 
     // generates SECTION_LIST
+    printf("// Generate SECTION_LIST.\n\n");
+
     printf("const Section* SECTION_LIST[] = {\n");
     for (int i=0; i<descriptor->field_count(); i++) {
         const FieldDescriptor* field = descriptor->field(i);
@@ -205,7 +332,7 @@
         if (field->type() != FieldDescriptor::TYPE_MESSAGE) {
             continue;
         }
-        const SectionFlags s = field->options().GetExtension(section);
+        const SectionFlags s = getSectionFlags(field);
         switch (s.type()) {
             case SECTION_NONE:
                 continue;
@@ -225,16 +352,73 @@
         }
     }
     printf("    NULL };\n");
+
+    emptyline();
+    printf("// =============================================================================\n");
     emptyline();
 
-    // generates PRIVACY_POLICY
+    // generates PRIVACY_POLICY_LIST
+    printf("// Generate PRIVACY_POLICY_LIST.\n\n");
     map<string, bool> messageNames;
-    if (!generatePrivacyFlags(descriptor, "PRIVACY_POLICY", messageNames)) {
-        // if no privacy options set at all, define an empty list
-        printf("const Privacy* PRIVACY_POLICY_LIST[] = {};\n");
-        printf("const int PRIVACY_POLICY_COUNT = 0;\n");
+    set<string> parents;
+    bool skip[descriptor->field_count()];
+
+    for (int i=0; i<descriptor->field_count(); i++) {
+        const FieldDescriptor* field = descriptor->field(i);
+        const string fieldName = getFieldName(field);
+        PrivacyFlags p = getPrivacyFlags(field);
+
+        skip[i] = true;
+
+        if (field->type() != FieldDescriptor::TYPE_MESSAGE) {
+            continue;
+        }
+        // generate privacy flags for each field.
+        if (generatePrivacyFlags(field->message_type(), messageNames, &parents)) {
+            printf("Privacy %s { %d, %d, %s, %d, NULL };\n", fieldName.c_str(), field->number(),
+                    field->type(), getMessageTypeName(field->message_type()).c_str(), p.dest());
+        } else if (isDefaultField(field)) {
+            continue; // don't create a new privacy if the value is default.
+        } else {
+            printf("Privacy %s { %d, %d, NULL, %d, NULL };\n", fieldName.c_str(), field->number(),
+                    field->type(), p.dest());
+        }
+        skip[i] = false;
     }
 
+    // generate final PRIVACY_POLICY_LIST
+    emptyline();
+    int policyCount = 0;
+    if (gSelfRecursionAssignments.empty()) {
+        printf("Privacy* privacyArray[] = {\n");
+        for (int i=0; i<descriptor->field_count(); i++) {
+            if (skip[i]) continue;
+            printf("    &%s,\n", getFieldName(descriptor->field(i)).c_str());
+            policyCount++;
+        }
+        printf("};\n\n");
+        printf("const Privacy** PRIVACY_POLICY_LIST = const_cast<const Privacy**>(privacyArray);\n\n");
+        printf("const int PRIVACY_POLICY_COUNT = %d;\n", policyCount);
+    } else {
+        for (int i=0; i<descriptor->field_count(); i++) {
+            if (!skip[i]) policyCount++;
+        }
+
+        printf("static const Privacy** createList() {\n");
+        for (size_t i=0; i<gSelfRecursionAssignments.size(); ++i) {
+            printf("    %s;\n", gSelfRecursionAssignments[i].c_str());
+        }
+        printf("    Privacy** privacyArray = (Privacy**)malloc(%d * sizeof(Privacy**));\n", policyCount);
+        policyCount = 0; // reset
+        for (int i=0; i<descriptor->field_count(); i++) {
+            if (skip[i]) continue;
+            printf("    privacyArray[%d] = &%s;\n", policyCount++, getFieldName(descriptor->field(i)).c_str());
+        }
+        printf("    return const_cast<const Privacy**>(privacyArray);\n");
+        printf("}\n\n");
+        printf("const Privacy** PRIVACY_POLICY_LIST = createList();\n\n");
+        printf("const int PRIVACY_POLICY_COUNT = %d;\n", policyCount);
+    }
     return true;
 }
 
diff --git a/tools/streaming_proto/Android.bp b/tools/streaming_proto/Android.bp
index 96e060d..dc5c14e 100644
--- a/tools/streaming_proto/Android.bp
+++ b/tools/streaming_proto/Android.bp
@@ -21,8 +21,11 @@
     name: "protoc-gen-stream-defaults",
     srcs: [
         "Errors.cpp",
+        "stream_proto_utils.cpp",
         "string_utils.cpp",
     ],
+
+    shared_libs: ["libprotoc"],
 }
 
 cc_library {
@@ -52,7 +55,6 @@
     ],
 
     defaults: ["protoc-gen-stream-defaults"],
-    shared_libs: ["libprotoc"],
 }
 
 cc_binary_host {
@@ -62,6 +64,5 @@
     ],
 
     defaults: ["protoc-gen-stream-defaults"],
-    shared_libs: ["libprotoc"],
     static_libs: ["streamingflags"],
 }
diff --git a/tools/streaming_proto/cpp/main.cpp b/tools/streaming_proto/cpp/main.cpp
index dc96d5c..4816984 100644
--- a/tools/streaming_proto/cpp/main.cpp
+++ b/tools/streaming_proto/cpp/main.cpp
@@ -1,108 +1,23 @@
 #include "Errors.h"
+#include "stream_proto_utils.h"
 #include "string_utils.h"
 
 #include <frameworks/base/tools/streaming_proto/stream.pb.h>
 
-#include "google/protobuf/compiler/plugin.pb.h"
-#include "google/protobuf/io/zero_copy_stream_impl.h"
-#include "google/protobuf/text_format.h"
-
 #include <iomanip>
 #include <iostream>
 #include <sstream>
 
 using namespace android::stream_proto;
-using namespace google::protobuf;
-using namespace google::protobuf::compiler;
 using namespace google::protobuf::io;
 using namespace std;
 
-/**
- * Position of the field type in a (long long) fieldId.
- */
-const uint64_t FIELD_TYPE_SHIFT = 32;
-
-//
-// FieldId flags for whether the field is single, repeated or packed.
-// TODO: packed is not supported yet.
-//
-const uint64_t FIELD_COUNT_SHIFT = 40;
-const uint64_t FIELD_COUNT_MASK = 0x0fULL << FIELD_COUNT_SHIFT;
-const uint64_t FIELD_COUNT_UNKNOWN = 0;
-const uint64_t FIELD_COUNT_SINGLE = 1ULL << FIELD_COUNT_SHIFT;
-const uint64_t FIELD_COUNT_REPEATED = 2ULL << FIELD_COUNT_SHIFT;
-const uint64_t FIELD_COUNT_PACKED = 4ULL << FIELD_COUNT_SHIFT;
-
-// Indent
-const string INDENT = "    ";
-
-/**
- * See if this is the file for this request, and not one of the imported ones.
- */
-static bool
-should_generate_for_file(const CodeGeneratorRequest& request, const string& file)
-{
-    const int N = request.file_to_generate_size();
-    for (int i=0; i<N; i++) {
-        if (request.file_to_generate(i) == file) {
-            return true;
-        }
-    }
-    return false;
-}
-
 static string
 make_filename(const FileDescriptorProto& file_descriptor)
 {
     return file_descriptor.name() + ".h";
 }
 
-static string
-get_proto_type(const FieldDescriptorProto& field)
-{
-    switch (field.type()) {
-        case FieldDescriptorProto::TYPE_DOUBLE:
-            return "double";
-        case FieldDescriptorProto::TYPE_FLOAT:
-            return "float";
-        case FieldDescriptorProto::TYPE_INT64:
-            return "int64";
-        case FieldDescriptorProto::TYPE_UINT64:
-            return "uint64";
-        case FieldDescriptorProto::TYPE_INT32:
-            return "int32";
-        case FieldDescriptorProto::TYPE_FIXED64:
-            return "fixed64";
-        case FieldDescriptorProto::TYPE_FIXED32:
-            return "fixed32";
-        case FieldDescriptorProto::TYPE_BOOL:
-            return "bool";
-        case FieldDescriptorProto::TYPE_STRING:
-            return "string";
-        case FieldDescriptorProto::TYPE_GROUP:
-            return "group<unsupported!>";
-        case FieldDescriptorProto::TYPE_MESSAGE:
-            return field.type_name();
-        case FieldDescriptorProto::TYPE_BYTES:
-            return "bytes";
-        case FieldDescriptorProto::TYPE_UINT32:
-            return "uint32";
-        case FieldDescriptorProto::TYPE_ENUM:
-            return field.type_name();
-        case FieldDescriptorProto::TYPE_SFIXED32:
-            return "sfixed32";
-        case FieldDescriptorProto::TYPE_SFIXED64:
-            return "sfixed64";
-        case FieldDescriptorProto::TYPE_SINT32:
-            return "sint32";
-        case FieldDescriptorProto::TYPE_SINT64:
-            return "sint64";
-        default:
-            // won't happen
-            return "void";
-    }
-}
-
 static void
 write_enum(stringstream& text, const EnumDescriptorProto& enu, const string& indent)
 {
@@ -117,27 +32,6 @@
     text << endl;
 }
 
-static uint64_t
-get_field_id(const FieldDescriptorProto& field)
-{
-    // Number
-    uint64_t result = (uint64_t)field.number();
-
-    // Type
-    result |= (uint64_t)field.type() << FIELD_TYPE_SHIFT;
-
-    // Count
-    if (field.options().packed()) {
-        result |= FIELD_COUNT_PACKED;
-    } else if (field.label() == FieldDescriptorProto::LABEL_REPEATED) {
-        result |= FIELD_COUNT_REPEATED;
-    } else {
-        result |= FIELD_COUNT_SINGLE;
-    }
-
-    return result;
-}
-
 static void
 write_field(stringstream& text, const FieldDescriptorProto& field, const string& indent)
 {
diff --git a/tools/streaming_proto/java/main.cpp b/tools/streaming_proto/java/main.cpp
index b7d594b..c9c50a5 100644
--- a/tools/streaming_proto/java/main.cpp
+++ b/tools/streaming_proto/java/main.cpp
@@ -1,11 +1,7 @@
 #include "Errors.h"
-
+#include "stream_proto_utils.h"
 #include "string_utils.h"
 
-#include "google/protobuf/compiler/plugin.pb.h"
-#include "google/protobuf/io/zero_copy_stream_impl.h"
-#include "google/protobuf/text_format.h"
-
 #include <stdio.h>
 #include <iomanip>
 #include <iostream>
@@ -13,51 +9,9 @@
 #include <map>
 
 using namespace android::stream_proto;
-using namespace google::protobuf;
-using namespace google::protobuf::compiler;
 using namespace google::protobuf::io;
 using namespace std;
 
-const int FIELD_TYPE_SHIFT = 32;
-const uint64_t FIELD_TYPE_DOUBLE = 1L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_FLOAT = 2L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_INT32 = 3L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_INT64 = 4L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_UINT32 = 5L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_UINT64 = 6L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_SINT32 = 7L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_SINT64 = 8L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_FIXED32 = 9L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_FIXED64 = 10L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_SFIXED32 = 11L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_SFIXED64 = 12L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_BOOL = 13L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_STRING = 14L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_BYTES = 15L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_ENUM = 16L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_OBJECT = 17L << FIELD_TYPE_SHIFT;
-
-const int FIELD_COUNT_SHIFT = 40;
-const uint64_t FIELD_COUNT_SINGLE = 1L << FIELD_COUNT_SHIFT;
-const uint64_t FIELD_COUNT_REPEATED = 2L << FIELD_COUNT_SHIFT;
-const uint64_t FIELD_COUNT_PACKED = 5L << FIELD_COUNT_SHIFT;
-
-
-/**
- * See if this is the file for this request, and not one of the imported ones.
- */
-static bool
-should_generate_for_file(const CodeGeneratorRequest& request, const string& file)
-{
-    const int N = request.file_to_generate_size();
-    for (int i=0; i<N; i++) {
-        if (request.file_to_generate(i) == file) {
-            return true;
-        }
-    }
-    return false;
-}
-
 /**
  * If the descriptor gives us a class name, use that. Otherwise make one up from
  * the filename of the .proto file.
@@ -112,7 +66,7 @@
 static string
 indent_more(const string& indent)
 {
-    return indent + "    ";
+    return indent + INDENT;
 }
 
 /**
@@ -133,130 +87,6 @@
 }
 
 /**
- * Get the string name for a field.
- */
-static string
-get_proto_type(const FieldDescriptorProto& field)
-{
-    switch (field.type()) {
-        case FieldDescriptorProto::TYPE_DOUBLE:
-            return "double";
-        case FieldDescriptorProto::TYPE_FLOAT:
-            return "float";
-        case FieldDescriptorProto::TYPE_INT64:
-            return "int64";
-        case FieldDescriptorProto::TYPE_UINT64:
-            return "uint64";
-        case FieldDescriptorProto::TYPE_INT32:
-            return "int32";
-        case FieldDescriptorProto::TYPE_FIXED64:
-            return "fixed64";
-        case FieldDescriptorProto::TYPE_FIXED32:
-            return "fixed32";
-        case FieldDescriptorProto::TYPE_BOOL:
-            return "bool";
-        case FieldDescriptorProto::TYPE_STRING:
-            return "string";
-        case FieldDescriptorProto::TYPE_GROUP:
-            return "group<unsupported!>";
-        case FieldDescriptorProto::TYPE_MESSAGE:
-            return field.type_name();
-        case FieldDescriptorProto::TYPE_BYTES:
-            return "bytes";
-        case FieldDescriptorProto::TYPE_UINT32:
-            return "uint32";
-        case FieldDescriptorProto::TYPE_ENUM:
-            return field.type_name();
-        case FieldDescriptorProto::TYPE_SFIXED32:
-            return "sfixed32";
-        case FieldDescriptorProto::TYPE_SFIXED64:
-            return "sfixed64";
-        case FieldDescriptorProto::TYPE_SINT32:
-            return "sint32";
-        case FieldDescriptorProto::TYPE_SINT64:
-            return "sint64";
-        default:
-            // won't happen
-            return "void";
-    }
-}
-
-static uint64_t
-get_field_id(const FieldDescriptorProto& field)
-{
-    // Number
-    uint64_t result = (uint32_t)field.number();
-
-    // Type
-    switch (field.type()) {
-        case FieldDescriptorProto::TYPE_DOUBLE:
-            result |= FIELD_TYPE_DOUBLE;
-            break;
-        case FieldDescriptorProto::TYPE_FLOAT:
-            result |= FIELD_TYPE_FLOAT;
-            break;
-        case FieldDescriptorProto::TYPE_INT64:
-            result |= FIELD_TYPE_INT64;
-            break;
-        case FieldDescriptorProto::TYPE_UINT64:
-            result |= FIELD_TYPE_UINT64;
-            break;
-        case FieldDescriptorProto::TYPE_INT32:
-            result |= FIELD_TYPE_INT32;
-            break;
-        case FieldDescriptorProto::TYPE_FIXED64:
-            result |= FIELD_TYPE_FIXED64;
-            break;
-        case FieldDescriptorProto::TYPE_FIXED32:
-            result |= FIELD_TYPE_FIXED32;
-            break;
-        case FieldDescriptorProto::TYPE_BOOL:
-            result |= FIELD_TYPE_BOOL;
-            break;
-        case FieldDescriptorProto::TYPE_STRING:
-            result |= FIELD_TYPE_STRING;
-            break;
-        case FieldDescriptorProto::TYPE_MESSAGE:
-            result |= FIELD_TYPE_OBJECT;
-            break;
-        case FieldDescriptorProto::TYPE_BYTES:
-            result |= FIELD_TYPE_BYTES;
-            break;
-        case FieldDescriptorProto::TYPE_UINT32:
-            result |= FIELD_TYPE_UINT32;
-            break;
-        case FieldDescriptorProto::TYPE_ENUM:
-            result |= FIELD_TYPE_ENUM;
-            break;
-        case FieldDescriptorProto::TYPE_SFIXED32:
-            result |= FIELD_TYPE_SFIXED32;
-            break;
-        case FieldDescriptorProto::TYPE_SFIXED64:
-            result |= FIELD_TYPE_SFIXED64;
-            break;
-        case FieldDescriptorProto::TYPE_SINT32:
-            result |= FIELD_TYPE_SINT32;
-            break;
-        case FieldDescriptorProto::TYPE_SINT64:
-            result |= FIELD_TYPE_SINT64;
-            break;
-        default:
-            ;
-    }
-
-    // Count
-    if (field.options().packed()) {
-        result |= FIELD_COUNT_PACKED;
-    } else if (field.label() == FieldDescriptorProto::LABEL_REPEATED) {
-        result |= FIELD_COUNT_REPEATED;
-    } else {
-        result |= FIELD_COUNT_SINGLE;
-    }
-
-    return result;
-}
-
-/**
  * Write a field.
  */
 static void
diff --git a/tools/streaming_proto/stream_proto_utils.cpp b/tools/streaming_proto/stream_proto_utils.cpp
new file mode 100644
index 0000000..e8f86bc
--- /dev/null
+++ b/tools/streaming_proto/stream_proto_utils.cpp
@@ -0,0 +1,102 @@
+#include "stream_proto_utils.h"
+
+namespace android {
+namespace stream_proto {
+
+/**
+ * Position of the field type in a (long long) fieldId.
+ */
+const uint64_t FIELD_TYPE_SHIFT = 32;
+
+//
+// FieldId flags for whether the field is single, repeated or packed.
+// TODO: packed is not supported yet.
+//
+const uint64_t FIELD_COUNT_SHIFT = 40;
+const uint64_t FIELD_COUNT_MASK = 0x0fULL << FIELD_COUNT_SHIFT;
+const uint64_t FIELD_COUNT_UNKNOWN = 0;
+const uint64_t FIELD_COUNT_SINGLE = 1ULL << FIELD_COUNT_SHIFT;
+const uint64_t FIELD_COUNT_REPEATED = 2ULL << FIELD_COUNT_SHIFT;
+const uint64_t FIELD_COUNT_PACKED = 5ULL << FIELD_COUNT_SHIFT;
+
+uint64_t
+get_field_id(const FieldDescriptorProto& field)
+{
+    // Number
+    uint64_t result = (uint32_t)field.number();
+
+    // Type
+    result |= (uint64_t)field.type() << FIELD_TYPE_SHIFT;
+
+    // Count
+    if (field.options().packed()) {
+        result |= FIELD_COUNT_PACKED;
+    } else if (field.label() == FieldDescriptorProto::LABEL_REPEATED) {
+        result |= FIELD_COUNT_REPEATED;
+    } else {
+        result |= FIELD_COUNT_SINGLE;
+    }
+
+    return result;
+}
+
+string
+get_proto_type(const FieldDescriptorProto& field)
+{
+    switch (field.type()) {
+        case FieldDescriptorProto::TYPE_DOUBLE:
+            return "double";
+        case FieldDescriptorProto::TYPE_FLOAT:
+            return "float";
+        case FieldDescriptorProto::TYPE_INT64:
+            return "int64";
+        case FieldDescriptorProto::TYPE_UINT64:
+            return "uint64";
+        case FieldDescriptorProto::TYPE_INT32:
+            return "int32";
+        case FieldDescriptorProto::TYPE_FIXED64:
+            return "fixed64";
+        case FieldDescriptorProto::TYPE_FIXED32:
+            return "fixed32";
+        case FieldDescriptorProto::TYPE_BOOL:
+            return "bool";
+        case FieldDescriptorProto::TYPE_STRING:
+            return "string";
+        case FieldDescriptorProto::TYPE_GROUP:
+            return "group<unsupported!>";
+        case FieldDescriptorProto::TYPE_MESSAGE:
+            return field.type_name();
+        case FieldDescriptorProto::TYPE_BYTES:
+            return "bytes";
+        case FieldDescriptorProto::TYPE_UINT32:
+            return "uint32";
+        case FieldDescriptorProto::TYPE_ENUM:
+            return field.type_name();
+        case FieldDescriptorProto::TYPE_SFIXED32:
+            return "sfixed32";
+        case FieldDescriptorProto::TYPE_SFIXED64:
+            return "sfixed64";
+        case FieldDescriptorProto::TYPE_SINT32:
+            return "sint32";
+        case FieldDescriptorProto::TYPE_SINT64:
+            return "sint64";
+        default:
+            // won't happen
+            return "void";
+    }
+}
+
+bool
+should_generate_for_file(const CodeGeneratorRequest& request, const string& file)
+{
+    const int N = request.file_to_generate_size();
+    for (int i=0; i<N; i++) {
+        if (request.file_to_generate(i) == file) {
+            return true;
+        }
+    }
+    return false;
+}
+
+} // stream_proto
+} // android
diff --git a/tools/streaming_proto/stream_proto_utils.h b/tools/streaming_proto/stream_proto_utils.h
new file mode 100644
index 0000000..5297ecc
--- /dev/null
+++ b/tools/streaming_proto/stream_proto_utils.h
@@ -0,0 +1,29 @@
+#include <stdint.h>
+
+#include "google/protobuf/compiler/plugin.pb.h"
+#include "google/protobuf/io/zero_copy_stream_impl.h"
+
+namespace android {
+namespace stream_proto {
+
+using namespace google::protobuf;
+using namespace google::protobuf::compiler;
+using namespace std;
+
+/**
+ * Get encoded field id from a field.
+ */
+uint64_t get_field_id(const FieldDescriptorProto& field);
+
+/**
+ * Get the string name for a field.
+ */
+string get_proto_type(const FieldDescriptorProto& field);
+
+/**
+ * See if this is the file for this request, and not one of the imported ones.
+ */
+bool should_generate_for_file(const CodeGeneratorRequest& request, const string& file);
+
+} // stream_proto
+} // android
diff --git a/tools/streaming_proto/string_utils.h b/tools/streaming_proto/string_utils.h
index 03284d1..d6f195f 100644
--- a/tools/streaming_proto/string_utils.h
+++ b/tools/streaming_proto/string_utils.h
@@ -6,6 +6,9 @@
 
 using namespace std;
 
+// Indent
+const string INDENT = "    ";
+
 /**
  * Capitalizes the string, removes underscores and makes the next letter
  * capitalized, and makes the letter following numbers capitalized.