Merge "Add start margin to preference icon."
diff --git a/Android.mk b/Android.mk
index 7bb6448..aa7caa5 100644
--- a/Android.mk
+++ b/Android.mk
@@ -270,6 +270,7 @@
 	core/java/android/os/IRecoverySystemProgressListener.aidl \
 	core/java/android/os/IRemoteCallback.aidl \
 	core/java/android/os/ISchedulingPolicyService.aidl \
+	core/java/android/os/IStatsCompanionService.aidl \
 	core/java/android/os/IStatsManager.aidl \
 	core/java/android/os/IThermalEventListener.aidl \
 	core/java/android/os/IThermalService.aidl \
diff --git a/api/test-current.txt b/api/test-current.txt
index a54a79a..2d7f67f 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -4052,10 +4052,11 @@
     method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
     method public void requestUsageTimeReport(android.app.PendingIntent);
     method public android.app.ActivityOptions setAppVerificationBundle(android.os.Bundle);
+    method public void setLaunchActivityType(int);
     method public android.app.ActivityOptions setLaunchBounds(android.graphics.Rect);
     method public android.app.ActivityOptions setLaunchDisplayId(int);
-    method public void setLaunchStackId(int);
     method public void setLaunchTaskId(int);
+    method public void setLaunchWindowingMode(int);
     method public void setTaskOverlay(boolean, boolean);
     method public android.os.Bundle toBundle();
     method public void update(android.app.ActivityOptions);
@@ -6244,6 +6245,7 @@
     field public static final int ACTIVITY_TYPE_UNDEFINED = 0; // 0x0
     field public static final int WINDOWING_MODE_FREEFORM = 5; // 0x5
     field public static final int WINDOWING_MODE_FULLSCREEN = 1; // 0x1
+    field public static final int WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY = 4; // 0x4
     field public static final int WINDOWING_MODE_PINNED = 2; // 0x2
     field public static final int WINDOWING_MODE_SPLIT_SCREEN_PRIMARY = 3; // 0x3
     field public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY = 4; // 0x4
diff --git a/cmds/incidentd/tests/EncodedBuffer_test.cpp b/cmds/incidentd/tests/EncodedBuffer_test.cpp
index 98c39bd..37a938a 100644
--- a/cmds/incidentd/tests/EncodedBuffer_test.cpp
+++ b/cmds/incidentd/tests/EncodedBuffer_test.cpp
@@ -42,40 +42,17 @@
 const string FIX32_FIELD_4 = "\x25\xff\xff\xff\xff"; // -1
 const string MESSAGE_FIELD_5 = "\x2a\x10" + VARINT_FIELD_1 + STRING_FIELD_2;
 
-static Privacy* create_privacy(uint32_t field_id, uint8_t type, uint8_t dest) {
-  struct Privacy* p = (struct Privacy*)malloc(sizeof(struct Privacy));
-  p->field_id = field_id;
-  p->type = type;
-  p->children = NULL;
-  p->dest = dest;
-  p->patterns = NULL;
-  return p;
-}
-
-static Privacy* create_message_privacy(uint32_t field_id, Privacy** children)
-{
-  struct Privacy* p = (struct Privacy*)malloc(sizeof(struct Privacy));
-  p->field_id = field_id;
-  p->type = MESSAGE_TYPE;
-  p->children = children;
-  p->dest = EXPLICIT;
-  p->patterns = NULL;
-  return p;
-}
-
-static Privacy* create_string_privacy(uint32_t field_id, uint8_t dest, const char** patterns)
-{
-  struct Privacy* p = (struct Privacy*)malloc(sizeof(struct Privacy));
-  p->field_id = field_id;
-  p->type = STRING_TYPE;
-  p->children = NULL;
-  p->dest = dest;
-  p->patterns = patterns;
-  return p;
-}
-
 class EncodedBufferTest : public Test {
 public:
+    virtual ~EncodedBufferTest() {
+        // Delete in reverse order of construction, to be consistent with
+        // regular allocation/deallocation.
+        while (!privacies.empty()) {
+            delete privacies.back();
+            privacies.pop_back();
+        }
+    }
+
     virtual void SetUp() override {
         ASSERT_NE(tf.fd, -1);
     }
@@ -113,9 +90,48 @@
         assertStrip(dest, expected, create_message_privacy(300, list));
     }
 
+    Privacy* create_privacy(uint32_t field_id, uint8_t type, uint8_t dest) {
+        Privacy* p = new_uninit_privacy();
+        p->field_id = field_id;
+        p->type = type;
+        p->children = NULL;
+        p->dest = dest;
+        p->patterns = NULL;
+        return p;
+    }
+
+    Privacy* create_message_privacy(uint32_t field_id, Privacy** children) {
+        Privacy* p = new_uninit_privacy();
+        p->field_id = field_id;
+        p->type = MESSAGE_TYPE;
+        p->children = children;
+        p->dest = EXPLICIT;
+        p->patterns = NULL;
+        return p;
+    }
+
+    Privacy* create_string_privacy(uint32_t field_id, uint8_t dest, const char** patterns) {
+        Privacy* p = new_uninit_privacy();
+        p->field_id = field_id;
+        p->type = STRING_TYPE;
+        p->children = NULL;
+        p->dest = dest;
+        p->patterns = patterns;
+        return p;
+    }
+
     FdBuffer buffer;
 private:
     TemporaryFile tf;
+    // Littering this code with unique_ptr (or similar) is ugly, so we just
+    // mass-free everything after the test completes.
+    std::vector<Privacy *> privacies;
+
+    Privacy *new_uninit_privacy() {
+        Privacy* p = new Privacy;
+        privacies.push_back(p);
+        return p;
+    }
 };
 
 TEST_F(EncodedBufferTest, NullFieldPolicy) {
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 9c2e63e..6de5303 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -41,7 +41,9 @@
 
 LOCAL_SRC_FILES := \
     ../../core/java/android/os/IStatsManager.aidl \
+    ../../core/java/android/os/IStatsCompanionService.aidl \
     src/StatsService.cpp \
+    src/AnomalyMonitor.cpp \
     src/LogEntryPrinter.cpp \
     src/LogReader.cpp \
     src/main.cpp \
@@ -119,6 +121,7 @@
 LOCAL_SRC_FILES := \
     ../../core/java/android/os/IStatsManager.aidl \
     src/StatsService.cpp \
+    tests/indexed_priority_queue_test.cpp \
     src/LogEntryPrinter.cpp \
     src/LogReader.cpp \
     tests/LogReader_test.cpp \
diff --git a/cmds/statsd/src/AnomalyMonitor.cpp b/cmds/statsd/src/AnomalyMonitor.cpp
new file mode 100644
index 0000000..d73de95
--- /dev/null
+++ b/cmds/statsd/src/AnomalyMonitor.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AnomalyMonitor"
+#define DEBUG true
+
+#include <AnomalyMonitor.h>
+
+#include <binder/IServiceManager.h>
+#include <cutils/log.h>
+
+namespace statsd {
+
+AnomalyMonitor::AnomalyMonitor(uint32_t minDiffToUpdateRegisteredAlarmTimeSec)
+        : mRegisteredAlarmTimeSec(0),
+          mMinUpdateTimeSec(minDiffToUpdateRegisteredAlarmTimeSec) {
+}
+
+AnomalyMonitor::~AnomalyMonitor() {
+}
+
+void AnomalyMonitor::add(sp<const AnomalyAlarm> alarm) {
+    if (alarm == nullptr) {
+        ALOGW("Asked to add a null alarm.");
+        return;
+    }
+    if (alarm->timestampSec < 1) {
+        // forbidden since a timestamp 0 is used to indicate no alarm registered
+        ALOGW("Asked to add a 0-time alarm.");
+        return;
+    }
+    std::lock_guard<std::mutex> lock(mLock);
+    // TODO: Ensure that refractory period is respected.
+    if (DEBUG) ALOGD("Adding alarm with time %u", alarm->timestampSec);
+    mPq.push(alarm);
+    if (mRegisteredAlarmTimeSec < 1 ||
+            alarm->timestampSec + mMinUpdateTimeSec < mRegisteredAlarmTimeSec) {
+        updateRegisteredAlarmTime(alarm->timestampSec);
+    }
+}
+
+void AnomalyMonitor::remove(sp<const AnomalyAlarm> alarm) {
+    if (alarm == nullptr) {
+        ALOGW("Asked to remove a null alarm.");
+        return;
+    }
+    std::lock_guard<std::mutex> lock(mLock);
+    if (DEBUG) ALOGD("Removing alarm with time %u", alarm->timestampSec);
+    mPq.remove(alarm);
+    if (mPq.empty()) {
+        if (DEBUG) ALOGD("Queue is empty. Cancel any alarm.");
+        mRegisteredAlarmTimeSec = 0;
+        // TODO: Make this resistant to doing work when companion is not ready yet
+        sp<IStatsCompanionService> statsCompanionService = getStatsCompanion_l();
+        if (statsCompanionService != nullptr) {
+            statsCompanionService->cancelAnomalyAlarm();
+        }
+        return;
+    }
+    uint32_t soonestAlarmTimeSec = mPq.top()->timestampSec;
+    if (DEBUG) ALOGD("Soonest alarm is %u", soonestAlarmTimeSec);
+    if (soonestAlarmTimeSec > mRegisteredAlarmTimeSec + mMinUpdateTimeSec) {
+        updateRegisteredAlarmTime(soonestAlarmTimeSec);
+    }
+}
+
+void AnomalyMonitor::updateRegisteredAlarmTime(uint32_t timestampSec) {
+    if (DEBUG) ALOGD("Updating reg alarm time to %u", timestampSec);
+    mRegisteredAlarmTimeSec = timestampSec;
+    sp<IStatsCompanionService> statsCompanionService = getStatsCompanion_l();
+    if (statsCompanionService != nullptr) {
+        statsCompanionService->setAnomalyAlarm(secToMs(mRegisteredAlarmTimeSec));
+    }
+}
+
+sp<IStatsCompanionService> AnomalyMonitor::getStatsCompanion_l() {
+    if (mStatsCompanion != nullptr) {
+        return mStatsCompanion;
+    }
+    // Get statscompanion service from service manager
+    const sp<IServiceManager> sm(defaultServiceManager());
+    if (sm != nullptr) {
+        const String16 name("statscompanion");
+        mStatsCompanion =
+                interface_cast<IStatsCompanionService>(sm->checkService(name));
+        if (mStatsCompanion == nullptr) {
+            ALOGW("statscompanion service unavailable!");
+            return nullptr;
+        }
+    }
+    return mStatsCompanion;
+}
+
+int64_t AnomalyMonitor::secToMs(uint32_t timeSec) {
+    return ((int64_t) timeSec) * 1000;
+}
+
+}  // namespace statsd
\ No newline at end of file
diff --git a/cmds/statsd/src/AnomalyMonitor.h b/cmds/statsd/src/AnomalyMonitor.h
new file mode 100644
index 0000000..5418cf0
--- /dev/null
+++ b/cmds/statsd/src/AnomalyMonitor.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANOMALY_MONITOR_H
+#define ANOMALY_MONITOR_H
+
+#include <indexed_priority_queue.h>
+#include <android/os/IStatsCompanionService.h>
+#include <utils/RefBase.h>
+
+#include <queue>
+#include <vector>
+
+using namespace android::os;
+using namespace android;
+
+namespace statsd {
+
+/**
+ * Represents an alarm, associated with some aggregate metric, holding a
+ * projected time at which the metric is expected to exceed its anomaly
+ * threshold.
+ * Timestamps are in seconds since epoch in a uint32, so will fail in year 2106.
+ */
+struct AnomalyAlarm : public RefBase {
+    AnomalyAlarm(uint32_t timestampSec) : timestampSec(timestampSec) {
+    }
+
+    const uint32_t timestampSec;
+
+    /** AnomalyAlarm a is smaller (higher priority) than b if its timestamp is sooner. */
+    struct SmallerTimestamp {
+        bool operator()(sp<const AnomalyAlarm> a, sp<const AnomalyAlarm> b) const {
+            return (a->timestampSec < b->timestampSec);
+        }
+    };
+};
+
+/**
+ * Manages alarms for Anomaly Detection.
+ */
+class AnomalyMonitor {
+ public:
+    /**
+     * @param minDiffToUpdateRegisteredAlarmTimeSec If the soonest alarm differs
+     * from the registered alarm by more than this amount, update the registered
+     * alarm.
+     */
+    AnomalyMonitor(uint32_t minDiffToUpdateRegisteredAlarmTimeSec);
+    ~AnomalyMonitor();
+
+    /**
+     * Adds the given alarm (reference) to the queue.
+     */
+    void add(sp<const AnomalyAlarm> alarm);
+
+    /**
+     * Removes the given alarm (reference) from the queue.
+     * Note that alarm comparison is reference-based; if another alarm exists
+     * with the same timestampSec, that alarm will still remain in the queue.
+     */
+    void remove(sp<const AnomalyAlarm> alarm);
+
+    /**
+     * Returns the projected alarm timestamp that is registered with
+     * StatsCompanionService. This may not be equal to the soonest alarm,
+     * but should be within minDiffToUpdateRegisteredAlarmTimeSec of it.
+     */
+    uint32_t getRegisteredAlarmTimeSec() const {
+        return mRegisteredAlarmTimeSec;
+    }
+
+ private:
+    /** Lock for accessing/writing to mPq. */
+    std::mutex mLock;
+
+    /**
+     * Timestamp (seconds since epoch) of the alarm registered with
+     * StatsCompanionService. This, in general, may not be equal to the soonest
+     * alarm stored in mPq, but should be within minUpdateTimeSec of it.
+     * A value of 0 indicates that no alarm is currently registered.
+     */
+    uint32_t mRegisteredAlarmTimeSec;
+
+    /**
+     * Priority queue of alarms, prioritized by soonest alarm.timestampSec.
+     */
+    indexed_priority_queue<AnomalyAlarm, AnomalyAlarm::SmallerTimestamp> mPq;
+
+    /**
+     * Binder interface for communicating with StatsCompanionService.
+     */
+    sp<IStatsCompanionService> mStatsCompanion;
+
+    /**
+     * Amount by which the soonest projected alarm must differ from
+     * mRegisteredAlarmTimeSec before updateRegisteredAlarmTime is called.
+     */
+    uint32_t mMinUpdateTimeSec;
+
+    /**
+     * Updates the alarm registered with StatsCompanionService to the given time.
+     * Also correspondingly updates mRegisteredAlarmTimeSec.
+     */
+    void updateRegisteredAlarmTime(uint32_t timestampSec);
+
+    /** Returns the StatsCompanionService. */
+    sp<IStatsCompanionService> getStatsCompanion_l();
+
+    /** Converts uint32 timestamp in seconds to a Java long in msec. */
+    int64_t secToMs(uint32_t timeSec);
+};
+
+} // namespace statsd
+
+#endif // ANOMALY_MONITOR_H
\ No newline at end of file
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 24413f6..67f6782 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -162,6 +162,38 @@
 }
 
 Status
+StatsService::informAnomalyAlarmFired()
+{
+    ALOGD("StatsService::informAnomalyAlarmFired was called");
+
+    if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
+        return Status::fromExceptionCode(Status::EX_SECURITY,
+                "Only system uid can call informAnomalyAlarmFired");
+    }
+
+    ALOGD("StatsService::informAnomalyAlarmFired succeeded");
+    // TODO: check through all counters/timers and see if an anomaly has indeed occurred.
+
+    return Status::ok();
+}
+
+Status
+StatsService::informPollAlarmFired()
+{
+    ALOGD("StatsService::informPollAlarmFired was called");
+
+    if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
+        return Status::fromExceptionCode(Status::EX_SECURITY,
+                "Only system uid can call informPollAlarmFired");
+    }
+
+    ALOGD("StatsService::informPollAlarmFired succeeded");
+    // TODO: determine what services to poll and poll (or ask StatsCompanionService to poll) them.
+
+    return Status::ok();
+}
+
+Status
 StatsService::systemRunning()
 {
     if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index ef52b562..2a8c3f6 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -49,6 +49,10 @@
 
     virtual Status systemRunning();
 
+    virtual Status informAnomalyAlarmFired();
+
+    virtual Status informPollAlarmFired();
+
     virtual status_t setProcessor(const sp<StatsLogProcessor>& main_processor);
 
 private:
diff --git a/cmds/statsd/src/indexed_priority_queue.h b/cmds/statsd/src/indexed_priority_queue.h
new file mode 100644
index 0000000..d302f85
--- /dev/null
+++ b/cmds/statsd/src/indexed_priority_queue.h
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STATSD_INDEXED_PRIORITY_QUEUE_H
+#define STATSD_INDEXED_PRIORITY_QUEUE_H
+
+// ALOGE can be called from this file. If header loaded by another class, use their LOG_TAG instead.
+#ifndef LOG_TAG
+#define LOG_TAG "statsd(indexed_priority_queue)"
+#endif //LOG_TAG
+
+#include <cutils/log.h>
+#include <unordered_map>
+#include <utils/RefBase.h>
+#include <vector>
+
+using namespace android;
+
+namespace statsd {
+
+/** Defines a hash function for sp<AA>, returning the hash of the underlying pointer. */
+template <class AA>
+struct SpHash {
+    size_t operator()(const sp<const AA>& k) const {
+        return std::hash<const AA*>()(k.get());
+    }
+};
+
+/**
+ * Min priority queue for generic type AA.
+ * Unlike a regular priority queue, this class is also capable of removing interior elements.
+ * @tparam Comparator must implement [bool operator()(sp<const AA> a, sp<const AA> b)], returning
+ *    whether a should be closer to the top of the queue than b.
+ */
+template <class AA, class Comparator>
+class indexed_priority_queue {
+ public:
+    indexed_priority_queue();
+    /** Adds a into the priority queue. If already present or a==nullptr, does nothing. */
+    void push(sp<const AA> a);
+    /** Removes a from the priority queue. If not present or a==nullptr, does nothing. */
+    void remove(sp<const AA> a);
+    /** Removes all elements. */
+    void clear();
+    /** Returns whether priority queue contains a (not just a copy of a, but a itself). */
+    bool contains(sp<const AA> a) const;
+    /** Returns min element. Returns nullptr iff empty(). */
+    sp<const AA> top() const;
+    /** Returns number of elements in priority queue. */
+    size_t size() const { return pq.size() - 1; } // pq is 1-indexed
+    /** Returns true iff priority queue is empty. */
+    bool empty() const { return size() < 1; }
+
+ private:
+    /** Vector representing a min-heap (1-indexed, with nullptr at 0). */
+    std::vector<sp<const AA>> pq;
+    /** Mapping of each element in pq to its index in pq (i.e. the inverse of a=pq[i]). */
+    std::unordered_map<sp<const AA>, size_t, SpHash<AA>> indices;
+
+    void init();
+    void sift_up(size_t idx);
+    void sift_down(size_t idx);
+    /** Returns whether pq[idx1] is considered higher than pq[idx2], according to Comparator. */
+    bool higher(size_t idx1, size_t idx2) const;
+    void swap_indices(size_t i, size_t j);
+};
+
+// Implementation must be done in this file due to use of template.
+
+template <class AA, class Comparator>
+indexed_priority_queue<AA,Comparator>::indexed_priority_queue() {
+    init();
+}
+
+template <class AA, class Comparator>
+void indexed_priority_queue<AA,Comparator>::push(sp<const AA> a) {
+    if (a == nullptr) return;
+    if (contains(a)) return;
+    pq.push_back(a);
+    size_t idx = size(); // index of last element since 1-indexed
+    indices.insert({a, idx});
+    sift_up(idx); // get the pq back in order
+}
+
+template <class AA, class Comparator>
+void indexed_priority_queue<AA,Comparator>::remove(sp<const AA> a) {
+    if (a == nullptr) return;
+    if (!contains(a)) return;
+    size_t idx = indices[a];
+    if (idx >= pq.size()) {
+        ALOGE("indexed_priority_queue: Invalid index in map of indices.");
+        return;
+    }
+    if (idx == size()) { // if a is the last element, i.e. at index idx == size() == (pq.size()-1)
+        pq.pop_back();
+        indices.erase(a);
+        return;
+    }
+    // move last element (guaranteed not to be at idx) to idx, then delete a
+    sp<const AA> last_a = pq.back();
+    pq[idx] = last_a;
+    pq.pop_back();
+    indices[last_a] = idx;
+    indices.erase(a);
+
+    // get the heap back in order (since the element at idx is not in order)
+    sift_up(idx);
+    sift_down(idx);
+}
+
+template <class AA, class Comparator>
+void indexed_priority_queue<AA,Comparator>::clear() {
+    pq.clear();
+    indices.clear();
+    init();
+}
+
+template <class AA, class Comparator>
+sp<const AA> indexed_priority_queue<AA,Comparator>::top() const {
+    if (empty()) return nullptr;
+    return pq[1];
+}
+
+template <class AA, class Comparator>
+void indexed_priority_queue<AA,Comparator>::init() {
+    pq.push_back(nullptr); // so that pq is 1-indexed.
+    indices.insert({nullptr, 0}); // just to be consistent with pq.
+}
+
+template <class AA, class Comparator>
+void indexed_priority_queue<AA,Comparator>::sift_up(size_t idx) {
+    while (idx > 1) {
+        size_t parent = idx/2;
+        if (higher(idx, parent)) swap_indices(idx, parent);
+        else break;
+        idx = parent;
+    }
+}
+
+template <class AA, class Comparator>
+void indexed_priority_queue<AA,Comparator>::sift_down(size_t idx) {
+    while (2*idx <= size()) {
+        size_t child = 2 * idx;
+        if (child < size() && higher(child+1, child)) child++;
+        if (higher(child, idx)) swap_indices(child, idx);
+        else break;
+        idx = child;
+    }
+}
+
+template <class AA, class Comparator>
+bool indexed_priority_queue<AA,Comparator>::higher(size_t idx1, size_t idx2) const {
+    if (!(0u < idx1 && idx1 < pq.size() && 0u < idx2 && idx2 < pq.size())) {
+        ALOGE("indexed_priority_queue: Attempting to access invalid index");
+        return false; // got to do something.
+    }
+    return Comparator()(pq[idx1], pq[idx2]);
+}
+
+template <class AA, class Comparator>
+bool indexed_priority_queue<AA,Comparator>::contains(sp<const AA> a) const {
+    if (a == nullptr) return false; // publicly, we pretend that nullptr is not actually in pq.
+    return indices.count(a) > 0;
+}
+
+template <class AA, class Comparator>
+void indexed_priority_queue<AA,Comparator>::swap_indices(size_t i, size_t j) {
+    if (!(0u < i && i < pq.size() && 0u < j && j < pq.size())) {
+        ALOGE("indexed_priority_queue: Attempting to swap invalid index");
+        return;
+    }
+    sp<const AA> val_i = pq[i];
+    sp<const AA> val_j = pq[j];
+    pq[i] = val_j;
+    pq[j] = val_i;
+    indices[val_i] = j;
+    indices[val_j] = i;
+}
+
+} // namespace statsd
+
+#endif //STATSD_INDEXED_PRIORITY_QUEUE_H
diff --git a/cmds/statsd/tests/indexed_priority_queue_test.cpp b/cmds/statsd/tests/indexed_priority_queue_test.cpp
new file mode 100644
index 0000000..a679128
--- /dev/null
+++ b/cmds/statsd/tests/indexed_priority_queue_test.cpp
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../src/indexed_priority_queue.h"
+
+#include <gtest/gtest.h>
+
+using namespace statsd;
+
+/** struct for template in indexed_priority_queue */
+struct AATest : public RefBase {
+    AATest(uint32_t val) : val(val) {
+    }
+
+    const int val;
+
+    struct Smaller {
+        bool operator()(const sp<const AATest> a, const sp<const AATest> b) const {
+            return (a->val < b->val);
+        }
+    };
+};
+
+#ifdef __ANDROID__
+TEST(indexed_priority_queue, empty_and_size) {
+    indexed_priority_queue<AATest, AATest::Smaller> ipq;
+    sp<const AATest> aa4 = new AATest{4};
+    sp<const AATest> aa8 = new AATest{8};
+
+    EXPECT_EQ(0u, ipq.size());
+    EXPECT_TRUE(ipq.empty());
+
+    ipq.push(aa4);
+    EXPECT_EQ(1u, ipq.size());
+    EXPECT_FALSE(ipq.empty());
+
+    ipq.push(aa8);
+    EXPECT_EQ(2u, ipq.size());
+    EXPECT_FALSE(ipq.empty());
+
+    ipq.remove(aa4);
+    EXPECT_EQ(1u, ipq.size());
+    EXPECT_FALSE(ipq.empty());
+
+    ipq.remove(aa8);
+    EXPECT_EQ(0u, ipq.size());
+    EXPECT_TRUE(ipq.empty());
+}
+
+TEST(indexed_priority_queue, top) {
+    indexed_priority_queue<AATest, AATest::Smaller> ipq;
+    sp<const AATest> aa2 = new AATest{2};
+    sp<const AATest> aa4 = new AATest{4};
+    sp<const AATest> aa8 = new AATest{8};
+    sp<const AATest> aa12 = new AATest{12};
+    sp<const AATest> aa16 = new AATest{16};
+    sp<const AATest> aa20 = new AATest{20};
+
+    EXPECT_EQ(ipq.top(), nullptr);
+
+    // add 8, 4, 12
+    ipq.push(aa8);
+    EXPECT_EQ(ipq.top(), aa8);
+
+    ipq.push(aa12);
+    EXPECT_EQ(ipq.top(), aa8);
+
+    ipq.push(aa4);
+    EXPECT_EQ(ipq.top(), aa4);
+
+    // remove 12, 4
+    ipq.remove(aa12);
+    EXPECT_EQ(ipq.top(), aa4);
+
+    ipq.remove(aa4);
+    EXPECT_EQ(ipq.top(), aa8);
+
+    // add 16, 2, 20
+    ipq.push(aa16);
+    EXPECT_EQ(ipq.top(), aa8);
+
+    ipq.push(aa2);
+    EXPECT_EQ(ipq.top(), aa2);
+
+    ipq.push(aa20);
+    EXPECT_EQ(ipq.top(), aa2);
+
+    // remove 2, 20, 16, 8
+    ipq.remove(aa2);
+    EXPECT_EQ(ipq.top(), aa8);
+
+    ipq.remove(aa20);
+    EXPECT_EQ(ipq.top(), aa8);
+
+    ipq.remove(aa16);
+    EXPECT_EQ(ipq.top(), aa8);
+
+    ipq.remove(aa8);
+    EXPECT_EQ(ipq.top(), nullptr);
+}
+
+TEST(indexed_priority_queue, push_same_aa) {
+    indexed_priority_queue<AATest, AATest::Smaller> ipq;
+    sp<const AATest> aa4_a = new AATest{4};
+    sp<const AATest> aa4_b = new AATest{4};
+
+    ipq.push(aa4_a);
+    EXPECT_EQ(1u, ipq.size());
+    EXPECT_TRUE(ipq.contains(aa4_a));
+    EXPECT_FALSE(ipq.contains(aa4_b));
+
+    ipq.push(aa4_a);
+    EXPECT_EQ(1u, ipq.size());
+    EXPECT_TRUE(ipq.contains(aa4_a));
+    EXPECT_FALSE(ipq.contains(aa4_b));
+
+    ipq.push(aa4_b);
+    EXPECT_EQ(2u, ipq.size());
+    EXPECT_TRUE(ipq.contains(aa4_a));
+    EXPECT_TRUE(ipq.contains(aa4_b));
+}
+
+
+TEST(indexed_priority_queue, remove_nonexistant) {
+    indexed_priority_queue<AATest, AATest::Smaller> ipq;
+    sp<const AATest> aa4 = new AATest{4};
+    sp<const AATest> aa5 = new AATest{5};
+
+    ipq.push(aa4);
+    ipq.remove(aa5);
+    EXPECT_EQ(1u, ipq.size());
+    EXPECT_TRUE(ipq.contains(aa4));
+    EXPECT_FALSE(ipq.contains(aa5));
+}
+
+TEST(indexed_priority_queue, remove_same_aa) {
+    indexed_priority_queue<AATest, AATest::Smaller> ipq;
+    sp<const AATest> aa4_a = new AATest{4};
+    sp<const AATest> aa4_b = new AATest{4};
+
+    ipq.push(aa4_a);
+    ipq.push(aa4_b);
+    EXPECT_EQ(2u, ipq.size());
+    EXPECT_TRUE(ipq.contains(aa4_a));
+    EXPECT_TRUE(ipq.contains(aa4_b));
+
+    ipq.remove(aa4_b);
+    EXPECT_EQ(1u, ipq.size());
+    EXPECT_TRUE(ipq.contains(aa4_a));
+    EXPECT_FALSE(ipq.contains(aa4_b));
+
+    ipq.remove(aa4_a);
+    EXPECT_EQ(0u, ipq.size());
+    EXPECT_FALSE(ipq.contains(aa4_a));
+    EXPECT_FALSE(ipq.contains(aa4_b));
+}
+
+TEST(indexed_priority_queue, nulls) {
+    indexed_priority_queue<AATest, AATest::Smaller> ipq;
+
+    EXPECT_TRUE(ipq.empty());
+    EXPECT_FALSE(ipq.contains(nullptr));
+
+    ipq.push(nullptr);
+    EXPECT_TRUE(ipq.empty());
+    EXPECT_FALSE(ipq.contains(nullptr));
+
+    ipq.remove(nullptr);
+    EXPECT_TRUE(ipq.empty());
+    EXPECT_FALSE(ipq.contains(nullptr));
+}
+
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/config/compiled-classes-phone b/config/compiled-classes-phone
index c829728..c1cbb64 100644
--- a/config/compiled-classes-phone
+++ b/config/compiled-classes-phone
@@ -5243,7 +5243,6 @@
 com.android.internal.app.IVoiceInteractor$Stub
 com.android.internal.app.NightDisplayController
 com.android.internal.app.NightDisplayController$Callback
-com.android.internal.app.NightDisplayController$LocalTime
 com.android.internal.app.ProcessMap
 com.android.internal.app.ResolverActivity
 com.android.internal.app.ToolbarActionBar
diff --git a/config/preloaded-classes b/config/preloaded-classes
index cb3cbe1..2844efb3 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -2786,7 +2786,6 @@
 com.android.internal.app.IVoiceInteractor
 com.android.internal.app.IVoiceInteractor$Stub
 com.android.internal.app.NightDisplayController
-com.android.internal.app.NightDisplayController$1
 com.android.internal.appwidget.IAppWidgetService
 com.android.internal.appwidget.IAppWidgetService$Stub
 com.android.internal.appwidget.IAppWidgetService$Stub$Proxy
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
index bf9bd79..a3b3a9f 100644
--- a/core/java/android/accounts/AbstractAccountAuthenticator.java
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -175,6 +175,9 @@
                 }
                 if (result != null) {
                     response.onResult(result);
+                } else {
+                    response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
+                            "null bundle returned");
                 }
             } catch (Exception e) {
                 handleException(response, "addAccount", accountType, e);
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index dd6ad55..bd9c9fa 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -2321,6 +2321,10 @@
         private class Response extends IAccountManagerResponse.Stub {
             @Override
             public void onResult(Bundle bundle) {
+                if (bundle == null) {
+                    onError(ERROR_CODE_INVALID_RESPONSE, "null bundle returned");
+                    return;
+                }
                 Intent intent = bundle.getParcelable(KEY_INTENT);
                 if (intent != null && mActivity != null) {
                     // since the user provided an Activity we will silently start intents
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index a866503..78d05f5 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -770,21 +770,6 @@
         }
 
         /**
-         * Returns true if animation specs should be constructed for app transition that moves
-         * the task to the specified stack.
-         * @hide
-         */
-        public static boolean useAnimationSpecForAppTransition(int stackId) {
-            // TODO: INVALID_STACK_ID is also animated because we don't persist stack id's across
-            // reboots.
-            return stackId == FREEFORM_WORKSPACE_STACK_ID
-                    || stackId == FULLSCREEN_WORKSPACE_STACK_ID
-                    || stackId == ASSISTANT_STACK_ID
-                    || stackId == DOCKED_STACK_ID
-                    || stackId == INVALID_STACK_ID;
-        }
-
-        /**
          * Returns true if activities from stasks in the given {@param stackId} are allowed to
          * enter picture-in-picture.
          * @hide
@@ -885,6 +870,18 @@
             return windowingMode;
         }
 
+        /** Returns the stack id for the input windowing mode.
+         * @hide */
+        // TODO: To be removed once we are not using stack id for stuff...
+        public static int getStackIdForWindowingMode(int windowingMode) {
+            switch (windowingMode) {
+                case WINDOWING_MODE_PINNED: return PINNED_STACK_ID;
+                case WINDOWING_MODE_FREEFORM: return FREEFORM_WORKSPACE_STACK_ID;
+                case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: return DOCKED_STACK_ID;
+                default: return INVALID_STACK_ID;
+            }
+        }
+
         /** Returns the activity type that should be used for this input stack id.
          * @hide */
         // TODO: To be removed once we are not using stack id for stuff...
@@ -905,6 +902,18 @@
             }
             return activityType;
         }
+
+        /** Returns the stack id for the input activity type.
+         * @hide */
+        // TODO: To be removed once we are not using stack id for stuff...
+        public static int getStackIdForActivityType(int activityType) {
+            switch (activityType) {
+                case ACTIVITY_TYPE_HOME: return HOME_STACK_ID;
+                case ACTIVITY_TYPE_RECENTS: return RECENTS_STACK_ID;
+                case ACTIVITY_TYPE_ASSISTANT: return ASSISTANT_STACK_ID;
+                default: return INVALID_STACK_ID;
+            }
+        }
     }
 
     /**
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 0bffc9e..a68c3a5 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -18,6 +18,8 @@
 
 import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.view.Display.INVALID_DISPLAY;
 
 import android.annotation.Nullable;
@@ -164,10 +166,16 @@
     private static final String KEY_LAUNCH_DISPLAY_ID = "android.activity.launchDisplayId";
 
     /**
-     * The stack id the activity should be launched into.
+     * The windowing mode the activity should be launched into.
      * @hide
      */
-    private static final String KEY_LAUNCH_STACK_ID = "android.activity.launchStackId";
+    private static final String KEY_LAUNCH_WINDOWING_MODE = "android.activity.windowingMode";
+
+    /**
+     * The activity type the activity should be launched as.
+     * @hide
+     */
+    private static final String KEY_LAUNCH_ACTIVITY_TYPE = "android.activity.activityType";
 
     /**
      * The task id the activity should be launched into.
@@ -272,7 +280,10 @@
     private int mExitCoordinatorIndex;
     private PendingIntent mUsageTimeReport;
     private int mLaunchDisplayId = INVALID_DISPLAY;
-    private int mLaunchStackId = INVALID_STACK_ID;
+    @WindowConfiguration.WindowingMode
+    private int mLaunchWindowingMode = WINDOWING_MODE_UNDEFINED;
+    @WindowConfiguration.ActivityType
+    private int mLaunchActivityType = ACTIVITY_TYPE_UNDEFINED;
     private int mLaunchTaskId = -1;
     private int mDockCreateMode = DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
     private boolean mDisallowEnterPictureInPictureWhileLaunching;
@@ -860,7 +871,8 @@
                 break;
         }
         mLaunchDisplayId = opts.getInt(KEY_LAUNCH_DISPLAY_ID, INVALID_DISPLAY);
-        mLaunchStackId = opts.getInt(KEY_LAUNCH_STACK_ID, INVALID_STACK_ID);
+        mLaunchWindowingMode = opts.getInt(KEY_LAUNCH_WINDOWING_MODE, WINDOWING_MODE_UNDEFINED);
+        mLaunchActivityType = opts.getInt(KEY_LAUNCH_ACTIVITY_TYPE, ACTIVITY_TYPE_UNDEFINED);
         mLaunchTaskId = opts.getInt(KEY_LAUNCH_TASK_ID, -1);
         mTaskOverlay = opts.getBoolean(KEY_TASK_OVERLAY, false);
         mTaskOverlayCanResume = opts.getBoolean(KEY_TASK_OVERLAY_CAN_RESUME, false);
@@ -1070,14 +1082,34 @@
     }
 
     /** @hide */
-    public int getLaunchStackId() {
-        return mLaunchStackId;
+    public int getLaunchWindowingMode() {
+        return mLaunchWindowingMode;
+    }
+
+    /**
+     * Sets the windowing mode the activity should launch into. If the input windowing mode is
+     * {@link android.app.WindowConfiguration#WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} and the device
+     * isn't currently in split-screen windowing mode, then the activity will be launched in
+     * {@link android.app.WindowConfiguration#WINDOWING_MODE_FULLSCREEN} windowing mode. For clarity
+     * on this you can use
+     * {@link android.app.WindowConfiguration#WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY}
+     *
+     * @hide
+     */
+    @TestApi
+    public void setLaunchWindowingMode(int windowingMode) {
+        mLaunchWindowingMode = windowingMode;
+    }
+
+    /** @hide */
+    public int getLaunchActivityType() {
+        return mLaunchActivityType;
     }
 
     /** @hide */
     @TestApi
-    public void setLaunchStackId(int launchStackId) {
-        mLaunchStackId = launchStackId;
+    public void setLaunchActivityType(int activityType) {
+        mLaunchActivityType = activityType;
     }
 
     /**
@@ -1291,7 +1323,8 @@
                 break;
         }
         b.putInt(KEY_LAUNCH_DISPLAY_ID, mLaunchDisplayId);
-        b.putInt(KEY_LAUNCH_STACK_ID, mLaunchStackId);
+        b.putInt(KEY_LAUNCH_WINDOWING_MODE, mLaunchWindowingMode);
+        b.putInt(KEY_LAUNCH_ACTIVITY_TYPE, mLaunchActivityType);
         b.putInt(KEY_LAUNCH_TASK_ID, mLaunchTaskId);
         b.putBoolean(KEY_TASK_OVERLAY, mTaskOverlay);
         b.putBoolean(KEY_TASK_OVERLAY_CAN_RESUME, mTaskOverlayCanResume);
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 0ceb288..eccb264 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -307,7 +307,15 @@
     boolean shouldUpRecreateTask(in IBinder token, in String destAffinity);
     boolean navigateUpTo(in IBinder token, in Intent target, int resultCode,
             in Intent resultData);
-    void setLockScreenShown(boolean showing);
+    /**
+     * Informs ActivityManagerService that the keyguard is showing.
+     *
+     * @param showing True if the keyguard is showing, false otherwise.
+     * @param secondaryDisplayShowing The displayId of the secondary display on which the keyguard
+     *        is showing, or INVALID_DISPLAY if there is no such display. Only meaningful if
+     *        showing is true.
+     */
+    void setLockScreenShown(boolean showing, int secondaryDisplayShowing);
     boolean finishActivityAffinity(in IBinder token);
     // This is not public because you need to be very careful in how you
     // manage your activity to make sure it is always the uid you expect.
@@ -545,11 +553,6 @@
      */
     void resizePinnedStack(in Rect pinnedBounds, in Rect tempPinnedTaskBounds);
     boolean isVrModePackageEnabled(in ComponentName packageName);
-    /**
-     * Moves all tasks from the docked stack in the fullscreen stack and puts the top task of the
-     * fullscreen stack into the docked stack.
-     */
-    void swapDockedAndFullscreenStack();
     void notifyLockedProfile(int userId);
     void startConfirmDeviceCredentialIntent(in Intent intent, in Bundle options);
     void sendIdleJobTrigger();
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index 07eb5de..0cb3804 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -63,8 +63,21 @@
     /**
      * The containers adjacent to the {@link #WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} container in
      * split-screen mode.
+     * NOTE: Containers launched with the windowing mode with APIs like
+     * {@link ActivityOptions#setLaunchWindowingMode(int)} will be launched in
+     * {@link #WINDOWING_MODE_FULLSCREEN} if the display isn't currently in split-screen windowing
+     * mode
+     * @see #WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY
      */
     public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY = 4;
+    /**
+     * Alias for {@link #WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} that makes it clear that the usage
+     * points for APIs like {@link ActivityOptions#setLaunchWindowingMode(int)} that the container
+     * will launch into fullscreen or split-screen secondary depending on if the device is currently
+     * in fullscreen mode or split-screen mode.
+     */
+    public static final int WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY =
+            WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
     /** Can be freely resized within its parent container. */
     public static final int WINDOWING_MODE_FREEFORM = 5;
 
@@ -75,6 +88,7 @@
             WINDOWING_MODE_PINNED,
             WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
             WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
+            WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY,
             WINDOWING_MODE_FREEFORM,
     })
     public @interface WindowingMode {}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 2d8249a..03e4dfe 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2991,6 +2991,7 @@
             //@hide: CONTEXTHUB_SERVICE,
             SYSTEM_HEALTH_SERVICE,
             //@hide: INCIDENT_SERVICE,
+            //@hide: STATS_COMPANION_SERVICE,
             COMPANION_DEVICE_SERVICE
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -4020,6 +4021,12 @@
     public static final String INCIDENT_SERVICE = "incident";
 
     /**
+     * Service to assist statsd in obtaining general stats.
+     * @hide
+     */
+    public static final String STATS_COMPANION_SERVICE = "statscompanion";
+
+    /**
      * Use with {@link #getSystemService} to retrieve a {@link
      * android.content.om.OverlayManager} for managing overlay packages.
      *
diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.java b/core/java/android/hardware/location/NanoAppInstanceInfo.java
index ac6d83f..2623830 100644
--- a/core/java/android/hardware/location/NanoAppInstanceInfo.java
+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.java
@@ -287,8 +287,10 @@
         mPublisher = in.readString();
         mName = in.readString();
 
+        mHandle = in.readInt();
         mAppId = in.readLong();
         mAppVersion = in.readInt();
+        mContexthubId = in.readInt();
         mNeededReadMemBytes = in.readInt();
         mNeededWriteMemBytes = in.readInt();
         mNeededExecMemBytes = in.readInt();
@@ -309,6 +311,8 @@
     public void writeToParcel(Parcel out, int flags) {
         out.writeString(mPublisher);
         out.writeString(mName);
+
+        out.writeInt(mHandle);
         out.writeLong(mAppId);
         out.writeInt(mAppVersion);
         out.writeInt(mContexthubId);
diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl
new file mode 100644
index 0000000..b17d2f1b
--- /dev/null
+++ b/core/java/android/os/IStatsCompanionService.aidl
@@ -0,0 +1,46 @@
+/*
+ * 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.os;
+
+/**
+  * Binder interface to communicate with the Java-based statistics service helper.
+  * {@hide}
+  */
+oneway interface IStatsCompanionService {
+    /**
+    * Register an alarm for anomaly detection to fire at the given timestamp (ms since epoch).
+    * If anomaly alarm had already been registered, it will be replaced with the new timestamp.
+    * Uses AlarmManager.set API, so  if the timestamp is in the past, alarm fires immediately, and
+    * alarm is inexact.
+    */
+    void setAnomalyAlarm(long timestampMs);
+
+    /** Cancel any anomaly detection alarm. */
+    void cancelAnomalyAlarm();
+
+    /**
+      * Register a repeating alarm for polling to fire at the given timestamp and every
+      * intervalMs thereafter (in ms since epoch).
+      * If polling alarm had already been registered, it will be replaced by new one.
+      * Uses AlarmManager.setRepeating API, so if the timestamp is in past, alarm fires immediately,
+      * and alarm is inexact.
+      */
+    void setPollingAlarms(long timestampMs, long intervalMs);
+
+    /** Cancel any repeating polling alarm. */
+    void cancelPollingAlarms();
+}
diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl
index 9b5139d..b73ca20 100644
--- a/core/java/android/os/IStatsManager.aidl
+++ b/core/java/android/os/IStatsManager.aidl
@@ -17,12 +17,23 @@
 package android.os;
 
 /**
-  * Binder interface to communicate with the statistics collection service.
+  * Binder interface to communicate with the statistics management service.
   * {@hide}
   */
 oneway interface IStatsManager {
     /**
-     * Tell the incident daemon that the android system server is up and running.
+     * Tell the stats daemon that the android system server is up and running.
      */
     void systemRunning();
+
+    /**
+     * Tells statsd that an anomaly may have occurred, so statsd can check whether this is so and
+     * act accordingly.
+     */
+    void informAnomalyAlarmFired();
+
+    /** Tells statsd that it is time to poll some stats. Statsd will be responsible for determing
+     * what stats to poll and initiating the polling.
+     */
+    void informPollAlarmFired();
 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 40ced6c..a5c55ba 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6966,8 +6966,9 @@
         public static final String NIGHT_DISPLAY_CUSTOM_END_TIME = "night_display_custom_end_time";
 
         /**
-         * Time in milliseconds (since epoch) when Night display was last activated. Use to decide
-         * whether to apply the current activated state after a reboot or user change.
+         * A String representing the LocalDateTime when Night display was last activated. Use to
+         * decide whether to apply the current activated state after a reboot or user change. In
+         * legacy cases, this is represented by the time in milliseconds (since epoch).
          * @hide
          */
         public static final String NIGHT_DISPLAY_LAST_ACTIVATED_TIME =
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 27eeb2e..f888ba2 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -37,7 +37,6 @@
 import android.service.autofill.FillEventHistory;
 import android.util.ArrayMap;
 import android.util.ArraySet;
-import android.util.DebugUtils;
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.View;
@@ -202,9 +201,12 @@
      * Initial state of the autofill context, set when there is no session (i.e., when
      * {@link #mSessionId} is {@link #NO_SESSION}).
      *
+     * <p>In this state, app callbacks (such as {@link #notifyViewEntered(View)}) are notified to
+     * the server.
+     *
      * @hide
      */
-    public static final int STATE_UNKNOWN = 1;
+    public static final int STATE_UNKNOWN = 0;
 
     /**
      * State where the autofill context hasn't been {@link #commit() finished} nor
@@ -212,7 +214,18 @@
      *
      * @hide
      */
-    public static final int STATE_ACTIVE = 2;
+    public static final int STATE_ACTIVE = 1;
+
+    /**
+     * State where the autofill context was finished by the server because the autofill
+     * service could not autofill the page.
+     *
+     * <p>In this state, most apps callback (such as {@link #notifyViewEntered(View)}) are ignored,
+     * exception {@link #requestAutofill(View)} (and {@link #requestAutofill(View, int, Rect)}).
+     *
+     * @hide
+     */
+    public static final int STATE_FINISHED = 2;
 
     /**
      * State where the autofill context has been {@link #commit() finished} but the server still has
@@ -220,7 +233,7 @@
      *
      * @hide
      */
-    public static final int STATE_SHOWING_SAVE_UI = 4;
+    public static final int STATE_SHOWING_SAVE_UI = 3;
 
     /**
      * Makes an authentication id from a request id and a dataset id.
@@ -559,6 +572,14 @@
         }
         AutofillCallback callback = null;
         synchronized (mLock) {
+            if (isFinishedLocked() && (flags & FLAG_MANUAL_REQUEST) == 0) {
+                if (sVerbose) {
+                    Log.v(TAG, "notifyViewEntered(flags=" + flags + ", view=" + view
+                            + "): ignored on state " + getStateAsStringLocked());
+                }
+                return;
+            }
+
             ensureServiceClientAddedIfNeededLocked();
 
             if (!mEnabled) {
@@ -682,6 +703,14 @@
         }
         AutofillCallback callback = null;
         synchronized (mLock) {
+            if (isFinishedLocked() && (flags & FLAG_MANUAL_REQUEST) == 0) {
+                if (sVerbose) {
+                    Log.v(TAG, "notifyViewEntered(flags=" + flags + ", view=" + view
+                            + ", virtualId=" + virtualId
+                            + "): ignored on state " + getStateAsStringLocked());
+                }
+                return;
+            }
             ensureServiceClientAddedIfNeededLocked();
 
             if (!mEnabled) {
@@ -765,6 +794,10 @@
             }
 
             if (!mEnabled || !isActiveLocked()) {
+                if (sVerbose && mEnabled) {
+                    Log.v(TAG, "notifyValueChanged(" + view + "): ignoring on state "
+                            + getStateAsStringLocked());
+                }
                 return;
             }
 
@@ -950,10 +983,13 @@
             @NonNull AutofillValue value, int flags) {
         if (sVerbose) {
             Log.v(TAG, "startSessionLocked(): id=" + id + ", bounds=" + bounds + ", value=" + value
-                    + ", flags=" + flags + ", state=" + mState);
+                    + ", flags=" + flags + ", state=" + getStateAsStringLocked());
         }
-        if (mState != STATE_UNKNOWN) {
-            if (sDebug) Log.d(TAG, "not starting session for " + id + " on state " + mState);
+        if (mState != STATE_UNKNOWN && (flags & FLAG_MANUAL_REQUEST) == 0) {
+            if (sVerbose) {
+                Log.v(TAG, "not automatically starting session for " + id
+                        + " on state " + getStateAsStringLocked());
+            }
             return;
         }
         try {
@@ -973,7 +1009,7 @@
     }
 
     private void finishSessionLocked() {
-        if (sVerbose) Log.v(TAG, "finishSessionLocked(): " + mState);
+        if (sVerbose) Log.v(TAG, "finishSessionLocked(): " + getStateAsStringLocked());
 
         if (!isActiveLocked()) return;
 
@@ -987,7 +1023,7 @@
     }
 
     private void cancelSessionLocked() {
-        if (sVerbose) Log.v(TAG, "cancelSessionLocked(): " + mState);
+        if (sVerbose) Log.v(TAG, "cancelSessionLocked(): " + getStateAsStringLocked());
 
         if (!isActiveLocked()) return;
 
@@ -1306,6 +1342,14 @@
         }
     }
 
+    private void setSessionFinished() {
+        if (sVerbose) Log.v(TAG, "setSessionFinished()");
+        synchronized (mLock) {
+            resetSessionLocked();
+            mState = STATE_FINISHED;
+        }
+    }
+
     private void requestHideFillUi(AutofillId id) {
         final View anchor = findView(id);
         if (sVerbose) Log.v(TAG, "requestHideFillUi(" + id + "): anchor = " + anchor);
@@ -1341,7 +1385,11 @@
         }
     }
 
-    private void notifyNoFillUi(int sessionId, AutofillId id) {
+    private void notifyNoFillUi(int sessionId, AutofillId id, boolean sessionFinished) {
+        if (sVerbose) {
+            Log.v(TAG, "notifyNoFillUi(): sessionId=" + sessionId + ", autofillId=" + id
+                    + ", finished=" + sessionFinished);
+        }
         final View anchor = findView(id);
         if (anchor == null) {
             return;
@@ -1361,7 +1409,11 @@
             } else {
                 callback.onAutofillEvent(anchor, AutofillCallback.EVENT_INPUT_UNAVAILABLE);
             }
+        }
 
+        if (sessionFinished) {
+            // Callback call was "hijacked" to also update the session state.
+            setSessionFinished();
         }
     }
 
@@ -1434,8 +1486,7 @@
         pw.print(outerPrefix); pw.println("AutofillManager:");
         final String pfx = outerPrefix + "  ";
         pw.print(pfx); pw.print("sessionId: "); pw.println(mSessionId);
-        pw.print(pfx); pw.print("state: "); pw.println(
-                DebugUtils.flagsToString(AutofillManager.class, "STATE_", mState));
+        pw.print(pfx); pw.print("state: "); pw.println(getStateAsStringLocked());
         pw.print(pfx); pw.print("enabled: "); pw.println(mEnabled);
         pw.print(pfx); pw.print("hasService: "); pw.println(mService != null);
         pw.print(pfx); pw.print("hasCallback: "); pw.println(mCallback != null);
@@ -1452,10 +1503,29 @@
         pw.print(pfx); pw.print("fillable ids: "); pw.println(mFillableIds);
     }
 
+    private String getStateAsStringLocked() {
+        switch (mState) {
+            case STATE_UNKNOWN:
+                return "STATE_UNKNOWN";
+            case STATE_ACTIVE:
+                return "STATE_ACTIVE";
+            case STATE_FINISHED:
+                return "STATE_FINISHED";
+            case STATE_SHOWING_SAVE_UI:
+                return "STATE_SHOWING_SAVE_UI";
+            default:
+                return "INVALID:" + mState;
+        }
+    }
+
     private boolean isActiveLocked() {
         return mState == STATE_ACTIVE;
     }
 
+    private boolean isFinishedLocked() {
+        return mState == STATE_FINISHED;
+    }
+
     private void post(Runnable runnable) {
         final AutofillClient client = getClientLocked();
         if (client == null) {
@@ -1787,10 +1857,10 @@
         }
 
         @Override
-        public void notifyNoFillUi(int sessionId, AutofillId id) {
+        public void notifyNoFillUi(int sessionId, AutofillId id, boolean sessionFinished) {
             final AutofillManager afm = mAfm.get();
             if (afm != null) {
-                afm.post(() -> afm.notifyNoFillUi(sessionId, id));
+                afm.post(() -> afm.notifyNoFillUi(sessionId, id, sessionFinished));
             }
         }
 
@@ -1823,7 +1893,15 @@
         public void setSaveUiState(int sessionId, boolean shown) {
             final AutofillManager afm = mAfm.get();
             if (afm != null) {
-                afm.post(() ->afm.setSaveUiState(sessionId, shown));
+                afm.post(() -> afm.setSaveUiState(sessionId, shown));
+            }
+        }
+
+        @Override
+        public void setSessionFinished() {
+            final AutofillManager afm = mAfm.get();
+            if (afm != null) {
+                afm.post(() -> afm.setSessionFinished());
             }
         }
     }
diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
index 0eae858..db6855a 100644
--- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
@@ -67,9 +67,9 @@
     void requestHideFillUi(int sessionId, in AutofillId id);
 
     /**
-     * Notifies no fill UI will be shown.
+     * Notifies no fill UI will be shown, and also mark the state as finished if necessary.
      */
-    void notifyNoFillUi(int sessionId, in AutofillId id);
+    void notifyNoFillUi(int sessionId, in AutofillId id, boolean sessionFinished);
 
     /**
      * Starts the provided intent sender.
@@ -80,4 +80,10 @@
      * Sets the state of the Autofill Save UI for a given session.
      */
    void setSaveUiState(int sessionId, boolean shown);
+
+   /**
+     * Marks the state of the session as finished (because the AutofillService returned a null
+     * FillResponse).
+     */
+   void setSessionFinished();
 }
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 7c4154f..994512f 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -463,7 +463,7 @@
      */
     public static int onWebViewProviderChanged(PackageInfo packageInfo) {
         String[] nativeLibs = null;
-        String originalSourceDir = packageInfo.applicationInfo.sourceDir;
+        ApplicationInfo originalAppInfo = new ApplicationInfo(packageInfo.applicationInfo);
         try {
             fixupStubApplicationInfo(packageInfo.applicationInfo,
                                      AppGlobals.getInitialApplication().getPackageManager());
@@ -474,7 +474,7 @@
             Log.e(LOGTAG, "error preparing webview native library", t);
         }
 
-        WebViewZygote.onWebViewProviderChanged(packageInfo, originalSourceDir);
+        WebViewZygote.onWebViewProviderChanged(packageInfo, originalAppInfo);
 
         return prepareWebViewInSystemServer(nativeLibs);
     }
diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java
index 6e65c7a..db60ad8 100644
--- a/core/java/android/webkit/WebViewZygote.java
+++ b/core/java/android/webkit/WebViewZygote.java
@@ -17,6 +17,7 @@
 package android.webkit;
 
 import android.app.LoadedApk;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.os.Build;
 import android.os.SystemService;
@@ -67,11 +68,11 @@
     private static PackageInfo sPackage;
 
     /**
-     * Cache key for the selected WebView package's classloader. This is set from
+     * Original ApplicationInfo for the selected WebView package before stub fixup. This is set from
      * #onWebViewProviderChanged().
      */
     @GuardedBy("sLock")
-    private static String sPackageCacheKey;
+    private static ApplicationInfo sPackageOriginalAppInfo;
 
     /**
      * Flag for whether multi-process WebView is enabled. If this is {@code false}, the zygote
@@ -125,10 +126,11 @@
         }
     }
 
-    public static void onWebViewProviderChanged(PackageInfo packageInfo, String cacheKey) {
+    public static void onWebViewProviderChanged(PackageInfo packageInfo,
+                                                ApplicationInfo originalAppInfo) {
         synchronized (sLock) {
             sPackage = packageInfo;
-            sPackageCacheKey = cacheKey;
+            sPackageOriginalAppInfo = originalAppInfo;
 
             // If multi-process is not enabled, then do not start the zygote service.
             if (!sMultiprocessEnabled) {
@@ -217,10 +219,17 @@
             final String zip = (zipPaths.size() == 1) ? zipPaths.get(0) :
                     TextUtils.join(File.pathSeparator, zipPaths);
 
+            // In the case where the ApplicationInfo has been modified by the stub WebView,
+            // we need to use the original ApplicationInfo to determine what the original classpath
+            // would have been to use as a cache key.
+            LoadedApk.makePaths(null, false, sPackageOriginalAppInfo, zipPaths, null);
+            final String cacheKey = (zipPaths.size() == 1) ? zipPaths.get(0) :
+                    TextUtils.join(File.pathSeparator, zipPaths);
+
             ZygoteProcess.waitForConnectionToZygote(WEBVIEW_ZYGOTE_SOCKET);
 
             Log.d(LOGTAG, "Preloading package " + zip + " " + librarySearchPath);
-            sZygote.preloadPackageForAbi(zip, librarySearchPath, sPackageCacheKey,
+            sZygote.preloadPackageForAbi(zip, librarySearchPath, cacheKey,
                                          Build.SUPPORTED_ABIS[0]);
         } catch (Exception e) {
             Log.e(LOGTAG, "Error connecting to " + serviceName, e);
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index bc85fad..7903d6f 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -16,9 +16,10 @@
 
 package android.widget;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+
 import android.annotation.ColorInt;
 import android.annotation.DimenRes;
-import android.app.ActivityManager.StackId;
 import android.app.ActivityOptions;
 import android.app.ActivityThread;
 import android.app.Application;
@@ -324,11 +325,11 @@
 
         public boolean onClickHandler(View view, PendingIntent pendingIntent,
                 Intent fillInIntent) {
-            return onClickHandler(view, pendingIntent, fillInIntent, StackId.INVALID_STACK_ID);
+            return onClickHandler(view, pendingIntent, fillInIntent, WINDOWING_MODE_UNDEFINED);
         }
 
         public boolean onClickHandler(View view, PendingIntent pendingIntent,
-                Intent fillInIntent, int launchStackId) {
+                Intent fillInIntent, int windowingMode) {
             try {
                 // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
                 Context context = view.getContext();
@@ -339,8 +340,8 @@
                     opts = ActivityOptions.makeBasic();
                 }
 
-                if (launchStackId != StackId.INVALID_STACK_ID) {
-                    opts.setLaunchStackId(launchStackId);
+                if (windowingMode != WINDOWING_MODE_UNDEFINED) {
+                    opts.setLaunchWindowingMode(windowingMode);
                 }
                 context.startIntentSender(
                         pendingIntent.getIntentSender(), fillInIntent,
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index efcc3a2..2de5527 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -5549,7 +5549,7 @@
     public final void setHint(CharSequence hint) {
         setHintInternal(hint);
 
-        if (isInputMethodTarget()) {
+        if (mEditor != null && isInputMethodTarget()) {
             mEditor.reportExtractedText();
         }
     }
diff --git a/core/java/com/android/internal/app/NightDisplayController.java b/core/java/com/android/internal/app/NightDisplayController.java
index 860c5c4..7a1383c 100644
--- a/core/java/com/android/internal/app/NightDisplayController.java
+++ b/core/java/com/android/internal/app/NightDisplayController.java
@@ -32,8 +32,12 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.Calendar;
-import java.util.Locale;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeParseException;
 
 /**
  * Controller for managing Night display settings.
@@ -116,8 +120,9 @@
      */
     public boolean setActivated(boolean activated) {
         if (isActivated() != activated) {
-            Secure.putLongForUser(mContext.getContentResolver(),
-                    Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, System.currentTimeMillis(),
+            Secure.putStringForUser(mContext.getContentResolver(),
+                    Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
+                    LocalDateTime.now().toString(),
                     mUserId);
         }
         return Secure.putIntForUser(mContext.getContentResolver(),
@@ -128,17 +133,22 @@
      * Returns the time when Night display's activation state last changed, or {@code null} if it
      * has never been changed.
      */
-    public Calendar getLastActivatedTime() {
+    public LocalDateTime getLastActivatedTime() {
         final ContentResolver cr = mContext.getContentResolver();
-        final long lastActivatedTimeMillis = Secure.getLongForUser(
-                cr, Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, -1, mUserId);
-        if (lastActivatedTimeMillis < 0) {
-            return null;
+        final String lastActivatedTime = Secure.getStringForUser(
+                cr, Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, mUserId);
+        if (lastActivatedTime != null) {
+            try {
+                return LocalDateTime.parse(lastActivatedTime);
+            } catch (DateTimeParseException ignored) {}
+            // Uses the old epoch time.
+            try {
+                return LocalDateTime.ofInstant(
+                    Instant.ofEpochMilli(Long.parseLong(lastActivatedTime)),
+                    ZoneId.systemDefault());
+            } catch (DateTimeException|NumberFormatException ignored) {}
         }
-
-        final Calendar lastActivatedTime = Calendar.getInstance();
-        lastActivatedTime.setTimeInMillis(lastActivatedTimeMillis);
-        return lastActivatedTime;
+        return null;
     }
 
     /**
@@ -183,8 +193,10 @@
         }
 
         if (getAutoMode() != autoMode) {
-            Secure.putLongForUser(mContext.getContentResolver(),
-                    Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, -1L, mUserId);
+            Secure.putStringForUser(mContext.getContentResolver(),
+                    Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
+                    null,
+                    mUserId);
         }
         return Secure.putIntForUser(mContext.getContentResolver(),
                 Secure.NIGHT_DISPLAY_AUTO_MODE, autoMode, mUserId);
@@ -206,7 +218,7 @@
                     R.integer.config_defaultNightDisplayCustomStartTime);
         }
 
-        return LocalTime.valueOf(startTimeValue);
+        return LocalTime.ofSecondOfDay(startTimeValue / 1000);
     }
 
     /**
@@ -221,7 +233,7 @@
             throw new IllegalArgumentException("startTime cannot be null");
         }
         return Secure.putIntForUser(mContext.getContentResolver(),
-                Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, startTime.toMillis(), mUserId);
+                Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, startTime.toSecondOfDay() * 1000, mUserId);
     }
 
     /**
@@ -240,7 +252,7 @@
                     R.integer.config_defaultNightDisplayCustomEndTime);
         }
 
-        return LocalTime.valueOf(endTimeValue);
+        return LocalTime.ofSecondOfDay(endTimeValue / 1000);
     }
 
     /**
@@ -255,7 +267,7 @@
             throw new IllegalArgumentException("endTime cannot be null");
         }
         return Secure.putIntForUser(mContext.getContentResolver(),
-                Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, endTime.toMillis(), mUserId);
+                Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, endTime.toSecondOfDay() * 1000, mUserId);
     }
 
     /**
@@ -379,106 +391,6 @@
     }
 
     /**
-     * A time without a time-zone or date.
-     */
-    public static class LocalTime {
-
-        /**
-         * The hour of the day from 0 - 23.
-         */
-        public final int hourOfDay;
-        /**
-         * The minute within the hour from 0 - 59.
-         */
-        public final int minute;
-
-        public LocalTime(int hourOfDay, int minute) {
-            if (hourOfDay < 0 || hourOfDay > 23) {
-                throw new IllegalArgumentException("Invalid hourOfDay: " + hourOfDay);
-            } else if (minute < 0 || minute > 59) {
-                throw new IllegalArgumentException("Invalid minute: " + minute);
-            }
-
-            this.hourOfDay = hourOfDay;
-            this.minute = minute;
-        }
-
-        /**
-         * Returns the first date time corresponding to this local time that occurs before the
-         * provided date time.
-         *
-         * @param time the date time to compare against
-         * @return the prior date time corresponding to this local time
-         */
-        public Calendar getDateTimeBefore(Calendar time) {
-            final Calendar c = Calendar.getInstance();
-            c.set(Calendar.YEAR, time.get(Calendar.YEAR));
-            c.set(Calendar.DAY_OF_YEAR, time.get(Calendar.DAY_OF_YEAR));
-
-            c.set(Calendar.HOUR_OF_DAY, hourOfDay);
-            c.set(Calendar.MINUTE, minute);
-            c.set(Calendar.SECOND, 0);
-            c.set(Calendar.MILLISECOND, 0);
-
-            // Check if the local time has past, if so return the same time tomorrow.
-            if (c.after(time)) {
-                c.add(Calendar.DATE, -1);
-            }
-
-            return c;
-        }
-
-        /**
-         * Returns the first date time corresponding to this local time that occurs after the
-         * provided date time.
-         *
-         * @param time the date time to compare against
-         * @return the next date time corresponding to this local time
-         */
-        public Calendar getDateTimeAfter(Calendar time) {
-            final Calendar c = Calendar.getInstance();
-            c.set(Calendar.YEAR, time.get(Calendar.YEAR));
-            c.set(Calendar.DAY_OF_YEAR, time.get(Calendar.DAY_OF_YEAR));
-
-            c.set(Calendar.HOUR_OF_DAY, hourOfDay);
-            c.set(Calendar.MINUTE, minute);
-            c.set(Calendar.SECOND, 0);
-            c.set(Calendar.MILLISECOND, 0);
-
-            // Check if the local time has past, if so return the same time tomorrow.
-            if (c.before(time)) {
-                c.add(Calendar.DATE, 1);
-            }
-
-            return c;
-        }
-
-        /**
-         * Returns a local time corresponding the given number of milliseconds from midnight.
-         *
-         * @param millis the number of milliseconds from midnight
-         * @return the corresponding local time
-         */
-        private static LocalTime valueOf(int millis) {
-            final int hourOfDay = (millis / 3600000) % 24;
-            final int minutes = (millis / 60000) % 60;
-            return new LocalTime(hourOfDay, minutes);
-        }
-
-        /**
-         * Returns the local time represented as milliseconds from midnight.
-         */
-        private int toMillis() {
-            return hourOfDay * 3600000 + minute * 60000;
-        }
-
-        @Override
-        public String toString() {
-            return String.format(Locale.US, "%02d:%02d", hourOfDay, minute);
-        }
-    }
-
-    /**
      * Callback invoked whenever the Night display settings are changed.
      */
     public interface Callback {
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 42e9273..64e12b4 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -560,7 +560,7 @@
 
     if (stream.get()) {
         std::unique_ptr<SkStreamRewindable> bufferedStream(
-                SkFrontBufferedStream::Create(stream.release(), SkCodec::MinBufferedBytesNeeded()));
+                SkFrontBufferedStream::Make(std::move(stream), SkCodec::MinBufferedBytesNeeded()));
         SkASSERT(bufferedStream.get() != NULL);
         bitmap = doDecode(env, std::move(bufferedStream), padding, options);
     }
@@ -610,7 +610,7 @@
     // Use a buffered stream. Although an SkFILEStream can be rewound, this
     // ensures that SkImageDecoder::Factory never rewinds beyond the
     // current position of the file descriptor.
-    std::unique_ptr<SkStreamRewindable> stream(SkFrontBufferedStream::Create(fileStream.release(),
+    std::unique_ptr<SkStreamRewindable> stream(SkFrontBufferedStream::Make(std::move(fileStream),
             SkCodec::MinBufferedBytesNeeded()));
 
     return doDecode(env, std::move(stream), padding, bitmapFactoryOptions);
diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp
index b243817..4c10a85 100644
--- a/core/jni/android/graphics/Movie.cpp
+++ b/core/jni/android/graphics/Movie.cpp
@@ -104,7 +104,8 @@
     // will only read 6.
     // FIXME: Get this number from SkImageDecoder
     // bufferedStream takes ownership of strm
-    std::unique_ptr<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Create(strm, 6));
+    std::unique_ptr<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Make(
+        std::unique_ptr<SkStream>(strm), 6));
     SkASSERT(bufferedStream.get() != NULL);
 
     Movie* moov = Movie::DecodeStream(bufferedStream.get());
diff --git a/core/jni/android/graphics/Utils.cpp b/core/jni/android/graphics/Utils.cpp
index 8934c1e..630220a 100644
--- a/core/jni/android/graphics/Utils.cpp
+++ b/core/jni/android/graphics/Utils.cpp
@@ -42,7 +42,7 @@
     return fAsset->getRemainingLength() == 0;
 }
 
-SkStreamRewindable* AssetStreamAdaptor::duplicate() const {
+SkStreamRewindable* AssetStreamAdaptor::onDuplicate() const {
     // Cannot create a duplicate, since each AssetStreamAdaptor
     // would be modifying the Asset.
     //return new AssetStreamAdaptor(fAsset);
diff --git a/core/jni/android/graphics/Utils.h b/core/jni/android/graphics/Utils.h
index fffec5b..69930a5 100644
--- a/core/jni/android/graphics/Utils.h
+++ b/core/jni/android/graphics/Utils.h
@@ -36,7 +36,9 @@
     virtual size_t getLength() const;
     virtual bool isAtEnd() const;
 
-    virtual SkStreamRewindable* duplicate() const;
+protected:
+    SkStreamRewindable* onDuplicate() const override;
+
 private:
     Asset* fAsset;
 };
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index aa94e0f..695fdac 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3074,6 +3074,12 @@
     <permission android:name="android.permission.BATTERY_STATS"
         android:protectionLevel="signature|privileged|development" />
 
+    <!--Allows an application to manage statscompanion.
+    <p>Not for use by third-party applications.
+         @hide -->
+    <permission android:name="android.permission.STATSCOMPANION"
+        android:protectionLevel="signature" />
+
     <!-- @SystemApi Allows an application to control the backup and restore process.
     <p>Not for use by third-party applications.
          @hide pending API council -->
@@ -3859,6 +3865,16 @@
             </intent-filter>
         </receiver>
 
+        <receiver android:name="com.android.server.stats.StatsCompanionService$AnomalyAlarmReceiver"
+                  android:permission="android.permission.STATSCOMPANION"
+                  android:exported="false">
+        </receiver>
+
+        <receiver android:name="com.android.server.stats.StatsCompanionService$PollingAlarmReceiver"
+                  android:permission="android.permission.STATSCOMPANION"
+                  android:exported="false">
+        </receiver>
+
         <service android:name="android.hardware.location.GeofenceHardwareService"
             android:permission="android.permission.LOCATION_HARDWARE"
             android:exported="false" />
diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp
index 3a77195..afb1193 100644
--- a/libs/hwui/service/GraphicsStatsService.cpp
+++ b/libs/hwui/service/GraphicsStatsService.cpp
@@ -40,7 +40,7 @@
 
 constexpr int sHistogramSize = ProfileData::HistogramSize();
 
-static void mergeProfileDataIntoProto(service::GraphicsStatsProto* proto,
+static bool mergeProfileDataIntoProto(service::GraphicsStatsProto* proto,
         const std::string& package, int versionCode, int64_t startTime, int64_t endTime,
         const ProfileData* data);
 static void dumpAsTextToFd(service::GraphicsStatsProto* proto, int outFd);
@@ -159,7 +159,7 @@
     return success;
 }
 
-void mergeProfileDataIntoProto(service::GraphicsStatsProto* proto, const std::string& package,
+bool mergeProfileDataIntoProto(service::GraphicsStatsProto* proto, const std::string& package,
         int versionCode, int64_t startTime, int64_t endTime, const ProfileData* data) {
     if (proto->stats_start() == 0 || proto->stats_start() > startTime) {
         proto->set_stats_start(startTime);
@@ -188,23 +188,31 @@
         proto->mutable_histogram()->Reserve(sHistogramSize);
         creatingHistogram = true;
     } else if (proto->histogram_size() != sHistogramSize) {
-        LOG_ALWAYS_FATAL("Histogram size mismatch, proto is %d expected %d",
+        ALOGE("Histogram size mismatch, proto is %d expected %d",
                 proto->histogram_size(), sHistogramSize);
+        return false;
     }
     int index = 0;
+    bool hitMergeError = false;
     data->histogramForEach([&](ProfileData::HistogramEntry entry) {
+        if (hitMergeError) return;
+
         service::GraphicsStatsHistogramBucketProto* bucket;
         if (creatingHistogram) {
             bucket = proto->add_histogram();
             bucket->set_render_millis(entry.renderTimeMs);
         } else {
             bucket = proto->mutable_histogram(index);
-            LOG_ALWAYS_FATAL_IF(bucket->render_millis() != static_cast<int32_t>(entry.renderTimeMs),
-                    "Frame time mistmatch %d vs. %u", bucket->render_millis(), entry.renderTimeMs);
+            if (bucket->render_millis() != static_cast<int32_t>(entry.renderTimeMs)) {
+                ALOGW("Frame time mistmatch %d vs. %u", bucket->render_millis(), entry.renderTimeMs);
+                hitMergeError = true;
+                return;
+            }
         }
         bucket->set_frame_count(bucket->frame_count() + entry.frameCount);
         index++;
     });
+    return !hitMergeError;
 }
 
 static int32_t findPercentile(service::GraphicsStatsProto* proto, int percentile) {
@@ -221,9 +229,11 @@
 
 void dumpAsTextToFd(service::GraphicsStatsProto* proto, int fd) {
     // This isn't a full validation, just enough that we can deref at will
-    LOG_ALWAYS_FATAL_IF(proto->package_name().empty()
-            || !proto->has_summary(), "package_name() '%s' summary %d",
-            proto->package_name().c_str(), proto->has_summary());
+    if (proto->package_name().empty() || !proto->has_summary()) {
+        ALOGW("Skipping dump, invalid package_name() '%s' or summary %d",
+                proto->package_name().c_str(), proto->has_summary());
+        return;
+    }
     dprintf(fd, "\nPackage: %s", proto->package_name().c_str());
     dprintf(fd, "\nVersion: %d", proto->version_code());
     dprintf(fd, "\nStats since: %lldns", proto->stats_start());
@@ -254,14 +264,20 @@
     if (!parseFromFile(path, &statsProto)) {
         statsProto.Clear();
     }
-    mergeProfileDataIntoProto(&statsProto, package, versionCode, startTime, endTime, data);
+    if (!mergeProfileDataIntoProto(&statsProto, package, versionCode, startTime, endTime, data)) {
+        return;
+    }
     // Although we might not have read any data from the file, merging the existing data
     // should always fully-initialize the proto
-    LOG_ALWAYS_FATAL_IF(!statsProto.IsInitialized(), "%s",
-            statsProto.InitializationErrorString().c_str());
-    LOG_ALWAYS_FATAL_IF(statsProto.package_name().empty()
-            || !statsProto.has_summary(), "package_name() '%s' summary %d",
-            statsProto.package_name().c_str(), statsProto.has_summary());
+    if (!statsProto.IsInitialized()) {
+        ALOGE("proto initialization error %s", statsProto.InitializationErrorString().c_str());
+        return;
+    }
+    if (statsProto.package_name().empty() || !statsProto.has_summary()) {
+        ALOGE("missing package_name() '%s' summary %d",
+                statsProto.package_name().c_str(), statsProto.has_summary());
+        return;
+    }
     int outFd = open(path.c_str(), O_CREAT | O_RDWR | O_TRUNC, 0660);
     if (outFd <= 0) {
         int err = errno;
@@ -312,8 +328,9 @@
     if (!path.empty() && !parseFromFile(path, &statsProto)) {
         statsProto.Clear();
     }
-    if (data) {
-        mergeProfileDataIntoProto(&statsProto, package, versionCode, startTime, endTime, data);
+    if (data && !mergeProfileDataIntoProto(
+            &statsProto, package, versionCode, startTime, endTime, data)) {
+        return;
     }
     if (!statsProto.IsInitialized()) {
         ALOGW("Failed to load profile data from path '%s' and data %p",
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index fe427a7..8707ad0 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -204,7 +204,6 @@
                 audioRoutesChanged = true;
             }
 
-            final int mainType = mCurAudioRoutesInfo.mainType;
             if (!TextUtils.equals(newRoutes.bluetoothName, mCurAudioRoutesInfo.bluetoothName)) {
                 mCurAudioRoutesInfo.bluetoothName = newRoutes.bluetoothName;
                 if (mCurAudioRoutesInfo.bluetoothName != null) {
@@ -231,8 +230,11 @@
             }
 
             if (audioRoutesChanged) {
-                selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, getDefaultSystemAudioRoute(), false);
                 Log.v(TAG, "Audio routes updated: " + newRoutes + ", a2dp=" + isBluetoothA2dpOn());
+                if (mSelectedRoute == null || mSelectedRoute == mDefaultAudioVideo
+                        || mSelectedRoute == mBluetoothA2dpRoute) {
+                    selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, getDefaultSystemAudioRoute(), false);
+                }
             }
         }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
index 9b75c00..35ba6ae 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
@@ -26,7 +26,6 @@
 import android.content.res.Resources;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
-import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -320,6 +319,15 @@
             Context context, UserHandle user, Intent intent,
             Map<Pair<String, String>, Tile> addedCache, String defaultCategory, List<Tile> outTiles,
             boolean usePriority, boolean checkCategory, boolean forceTintExternalIcon) {
+        getTilesForIntent(context, user, intent, addedCache, defaultCategory, outTiles,
+                usePriority, checkCategory, forceTintExternalIcon, false /* shouldUpdateTiles */);
+    }
+
+    public static void getTilesForIntent(
+            Context context, UserHandle user, Intent intent,
+            Map<Pair<String, String>, Tile> addedCache, String defaultCategory, List<Tile> outTiles,
+            boolean usePriority, boolean checkCategory, boolean forceTintExternalIcon,
+            boolean shouldUpdateTiles) {
         PackageManager pm = context.getPackageManager();
         List<ResolveInfo> results = pm.queryIntentActivitiesAsUser(intent,
                 PackageManager.GET_META_DATA, user.getIdentifier());
@@ -357,9 +365,11 @@
                 updateTileData(context, tile, activityInfo, activityInfo.applicationInfo,
                         pm, providerMap, forceTintExternalIcon);
                 if (DEBUG) Log.d(LOG_TAG, "Adding tile " + tile.title);
-
                 addedCache.put(key, tile);
+            } else if (shouldUpdateTiles) {
+                updateSummaryAndTitle(context, providerMap, tile);
             }
+
             if (!tile.userHandle.contains(user)) {
                 tile.userHandle.add(user);
             }
@@ -380,7 +390,6 @@
             String summary = null;
             String keyHint = null;
             boolean isIconTintable = false;
-            RemoteViews remoteViews = null;
 
             // Get the activity's meta-data
             try {
@@ -428,7 +437,8 @@
                     }
                     if (metaData.containsKey(META_DATA_PREFERENCE_CUSTOM_VIEW)) {
                         int layoutId = metaData.getInt(META_DATA_PREFERENCE_CUSTOM_VIEW);
-                        remoteViews = new RemoteViews(applicationInfo.packageName, layoutId);
+                        tile.remoteViews = new RemoteViews(applicationInfo.packageName, layoutId);
+                        updateSummaryAndTitle(context, providerMap, tile);
                     }
                 }
             } catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) {
@@ -462,7 +472,6 @@
             // Suggest a key for this tile
             tile.key = keyHint;
             tile.isIconTintable = isIconTintable;
-            tile.remoteViews = remoteViews;
 
             return true;
         }
@@ -470,6 +479,26 @@
         return false;
     }
 
+    private static void updateSummaryAndTitle(
+            Context context, Map<String, IContentProvider> providerMap, Tile tile) {
+        if (tile == null || tile.metaData == null
+                || !tile.metaData.containsKey(META_DATA_PREFERENCE_SUMMARY_URI)) {
+            return;
+        }
+
+        String uriString = tile.metaData.getString(META_DATA_PREFERENCE_SUMMARY_URI);
+        Bundle bundle = getBundleFromUri(context, uriString, providerMap);
+        String overrideSummary = getString(bundle, META_DATA_PREFERENCE_SUMMARY);
+        String overrideTitle = getString(bundle, META_DATA_PREFERENCE_TITLE);
+        if (overrideSummary != null) {
+            tile.remoteViews.setTextViewText(android.R.id.summary, overrideSummary);
+        }
+
+        if (overrideTitle != null) {
+            tile.remoteViews.setTextViewText(android.R.id.title, overrideTitle);
+        }
+    }
+
     /**
      * Gets the icon package name and resource id from content provider.
      * @param context context
@@ -535,37 +564,6 @@
         }
     }
 
-    public static void updateTileUsingSummaryUri(Context context, final Tile tile) {
-        if (tile == null || tile.metaData == null ||
-                !tile.metaData.containsKey(META_DATA_PREFERENCE_SUMMARY_URI)) {
-            return;
-        }
-
-        new AsyncTask<Void, Void, Bundle>() {
-            @Override
-            protected Bundle doInBackground(Void... params) {
-                return getBundleFromUri(context,
-                        tile.metaData.getString(META_DATA_PREFERENCE_SUMMARY_URI), new HashMap<>());
-            }
-
-            @Override
-            protected void onPostExecute(Bundle bundle) {
-                if (bundle == null) {
-                    return;
-                }
-                final String overrideSummary = getString(bundle, META_DATA_PREFERENCE_SUMMARY);
-                final String overrideTitle = getString(bundle, META_DATA_PREFERENCE_TITLE);
-
-                if (overrideSummary != null) {
-                    tile.remoteViews.setTextViewText(android.R.id.summary, overrideSummary);
-                }
-                if (overrideTitle != null) {
-                    tile.remoteViews.setTextViewText(android.R.id.title, overrideTitle);
-                }
-            }
-        }.execute();
-    }
-
     private static String getString(Bundle bundle, String key) {
         return bundle == null ? null : bundle.getString(key);
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java
index 00f32b2..56b8441 100644
--- a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java
+++ b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java
@@ -195,7 +195,7 @@
             intent.setPackage(category.pkg);
         }
         TileUtils.getTilesForIntent(mContext, new UserHandle(UserHandle.myUserId()), intent,
-                mAddCache, null, suggestions, true, false, false);
+                mAddCache, null, suggestions, true, false, false, true /* shouldUpdateTiles */);
         filterSuggestions(suggestions, countBefore, isSmartSuggestionEnabled);
         if (!category.multiple && suggestions.size() > (countBefore + 1)) {
             // If there are too many, remove them all and only re-add the one with the highest
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
index 76f6a20..3e90435 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
@@ -22,12 +22,10 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.robolectric.RuntimeEnvironment.application;
@@ -66,7 +64,9 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.internal.ShadowExtractor;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -75,7 +75,8 @@
 
 @RunWith(RobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH,
-        sdk = TestConfig.SDK_VERSION)
+        sdk = TestConfig.SDK_VERSION,
+        shadows = {TileUtilsTest.TileUtilsShadowRemoteViews.class})
 public class TileUtilsTest {
 
     @Mock
@@ -420,12 +421,24 @@
     }
 
     @Test
-    public void updateTileUsingSummaryUri_summaryUriSpecified_shouldOverrideRemoteViewSummary()
+    public void getTilesForIntent_summaryUriSpecified_shouldOverrideRemoteViewSummary()
             throws RemoteException {
+        Intent intent = new Intent();
+        Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
+        List<Tile> outTiles = new ArrayList<>();
+        List<ResolveInfo> info = new ArrayList<>();
+        ResolveInfo resolveInfo = newInfo(true, null /* category */, null,
+                null, URI_GET_SUMMARY);
+        resolveInfo.activityInfo.metaData.putInt("com.android.settings.custom_view",
+                R.layout.user_preference);
+        info.add(resolveInfo);
+
+        when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
+                .thenReturn(info);
+
         // Mock the content provider interaction.
         Bundle bundle = new Bundle();
-        String expectedSummary = "new summary text";
-        bundle.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY, expectedSummary);
+        bundle.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY, "new summary text");
         when(mIContentProvider.call(anyString(),
                 eq(TileUtils.getMethodFromUri(Uri.parse(URI_GET_SUMMARY))), eq(URI_GET_SUMMARY),
                 any())).thenReturn(bundle);
@@ -434,14 +447,57 @@
         when(mContentResolver.acquireUnstableProvider(any(Uri.class)))
                 .thenReturn(mIContentProvider);
 
-        Tile tile = new Tile();
-        tile.metaData = new Bundle();
-        tile.metaData.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY_URI, URI_GET_SUMMARY);
-        tile.remoteViews = mock(RemoteViews.class);
-        TileUtils.updateTileUsingSummaryUri(mContext, tile);
-        ShadowApplication.runBackgroundTasks();
+        TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
+                null /* defaultCategory */, outTiles, false /* usePriority */,
+                false /* checkCategory */, true /* forceTintExternalIcon */);
 
-        verify(tile.remoteViews, times(1)).setTextViewText(anyInt(), eq(expectedSummary));
+        assertThat(outTiles.size()).isEqualTo(1);
+        Tile tile = outTiles.get(0);
+        assertThat(tile.remoteViews).isNotNull();
+        assertThat(tile.remoteViews.getLayoutId()).isEqualTo(R.layout.user_preference);
+        // Make sure the summary TextView got a new text string.
+        TileUtilsShadowRemoteViews shadowRemoteViews =
+                (TileUtilsShadowRemoteViews) ShadowExtractor.extract(tile.remoteViews);
+        assertThat(shadowRemoteViews.overrideViewId).isEqualTo(android.R.id.summary);
+        assertThat(shadowRemoteViews.overrideText).isEqualTo("new summary text");
+    }
+
+    @Test
+    public void getTilesForIntent_providerUnavailable_shouldNotOverrideRemoteViewSummary()
+            throws RemoteException {
+        Intent intent = new Intent();
+        Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
+        List<Tile> outTiles = new ArrayList<>();
+        List<ResolveInfo> info = new ArrayList<>();
+        ResolveInfo resolveInfo = newInfo(true, null /* category */, null,
+                null, URI_GET_SUMMARY);
+        resolveInfo.activityInfo.metaData.putInt("com.android.settings.custom_view",
+                R.layout.user_preference);
+        info.add(resolveInfo);
+
+        when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
+                .thenReturn(info);
+
+        // Mock the content provider interaction.
+        Bundle bundle = new Bundle();
+        bundle.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY, "new summary text");
+        when(mIContentProvider.call(anyString(),
+                eq(TileUtils.getMethodFromUri(Uri.parse(URI_GET_SUMMARY))), eq(URI_GET_SUMMARY),
+                any())).thenReturn(bundle);
+
+        TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
+                null /* defaultCategory */, outTiles, false /* usePriority */,
+                false /* checkCategory */, true /* forceTintExternalIcon */);
+
+        assertThat(outTiles.size()).isEqualTo(1);
+        Tile tile = outTiles.get(0);
+        assertThat(tile.remoteViews).isNotNull();
+        assertThat(tile.remoteViews.getLayoutId()).isEqualTo(R.layout.user_preference);
+        // Make sure the summary TextView didn't get any text view updates.
+        TileUtilsShadowRemoteViews shadowRemoteViews =
+                (TileUtilsShadowRemoteViews) ShadowExtractor.extract(tile.remoteViews);
+        assertThat(shadowRemoteViews.overrideViewId).isNull();
+        assertThat(shadowRemoteViews.overrideText).isNull();
     }
 
     public static ResolveInfo newInfo(boolean systemApp, String category) {
@@ -502,4 +558,16 @@
         }
     }
 
+    @Implements(RemoteViews.class)
+    public static class TileUtilsShadowRemoteViews {
+
+        private Integer overrideViewId;
+        private CharSequence overrideText;
+
+        @Implementation
+        public void setTextViewText(int viewId, CharSequence text) {
+            overrideViewId = viewId;
+            overrideText = text;
+        }
+    }
 }
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
deleted file mode 100644
index 22f1a65..0000000
--- a/packages/SystemUI/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-set noparent  # do not inherit owners in parent directories
-
-per-file Android.bp = build.master@android.com  # special file expert
-per-file Android.bp = android-sysui-eng+reviews@google.com
-
-android-sysui-eng+reviews@google.com
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index 8de1d31..2bc0e45c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -15,6 +15,8 @@
  */
 package com.android.keyguard;
 
+import static android.view.Display.INVALID_DISPLAY;
+
 import android.app.Presentation;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -28,16 +30,21 @@
 import android.view.View;
 import android.view.WindowManager;
 
+// TODO(multi-display): Support multiple external displays
 public class KeyguardDisplayManager {
     protected static final String TAG = "KeyguardDisplayManager";
     private static boolean DEBUG = KeyguardConstants.DEBUG;
+
+    private final ViewMediatorCallback mCallback;
+    private final MediaRouter mMediaRouter;
+    private final Context mContext;
+
     Presentation mPresentation;
-    private MediaRouter mMediaRouter;
-    private Context mContext;
     private boolean mShowing;
 
-    public KeyguardDisplayManager(Context context) {
+    public KeyguardDisplayManager(Context context, ViewMediatorCallback callback) {
         mContext = context;
+        mCallback = callback;
         mMediaRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE);
     }
 
@@ -90,6 +97,7 @@
     };
 
     protected void updateDisplays(boolean showing) {
+        Presentation originalPresentation = mPresentation;
         if (showing) {
             MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute(
                     MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
@@ -121,6 +129,13 @@
                 mPresentation = null;
             }
         }
+
+        // mPresentation is only updated when the display changes
+        if (mPresentation != originalPresentation) {
+            final int displayId = mPresentation != null
+                    ? mPresentation.getDisplay().getDisplayId() : INVALID_DISPLAY;
+            mCallback.onSecondaryDisplayShowingChanged(displayId);
+        }
     }
 
     private final static class KeyguardPresentation extends Presentation {
diff --git a/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java b/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java
index 327d218..b194de4 100644
--- a/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java
@@ -88,4 +88,9 @@
      *         {@link KeyguardSecurityView#PROMPT_REASON_TIMEOUT}.
      */
     int getBouncerPromptReason();
+
+    /**
+     * Invoked when the secondary display showing a keyguard window changes.
+     */
+    void onSecondaryDisplayShowingChanged(int displayId);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 4cbbbd6..189badf 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -1280,7 +1280,23 @@
             mGradientDrawable.setScreenSize(displaySize.x, displaySize.y);
             GradientColors colors = mColorExtractor.getColors(mKeyguardShowing ?
                     WallpaperManager.FLAG_LOCK : WallpaperManager.FLAG_SYSTEM);
-            mGradientDrawable.setColors(colors, false);
+            updateColors(colors, false /* animate */);
+        }
+
+        /**
+         * Updates background and system bars according to current GradientColors.
+         * @param colors Colors and hints to use.
+         * @param animate Interpolates gradient if true, just sets otherwise.
+         */
+        private void updateColors(GradientColors colors, boolean animate) {
+            mGradientDrawable.setColors(colors, animate);
+            View decorView = getWindow().getDecorView();
+            if (colors.supportsDarkText()) {
+                decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR |
+                    View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
+            } else {
+                decorView.setSystemUiVisibility(0);
+            }
         }
 
         @Override
@@ -1350,11 +1366,13 @@
         public void onColorsChanged(ColorExtractor extractor, int which) {
             if (mKeyguardShowing) {
                 if ((WallpaperManager.FLAG_LOCK & which) != 0) {
-                    mGradientDrawable.setColors(extractor.getColors(WallpaperManager.FLAG_LOCK));
+                    updateColors(extractor.getColors(WallpaperManager.FLAG_LOCK),
+                            true /* animate */);
                 }
             } else {
                 if ((WallpaperManager.FLAG_SYSTEM & which) != 0) {
-                    mGradientDrawable.setColors(extractor.getColors(WallpaperManager.FLAG_SYSTEM));
+                    updateColors(extractor.getColors(WallpaperManager.FLAG_SYSTEM),
+                            true /* animate */);
                 }
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 3eb68f5..28adca9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -17,6 +17,7 @@
 package com.android.systemui.keyguard;
 
 import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
+import static android.view.Display.INVALID_DISPLAY;
 
 import static com.android.internal.telephony.IccCardConstants.State.ABSENT;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
@@ -239,6 +240,9 @@
     // answer whether the input should be restricted)
     private boolean mShowing;
 
+    // display id of the secondary display on which we have put a keyguard window
+    private int mSecondaryDisplayShowing = INVALID_DISPLAY;
+
     /** Cached value of #isInputRestricted */
     private boolean mInputRestricted;
 
@@ -646,6 +650,13 @@
             }
             return KeyguardSecurityView.PROMPT_REASON_NONE;
         }
+
+        @Override
+        public void onSecondaryDisplayShowingChanged(int displayId) {
+            synchronized (KeyguardViewMediator.this) {
+                setShowingLocked(mShowing, displayId, false);
+            }
+        }
     };
 
     public void userActivity() {
@@ -670,7 +681,7 @@
         filter.addAction(Intent.ACTION_SHUTDOWN);
         mContext.registerReceiver(mBroadcastReceiver, filter);
 
-        mKeyguardDisplayManager = new KeyguardDisplayManager(mContext);
+        mKeyguardDisplayManager = new KeyguardDisplayManager(mContext, mViewMediatorCallback);
 
         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
 
@@ -685,7 +696,8 @@
                 com.android.keyguard.R.bool.config_enableKeyguardService)) {
             setShowingLocked(!shouldWaitForProvisioning()
                     && !mLockPatternUtils.isLockScreenDisabled(
-                            KeyguardUpdateMonitor.getCurrentUser()), true /* forceCallbacks */);
+                            KeyguardUpdateMonitor.getCurrentUser()),
+                    mSecondaryDisplayShowing, true /* forceCallbacks */);
         }
 
         mStatusBarKeyguardViewManager =
@@ -1694,10 +1706,10 @@
         playSound(mTrustedSoundId);
     }
 
-    private void updateActivityLockScreenState(boolean showing) {
+    private void updateActivityLockScreenState(boolean showing, int secondaryDisplayShowing) {
         mUiOffloadThread.submit(() -> {
             try {
-                ActivityManager.getService().setLockScreenShown(showing);
+                ActivityManager.getService().setLockScreenShown(showing, secondaryDisplayShowing);
             } catch (RemoteException e) {
             }
         });
@@ -2060,30 +2072,39 @@
     }
 
     private void setShowingLocked(boolean showing) {
-        setShowingLocked(showing, false /* forceCallbacks */);
+        setShowingLocked(showing, mSecondaryDisplayShowing, false /* forceCallbacks */);
     }
 
-    private void setShowingLocked(boolean showing, boolean forceCallbacks) {
-        if (showing != mShowing || forceCallbacks) {
+    private void setShowingLocked(
+            boolean showing, int secondaryDisplayShowing, boolean forceCallbacks) {
+        final boolean notifyDefaultDisplayCallbacks = showing != mShowing || forceCallbacks;
+        if (notifyDefaultDisplayCallbacks || secondaryDisplayShowing != mSecondaryDisplayShowing) {
             mShowing = showing;
-            int size = mKeyguardStateCallbacks.size();
-            for (int i = size - 1; i >= 0; i--) {
-                IKeyguardStateCallback callback = mKeyguardStateCallbacks.get(i);
-                try {
-                    callback.onShowingStateChanged(showing);
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "Failed to call onShowingStateChanged", e);
-                    if (e instanceof DeadObjectException) {
-                        mKeyguardStateCallbacks.remove(callback);
-                    }
+            mSecondaryDisplayShowing = secondaryDisplayShowing;
+            if (notifyDefaultDisplayCallbacks) {
+                notifyDefaultDisplayCallbacks(showing);
+            }
+            updateActivityLockScreenState(showing, secondaryDisplayShowing);
+        }
+    }
+
+    private void notifyDefaultDisplayCallbacks(boolean showing) {
+        int size = mKeyguardStateCallbacks.size();
+        for (int i = size - 1; i >= 0; i--) {
+            IKeyguardStateCallback callback = mKeyguardStateCallbacks.get(i);
+            try {
+                callback.onShowingStateChanged(showing);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failed to call onShowingStateChanged", e);
+                if (e instanceof DeadObjectException) {
+                    mKeyguardStateCallbacks.remove(callback);
                 }
             }
-            updateInputRestrictedLocked();
-            mUiOffloadThread.submit(() -> {
-                mTrustManager.reportKeyguardShowingChanged();
-            });
-            updateActivityLockScreenState(showing);
         }
+        updateInputRestrictedLocked();
+        mUiOffloadThread.submit(() -> {
+            mTrustManager.reportKeyguardShowingChanged();
+        });
     }
 
     private void notifyTrustedChangedLocked(boolean trusted) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index aecf95f..c4e8701 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -565,8 +565,7 @@
 
         // Launch the task
         ssp.startActivityFromRecents(
-                mContext, toTask.key, toTask.title, launchOpts, INVALID_STACK_ID,
-                null /* resultListener */);
+                mContext, toTask.key, toTask.title, launchOpts, null /* resultListener */);
     }
 
     /**
@@ -639,8 +638,7 @@
 
         // Launch the task
         ssp.startActivityFromRecents(
-                mContext, toTask.key, toTask.title, launchOpts, INVALID_STACK_ID,
-                null /* resultListener */);
+                mContext, toTask.key, toTask.title, launchOpts, null /* resultListener */);
     }
 
     public void showNextAffiliatedTask() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java
index 3db106e..862a1ee 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.recents.events.activity;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+
 import android.graphics.Rect;
 
 import com.android.systemui.recents.events.EventBus;
@@ -30,15 +33,23 @@
     public final TaskView taskView;
     public final Task task;
     public final Rect targetTaskBounds;
-    public final int targetTaskStack;
+    public final int targetWindowingMode;
+    public final int targetActivityType;
     public final boolean screenPinningRequested;
 
-    public LaunchTaskEvent(TaskView taskView, Task task, Rect targetTaskBounds, int targetTaskStack,
+    public LaunchTaskEvent(TaskView taskView, Task task, Rect targetTaskBounds,
             boolean screenPinningRequested) {
+        this(taskView, task, targetTaskBounds, screenPinningRequested,
+                WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED);
+    }
+
+    public LaunchTaskEvent(TaskView taskView, Task task, Rect targetTaskBounds,
+            boolean screenPinningRequested, int windowingMode, int activityType) {
         this.taskView = taskView;
         this.task = task;
         this.targetTaskBounds = targetTaskBounds;
-        this.targetTaskStack = targetTaskStack;
+        this.targetWindowingMode = windowingMode;
+        this.targetActivityType = activityType;
         this.screenPinningRequested = screenPinningRequested;
     }
 
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 7177782..366a908 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -23,6 +23,10 @@
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+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 static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
 
 import android.annotation.NonNull;
@@ -576,7 +580,7 @@
         try {
             final ActivityOptions options = ActivityOptions.makeBasic();
             options.setDockCreateMode(createMode);
-            options.setLaunchStackId(DOCKED_STACK_ID);
+            options.setLaunchWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
             mIam.startActivityFromRecents(taskId, options.toBundle());
             return true;
         } catch (Exception e) {
@@ -1120,9 +1124,16 @@
                 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 stackId,
+            ActivityOptions options, int windowingMode, int activityType,
             @Nullable final StartActivityFromRecentsResultListener resultListener) {
         if (mIam == null) {
             return;
@@ -1133,12 +1144,14 @@
             if (options == null) {
                 options = ActivityOptions.makeBasic();
             }
-            options.setLaunchStackId(FULLSCREEN_WORKSPACE_STACK_ID);
-        } else if (stackId != INVALID_STACK_ID) {
+            options.setLaunchWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+        } else if (windowingMode != WINDOWING_MODE_UNDEFINED
+                || activityType != ACTIVITY_TYPE_UNDEFINED) {
             if (options == null) {
                 options = ActivityOptions.makeBasic();
             }
-            options.setLaunchStackId(stackId);
+            options.setLaunchWindowingMode(windowingMode);
+            options.setLaunchActivityType(activityType);
         }
         final ActivityOptions finalOptions = options;
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
index b2675d7..4d33216 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -21,6 +21,15 @@
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 
 import android.annotation.Nullable;
 import android.app.ActivityManager.StackId;
@@ -107,7 +116,7 @@
      */
     public void launchTaskFromRecents(final TaskStack stack, @Nullable final Task task,
             final TaskStackView stackView, final TaskView taskView,
-            final boolean screenPinningRequested, final int destinationStack) {
+            final boolean screenPinningRequested, final int windowingMode, final int activityType) {
 
         final ActivityOptions.OnAnimationStartedListener animStartedListener;
         final AppTransitionAnimationSpecsFuture transitionFuture;
@@ -116,8 +125,8 @@
             // Fetch window rect here already in order not to be blocked on lock contention in WM
             // when the future calls it.
             final Rect windowRect = Recents.getSystemServices().getWindowRect();
-            transitionFuture = getAppTransitionFuture(
-                    () -> composeAnimationSpecs(task, stackView, destinationStack, windowRect));
+            transitionFuture = getAppTransitionFuture(() -> composeAnimationSpecs(
+                    task, stackView, windowingMode, activityType, windowRect));
             animStartedListener = new OnAnimationStartedListener() {
                 private boolean mHandled;
 
@@ -180,7 +189,8 @@
         if (taskView == null) {
             // If there is no task view, then we do not need to worry about animating out occluding
             // task views, and we can launch immediately
-            startTaskActivity(stack, task, taskView, opts, transitionFuture, destinationStack);
+            startTaskActivity(stack, task, taskView, opts, transitionFuture,
+                    windowingMode, activityType);
         } else {
             LaunchTaskStartedEvent launchStartedEvent = new LaunchTaskStartedEvent(taskView,
                     screenPinningRequested);
@@ -189,13 +199,14 @@
                     @Override
                     public void run() {
                         startTaskActivity(stack, task, taskView, opts, transitionFuture,
-                                destinationStack);
+                                windowingMode, activityType);
                     }
                 });
                 EventBus.getDefault().send(launchStartedEvent);
             } else {
                 EventBus.getDefault().send(launchStartedEvent);
-                startTaskActivity(stack, task, taskView, opts, transitionFuture, destinationStack);
+                startTaskActivity(stack, task, taskView, opts, transitionFuture,
+                        windowingMode, activityType);
             }
         }
         Recents.getSystemServices().sendCloseSystemWindows(
@@ -224,13 +235,13 @@
      *
      * @param taskView this is the {@link TaskView} that we are launching from. This can be null if
      *                 we are toggling recents and the launch-to task is now offscreen.
-     * @param destinationStack id of the stack to put the task into.
      */
     private void startTaskActivity(TaskStack stack, Task task, @Nullable TaskView taskView,
             ActivityOptions opts, AppTransitionAnimationSpecsFuture transitionFuture,
-            int destinationStack) {
+            int windowingMode, int activityType) {
         SystemServicesProxy ssp = Recents.getSystemServices();
-        ssp.startActivityFromRecents(mContext, task.key, task.title, opts, destinationStack,
+        ssp.startActivityFromRecents(mContext, task.key, task.title, opts, windowingMode,
+                activityType,
                 succeeded -> {
             if (succeeded) {
                 // Keep track of the index of the task launch
@@ -310,11 +321,9 @@
      * Composes the animation specs for all the tasks in the target stack.
      */
     private List<AppTransitionAnimationSpec> composeAnimationSpecs(final Task task,
-            final TaskStackView stackView, final int destinationStack, Rect windowRect) {
-        // Ensure we have a valid target stack id
-        final int targetStackId = destinationStack != INVALID_STACK_ID ?
-                destinationStack : task.key.stackId;
-        if (!StackId.useAnimationSpecForAppTransition(targetStackId)) {
+            final TaskStackView stackView, int windowingMode, int activityType, Rect windowRect) {
+        if (activityType == ACTIVITY_TYPE_RECENTS || activityType == ACTIVITY_TYPE_HOME
+                || windowingMode == WINDOWING_MODE_PINNED) {
             return null;
         }
 
@@ -329,9 +338,12 @@
         List<AppTransitionAnimationSpec> specs = new ArrayList<>();
 
         // TODO: Sometimes targetStackId is not initialized after reboot, so we also have to
-        // check for INVALID_STACK_ID
-        if (targetStackId == FULLSCREEN_WORKSPACE_STACK_ID || targetStackId == DOCKED_STACK_ID
-                || targetStackId == ASSISTANT_STACK_ID || targetStackId == INVALID_STACK_ID) {
+        // check for INVALID_STACK_ID (now WINDOWING_MODE_UNDEFINED)
+        if (windowingMode == WINDOWING_MODE_FULLSCREEN
+                || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+                || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
+                || activityType == ACTIVITY_TYPE_ASSISTANT
+                || windowingMode == WINDOWING_MODE_UNDEFINED) {
             if (taskView == null) {
                 specs.add(composeOffscreenAnimationSpec(task, offscreenTaskRect));
             } else {
@@ -353,7 +365,7 @@
         int taskCount = tasks.size();
         for (int i = taskCount - 1; i >= 0; i--) {
             Task t = tasks.get(i);
-            if (t.isFreeformTask() || targetStackId == FREEFORM_WORKSPACE_STACK_ID) {
+            if (t.isFreeformTask() || windowingMode == WINDOWING_MODE_FREEFORM) {
                 TaskView tv = stackView.getChildViewForTask(t);
                 if (tv == null) {
                     // TODO: Create a different animation task rect for this case (though it should
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 c44cd72..fd1b806 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -338,8 +338,7 @@
             Task task = mTaskStackView.getFocusedTask();
             if (task != null) {
                 TaskView taskView = mTaskStackView.getChildViewForTask(task);
-                EventBus.getDefault().send(new LaunchTaskEvent(taskView, task, null,
-                        INVALID_STACK_ID, false));
+                EventBus.getDefault().send(new LaunchTaskEvent(taskView, task, null, false));
 
                 if (logEvent != 0) {
                     MetricsLogger.action(getContext(), logEvent,
@@ -363,32 +362,13 @@
             Task task = getStack().getLaunchTarget();
             if (task != null) {
                 TaskView taskView = mTaskStackView.getChildViewForTask(task);
-                EventBus.getDefault().send(new LaunchTaskEvent(taskView, task, null,
-                        INVALID_STACK_ID, false));
+                EventBus.getDefault().send(new LaunchTaskEvent(taskView, task, null, false));
                 return true;
             }
         }
         return false;
     }
 
-    /** Launches a given task. */
-    public boolean launchTask(Task task, Rect taskBounds, int destinationStack) {
-        if (mTaskStackView != null) {
-            // Iterate the stack views and try and find the given task.
-            List<TaskView> taskViews = mTaskStackView.getTaskViews();
-            int taskViewCount = taskViews.size();
-            for (int j = 0; j < taskViewCount; j++) {
-                TaskView tv = taskViews.get(j);
-                if (tv.getTask() == task) {
-                    EventBus.getDefault().send(new LaunchTaskEvent(tv, task, taskBounds,
-                            destinationStack, false));
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
     /**
      * Hides the task stack and shows the empty view.
      */
@@ -570,7 +550,8 @@
     public final void onBusEvent(LaunchTaskEvent event) {
         mLastTaskLaunchedWasFreeform = event.task.isFreeformTask();
         mTransitionHelper.launchTaskFromRecents(getStack(), event.task, mTaskStackView,
-                event.taskView, event.screenPinningRequested, event.targetTaskStack);
+                event.taskView, event.screenPinningRequested, event.targetWindowingMode,
+                event.targetActivityType);
         if (Recents.getConfiguration().isLowRamDevice) {
             hideStackActionButton(HIDE_STACK_ACTION_BUTTON_DURATION, false /* translate */);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 8899e30..74e9ef2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -1487,7 +1487,7 @@
             Task frontTask = tasks.get(tasks.size() - 1);
             if (frontTask != null && frontTask.isFreeformTask()) {
                 EventBus.getDefault().send(new LaunchTaskEvent(getChildViewForTask(frontTask),
-                        frontTask, null, INVALID_STACK_ID, false));
+                        frontTask, null, false));
                 return true;
             }
         }
@@ -2369,12 +2369,12 @@
                         public void run() {
                             EventBus.getDefault().send(new LaunchTaskEvent(
                                     getChildViewForTask(task), task, null,
-                                    INVALID_STACK_ID, false /* screenPinningRequested */));
+                                    false /* screenPinningRequested */));
                         }
                     });
         } else {
-            EventBus.getDefault().send(new LaunchTaskEvent(getChildViewForTask(task),
-                    task, null, INVALID_STACK_ID, false /* screenPinningRequested */));
+            EventBus.getDefault().send(new LaunchTaskEvent(getChildViewForTask(task), task, null,
+                    false /* screenPinningRequested */));
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index ceeebd96..c64f6df 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -674,8 +674,7 @@
             mActionButtonView.setTranslationZ(0f);
             screenPinningRequested = true;
         }
-        EventBus.getDefault().send(new LaunchTaskEvent(this, mTask, null, INVALID_STACK_ID,
-                screenPinningRequested));
+        EventBus.getDefault().send(new LaunchTaskEvent(this, mTask, null, screenPinningRequested));
 
         MetricsLogger.action(v.getContext(), MetricsEvent.ACTION_OVERVIEW_SELECT,
                 mTask.key.getComponent().toString());
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index ae922fc..198ecae 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -16,6 +16,11 @@
 
 package com.android.systemui.recents.views;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.annotation.Nullable;
@@ -57,10 +62,6 @@
 import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.Task;
 
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-
 /* The task bar view */
 public class TaskViewHeader extends FrameLayout
         implements View.OnClickListener, View.OnLongClickListener {
@@ -172,7 +173,7 @@
     int mTaskBarViewLightTextColor;
     int mTaskBarViewDarkTextColor;
     int mDisabledTaskBarBackgroundColor;
-    int mMoveTaskTargetStackId = INVALID_STACK_ID;
+    int mTaskWindowingMode = WINDOWING_MODE_UNDEFINED;
 
     // Header background
     private HighlightColorDrawable mBackground;
@@ -485,12 +486,12 @@
         // current task
         if (mMoveTaskButton != null) {
             if (t.isFreeformTask()) {
-                mMoveTaskTargetStackId = FULLSCREEN_WORKSPACE_STACK_ID;
+                mTaskWindowingMode = WINDOWING_MODE_FULLSCREEN;
                 mMoveTaskButton.setImageDrawable(t.useLightOnPrimaryColor
                         ? mLightFullscreenIcon
                         : mDarkFullscreenIcon);
             } else {
-                mMoveTaskTargetStackId = FREEFORM_WORKSPACE_STACK_ID;
+                mTaskWindowingMode = WINDOWING_MODE_FREEFORM;
                 mMoveTaskButton.setImageDrawable(t.useLightOnPrimaryColor
                         ? mLightFreeformIcon
                         : mDarkFreeformIcon);
@@ -621,8 +622,8 @@
                     Constants.Metrics.DismissSourceHeaderButton);
         } else if (v == mMoveTaskButton) {
             TaskView tv = Utilities.findParent(this, TaskView.class);
-            EventBus.getDefault().send(new LaunchTaskEvent(tv, mTask, null,
-                    mMoveTaskTargetStackId, false));
+            EventBus.getDefault().send(new LaunchTaskEvent(tv, mTask, null, false,
+                    mTaskWindowingMode, ACTIVITY_TYPE_UNDEFINED));
         } else if (v == mAppInfoView) {
             EventBus.getDefault().send(new ShowApplicationInfoEvent(mTask));
         } else if (v == mAppIconView) {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 6bfef20..44e60ee 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -93,7 +93,6 @@
     private static final int LOG_VALUE_UNDOCK_MAX_OTHER = 1;
 
     private static final int TASK_POSITION_SAME = Integer.MAX_VALUE;
-    private static final boolean SWAPPING_ENABLED = false;
 
     /**
      * How much the background gets scaled when we are in the minimized dock state.
@@ -153,7 +152,6 @@
     private boolean mEntranceAnimationRunning;
     private boolean mExitAnimationRunning;
     private int mExitStartPosition;
-    private GestureDetector mGestureDetector;
     private boolean mDockedStackMinimized;
     private boolean mHomeStackResizable;
     private boolean mAdjustedForIme;
@@ -295,21 +293,6 @@
                 landscape ? TYPE_HORIZONTAL_DOUBLE_ARROW : TYPE_VERTICAL_DOUBLE_ARROW));
         getViewTreeObserver().addOnComputeInternalInsetsListener(this);
         mHandle.setAccessibilityDelegate(mHandleDelegate);
-        mGestureDetector = new GestureDetector(mContext, new SimpleOnGestureListener() {
-            @Override
-            public boolean onSingleTapUp(MotionEvent e) {
-                if (SWAPPING_ENABLED) {
-                    updateDockSide();
-                    SystemServicesProxy ssp = Recents.getSystemServices();
-                    if (mDockSide != WindowManager.DOCKED_INVALID
-                            && !ssp.isRecentsActivityVisible()) {
-                        mWindowManagerProxy.swapTasks();
-                        return true;
-                    }
-                }
-                return false;
-            }
-        });
     }
 
     @Override
@@ -478,7 +461,6 @@
     @Override
     public boolean onTouch(View v, MotionEvent event) {
         convertToScreenCoordinates(event);
-        mGestureDetector.onTouchEvent(event);
         final int action = event.getAction() & MotionEvent.ACTION_MASK;
         switch (action) {
             case MotionEvent.ACTION_DOWN:
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
index c245126..185f6e3 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -120,17 +120,6 @@
         }
     };
 
-    private final Runnable mSwapRunnable = new Runnable() {
-        @Override
-        public void run() {
-            try {
-                ActivityManager.getService().swapDockedAndFullscreenStack();
-            } catch (RemoteException e) {
-                Log.w(TAG, "Failed to resize stack: " + e);
-            }
-        }
-    };
-
     private final Runnable mSetTouchableRegionRunnable = new Runnable() {
         @Override
         public void run() {
@@ -218,10 +207,6 @@
         mExecutor.execute(mDimLayerRunnable);
     }
 
-    public void swapTasks() {
-        mExecutor.execute(mSwapRunnable);
-    }
-
     public void setTouchRegion(Rect region) {
         synchronized (mDockedRect) {
             mTouchableRegion.set(region);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
index 7e08d56..9d2d71e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
@@ -15,6 +15,12 @@
  */
 package com.android.systemui.statusbar.car;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+
 import android.app.ActivityManager.StackId;
 import android.content.Context;
 import android.content.Intent;
@@ -117,7 +123,8 @@
         // Set up the persistent docked task if needed.
         if (mPersistentTaskIntent != null && !mStatusBar.hasDockedTask()
                 && stackId != StackId.HOME_STACK_ID) {
-            mStatusBar.startActivityOnStack(mPersistentTaskIntent, StackId.DOCKED_STACK_ID);
+            mStatusBar.startActivityOnStack(mPersistentTaskIntent,
+                    WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED);
         }
     }
 
@@ -375,13 +382,15 @@
         // rather than the "preferred/last run" app.
         intent.putExtra(EXTRA_FACET_LAUNCH_PICKER, index == mCurrentFacetIndex);
 
-        int stackId = StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+        int windowingMode = WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
+        int activityType = ACTIVITY_TYPE_UNDEFINED;
         if (intent.getCategories().contains(Intent.CATEGORY_HOME)) {
-            stackId = StackId.HOME_STACK_ID;
+            windowingMode = WINDOWING_MODE_UNDEFINED;
+            activityType = ACTIVITY_TYPE_HOME;
         }
 
         setCurrentFacet(index);
-        mStatusBar.startActivityOnStack(intent, stackId);
+        mStatusBar.startActivityOnStack(intent, windowingMode, activityType);
     }
 
     /**
@@ -391,6 +400,7 @@
      */
     private void onFacetLongClicked(Intent intent, int index) {
         setCurrentFacet(index);
-        mStatusBar.startActivityOnStack(intent, StackId.FULLSCREEN_WORKSPACE_STACK_ID);
+        mStatusBar.startActivityOnStack(intent,
+                WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_UNDEFINED);
     }
 }
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 680f693..10fc496 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -378,9 +378,10 @@
         return result;
     }
 
-    public int startActivityOnStack(Intent intent, int stackId) {
-        ActivityOptions options = ActivityOptions.makeBasic();
-        options.setLaunchStackId(stackId);
+    public int startActivityOnStack(Intent intent, int windowingMode, int activityType) {
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchWindowingMode(windowingMode);
+        options.setLaunchActivityType(activityType);
         return startActivityWithOptions(intent, options.toBundle());
     }
 
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 200cada..4739a2e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -20,6 +20,7 @@
 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
 import static android.app.StatusBarManager.windowStateToString;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
@@ -37,7 +38,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
-import android.app.ActivityManager.StackId;
 import android.app.ActivityOptions;
 import android.app.INotificationManager;
 import android.app.KeyguardManager;
@@ -1057,6 +1057,7 @@
         mNotificationData.setHeadsUpManager(mHeadsUpManager);
         mGroupManager.setHeadsUpManager(mHeadsUpManager);
         mHeadsUpManager.setVisualStabilityManager(mVisualStabilityManager);
+        putComponent(HeadsUpManager.class, mHeadsUpManager);
 
         if (MULTIUSER_DEBUG) {
             mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById(
@@ -5931,7 +5932,7 @@
         private boolean superOnClickHandler(View view, PendingIntent pendingIntent,
                 Intent fillInIntent) {
             return super.onClickHandler(view, pendingIntent, fillInIntent,
-                    StackId.FULLSCREEN_WORKSPACE_STACK_ID);
+                    WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
         }
 
         private boolean handleRemoteInput(View view, PendingIntent pendingIntent, Intent fillInIntent) {
@@ -7148,10 +7149,10 @@
     }
 
     protected Bundle getActivityOptions() {
-        // Anything launched from the notification shade should always go into the
-        // fullscreen stack.
-        ActivityOptions options = ActivityOptions.makeBasic();
-        options.setLaunchStackId(StackId.FULLSCREEN_WORKSPACE_STACK_ID);
+        // Anything launched from the notification shade should always go into the secondary
+        // split-screen windowing mode.
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
         return options.toBundle();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index bb7b197..b7e6a40 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -16,44 +16,6 @@
 
 package com.android.systemui.statusbar.policy;
 
-import android.content.Intent;
-import android.net.ConnectivityManager;
-import android.net.NetworkCapabilities;
-import android.net.wifi.WifiManager;
-import android.os.Looper;
-import android.provider.Settings;
-import android.provider.Settings.Global;
-import android.telephony.PhoneStateListener;
-import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
-import android.telephony.SubscriptionInfo;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-import com.android.internal.telephony.cdma.EriInfo;
-import com.android.settingslib.net.DataUsageController;
-import com.android.systemui.statusbar.phone.SignalDrawable;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
-import com.android.systemui.statusbar.policy.NetworkController.IconState;
-import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
-import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
-import com.android.systemui.statusbar.policy.NetworkControllerImpl.SubscriptionDefaults;
-import com.android.systemui.SysuiTestCase;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.rules.TestWatcher;
-import org.junit.runner.Description;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mockito;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.List;
-
 import static junit.framework.Assert.assertEquals;
 
 import static org.mockito.Matchers.any;
@@ -65,6 +27,43 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import android.content.Intent;
+import android.net.ConnectivityManager;
+import android.net.NetworkCapabilities;
+import android.net.wifi.WifiManager;
+import android.provider.Settings;
+import android.provider.Settings.Global;
+import android.telephony.PhoneStateListener;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.testing.TestableLooper;
+import android.util.Log;
+
+import com.android.internal.telephony.cdma.EriInfo;
+import com.android.settingslib.net.DataUsageController;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.phone.SignalDrawable;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
+import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
+import com.android.systemui.statusbar.policy.NetworkControllerImpl.SubscriptionDefaults;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+
 public class NetworkControllerBaseTest extends SysuiTestCase {
     private static final String TAG = "NetworkControllerBaseTest";
     protected static final int DEFAULT_LEVEL = 2;
@@ -131,11 +130,12 @@
             mUserCallback = (DeviceProvisionedListener) invocation.getArguments()[0];
             mUserCallback.onUserSetupChanged();
             mUserCallback.onDeviceProvisionedChanged();
+            TestableLooper.get(this).processAllMessages();
             return null;
         }).when(mMockProvisionController).addCallback(any());
 
         mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm,
-                mConfig, Looper.getMainLooper(), mCallbackHandler,
+                mConfig, TestableLooper.get(this).getLooper(), mCallbackHandler,
                 mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
                 mMockSubDefaults, mMockProvisionController);
         setupNetworkController();
@@ -176,7 +176,7 @@
       when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false);
       NetworkControllerImpl networkControllerNoMobile
               = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm,
-                        mConfig, mContext.getMainLooper(), mCallbackHandler,
+                        mConfig, TestableLooper.get(this).getLooper(), mCallbackHandler,
                         mock(AccessPointControllerImpl.class),
                         mock(DataUsageController.class), mMockSubDefaults,
                         mock(DeviceProvisionedController.class));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index 0313a43..1419e9a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -9,6 +9,9 @@
 import android.support.test.runner.AndroidJUnit4;
 import android.telephony.TelephonyManager;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
 
 import com.android.settingslib.net.DataUsageController;
 
@@ -16,7 +19,8 @@
 import org.junit.runner.RunWith;
 
 @SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
 public class NetworkControllerDataTest extends NetworkControllerBaseTest {
 
     @Test
@@ -126,6 +130,7 @@
         setConnectivity(NetworkCapabilities.TRANSPORT_CELLULAR, false, false);
         when(mMockProvisionController.isUserSetup(anyInt())).thenReturn(false);
         mUserCallback.onUserSetupChanged();
+        TestableLooper.get(this).processAllMessages();
 
         // Don't show the X until the device is setup.
         verifyDataIndicators(0, 0);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerEthernetTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerEthernetTest.java
index 9ac51b6..d2d7347 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerEthernetTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerEthernetTest.java
@@ -3,6 +3,8 @@
 import android.net.NetworkCapabilities;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
 
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
 
@@ -14,7 +16,8 @@
 import static junit.framework.Assert.assertEquals;
 
 @SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
 public class NetworkControllerEthernetTest extends NetworkControllerBaseTest {
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
index b353f5a..3ad107c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
@@ -25,6 +25,8 @@
 import android.telephony.SubscriptionInfo;
 import android.telephony.TelephonyManager;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
 
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
@@ -46,7 +48,8 @@
 import static org.mockito.Mockito.mock;
 
 @SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
 public class NetworkControllerSignalTest extends NetworkControllerBaseTest {
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
index ffd0165..4c18f8d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
@@ -7,6 +7,8 @@
 import android.net.wifi.WifiManager;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
 
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
 
@@ -21,7 +23,8 @@
 import static org.mockito.Matchers.anyBoolean;
 
 @SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
 public class NetworkControllerWifiTest extends NetworkControllerBaseTest {
     // These match the constants in WifiManager and need to be kept up to date.
     private static final int MIN_RSSI = -100;
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 0730270..523e6b2 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -4610,6 +4610,11 @@
     // OS: P
     DIALOG_ENABLE_DEVELOPMENT_OPTIONS = 1158;
 
+    // OPEN: Settings > Developer options > OEM unlocking > Info dialog
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_ENABLE_OEM_UNLOCKING = 1159;
+
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
   }
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 77ce871..7212b23 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -638,7 +638,7 @@
 
     void destroySessionsLocked() {
         if (mSessions.size() == 0) {
-            mUi.destroyAll(null, null);
+            mUi.destroyAll(null, null, false);
             return;
         }
         while (mSessions.size() > 0) {
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index f315148..af55807 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -578,9 +578,8 @@
         public void run() {
             synchronized (mLock) {
                 if (isCancelledLocked()) {
-                    // TODO(b/653742740): we should probably return here, but for now we're justing
-                    // logging to confirm this is the problem if it happens again.
-                    Slog.e(LOG_TAG, "run() called after canceled: " + mRequest);
+                    if (sDebug) Slog.d(LOG_TAG, "run() called after canceled: " + mRequest);
+                    return;
                 }
             }
             final RemoteFillService remoteService = getService();
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 09ecdd5..ed3441f 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -471,7 +471,7 @@
         if ((response.getDatasets() == null || response.getDatasets().isEmpty())
                         && response.getAuthentication() == null) {
             // Response is "empty" from an UI point of view, need to notify client.
-            notifyUnavailableToClient();
+            notifyUnavailableToClient(false);
         }
         synchronized (mLock) {
             processResponseLocked(response, requestFlags);
@@ -572,6 +572,10 @@
     // FillServiceCallbacks
     @Override
     public void authenticate(int requestId, int datasetIndex, IntentSender intent, Bundle extras) {
+        if (sDebug) {
+            Slog.d(TAG, "authenticate(): requestId=" + requestId + "; datasetIdx=" + datasetIndex
+                    + "; intentSender=" + intent);
+        }
         final Intent fillInIntent;
         synchronized (mLock) {
             if (mDestroyed) {
@@ -580,6 +584,10 @@
                 return;
             }
             fillInIntent = createAuthFillInIntentLocked(requestId, extras);
+            if (fillInIntent == null) {
+                forceRemoveSelfLocked();
+                return;
+            }
         }
 
         mService.setAuthenticationSelected(id, mClientState);
@@ -1361,11 +1369,15 @@
         }
     }
 
-    private void notifyUnavailableToClient() {
+    private void notifyUnavailableToClient(boolean sessionFinished) {
         synchronized (mLock) {
-            if (!mHasCallback || mCurrentViewId == null) return;
+            if (mCurrentViewId == null) return;
             try {
-                mClient.notifyNoFillUi(id, mCurrentViewId);
+                if (mHasCallback) {
+                    mClient.notifyNoFillUi(id, mCurrentViewId, sessionFinished);
+                } else if (sessionFinished) {
+                    mClient.setSessionFinished();
+                }
             } catch (RemoteException e) {
                 Slog.e(TAG, "Error notifying client no fill UI: id=" + mCurrentViewId, e);
             }
@@ -1453,7 +1465,7 @@
         }
         mService.resetLastResponse();
         // Nothing to be done, but need to notify client.
-        notifyUnavailableToClient();
+        notifyUnavailableToClient(true);
         removeSelf();
     }
 
@@ -1572,6 +1584,10 @@
     }
 
     void autoFill(int requestId, int datasetIndex, Dataset dataset, boolean generateEvent) {
+        if (sDebug) {
+            Slog.d(TAG, "autoFill(): requestId=" + requestId  + "; datasetIdx=" + datasetIndex
+                    + "; dataset=" + dataset);
+        }
         synchronized (mLock) {
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#autoFill() rejected - session: "
@@ -1592,10 +1608,14 @@
             mService.logDatasetAuthenticationSelected(dataset.getId(), id, mClientState);
             setViewStatesLocked(null, dataset, ViewState.STATE_WAITING_DATASET_AUTH, false);
             final Intent fillInIntent = createAuthFillInIntentLocked(requestId, mClientState);
-
+            if (fillInIntent == null) {
+                forceRemoveSelfLocked();
+                return;
+            }
             final int authenticationId = AutofillManager.makeAuthenticationId(requestId,
                     datasetIndex);
             startAuthentication(authenticationId, dataset.getAuthentication(), fillInIntent);
+
         }
     }
 
@@ -1605,14 +1625,16 @@
         }
     }
 
+    // TODO: this should never be null, but we got at least one occurrence, probably due to a race.
+    @Nullable
     private Intent createAuthFillInIntentLocked(int requestId, Bundle extras) {
         final Intent fillInIntent = new Intent();
 
         final FillContext context = getFillContextByRequestIdLocked(requestId);
         if (context == null) {
-            // TODO(b/653742740): this will crash system_server. We need to handle it, but we're
-            // keeping it crashing for now so we can diagnose when it happens again
-            Slog.wtf(TAG, "no FillContext for requestId" + requestId + "; mContexts= " + mContexts);
+            Slog.wtf(TAG, "createAuthFillInIntentLocked(): no FillContext. requestId=" + requestId
+                    + "; mContexts= " + mContexts);
+            return null;
         }
         fillInIntent.putExtra(AutofillManager.EXTRA_ASSIST_STRUCTURE, context.getStructure());
         fillInIntent.putExtra(AutofillManager.EXTRA_CLIENT_STATE, extras);
@@ -1759,7 +1781,7 @@
         if (mDestroyed) {
             return null;
         }
-        mUi.destroyAll(mPendingSaveUi, this);
+        mUi.destroyAll(mPendingSaveUi, this, true);
         mUi.clearCallback(this);
         mDestroyed = true;
         writeLog(MetricsEvent.AUTOFILL_SESSION_FINISHED);
@@ -1775,7 +1797,16 @@
 
         mPendingSaveUi = null;
         removeSelfLocked();
-        mUi.destroyAll(mPendingSaveUi, this);
+
+        mHandlerCaller.getHandler().post(() -> {
+            try {
+                mClient.setState(mService.isEnabled(), true, false);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "error updating client state: " + e);
+            }
+        });
+
+        mUi.destroyAll(mPendingSaveUi, this, false);
     }
 
     /**
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index 434b590..36b95fc 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -275,7 +275,7 @@
                     if (mCallback != null) {
                         mCallback.save();
                     }
-                    destroySaveUiUiThread(pendingSaveUi);
+                    destroySaveUiUiThread(pendingSaveUi, true);
                 }
 
                 @Override
@@ -293,7 +293,7 @@
                     if (mCallback != null) {
                         mCallback.cancelSave();
                     }
-                    destroySaveUiUiThread(pendingSaveUi);
+                    destroySaveUiUiThread(pendingSaveUi, true);
                 }
 
                 @Override
@@ -335,8 +335,8 @@
      * Destroy all UI affordances.
      */
     public void destroyAll(@Nullable PendingUi pendingSaveUi,
-            @Nullable AutoFillUiCallback callback) {
-        mHandler.post(() -> destroyAllUiThread(pendingSaveUi, callback));
+            @Nullable AutoFillUiCallback callback, boolean notifyClient) {
+        mHandler.post(() -> destroyAllUiThread(pendingSaveUi, callback, notifyClient));
     }
 
     public void dump(PrintWriter pw) {
@@ -379,7 +379,7 @@
     }
 
     @android.annotation.UiThread
-    private void destroySaveUiUiThread(@Nullable PendingUi pendingSaveUi) {
+    private void destroySaveUiUiThread(@Nullable PendingUi pendingSaveUi, boolean notifyClient) {
         if (mSaveUi == null) {
             // Calling destroySaveUiUiThread() twice is normal - it usually happens when the
             // first call is made after the SaveUI is hidden and the second when the session is
@@ -391,7 +391,7 @@
         if (sDebug) Slog.d(TAG, "destroySaveUiUiThread(): " + pendingSaveUi);
         mSaveUi.destroy();
         mSaveUi = null;
-        if (pendingSaveUi != null) {
+        if (pendingSaveUi != null && notifyClient) {
             try {
                 if (sDebug) Slog.d(TAG, "destroySaveUiUiThread(): notifying client");
                 pendingSaveUi.client.setSaveUiState(pendingSaveUi.id, false);
@@ -403,9 +403,9 @@
 
     @android.annotation.UiThread
     private void destroyAllUiThread(@Nullable PendingUi pendingSaveUi,
-            @Nullable AutoFillUiCallback callback) {
+            @Nullable AutoFillUiCallback callback, boolean notifyClient) {
         hideFillUiUiThread(callback);
-        destroySaveUiUiThread(pendingSaveUi);
+        destroySaveUiUiThread(pendingSaveUi, notifyClient);
     }
 
     @android.annotation.UiThread
@@ -417,7 +417,7 @@
                 Slog.d(TAG, "hideAllUiThread(): "
                         + "destroying Save UI because pending restoration is finished");
             }
-            destroySaveUiUiThread(pendingSaveUi);
+            destroySaveUiUiThread(pendingSaveUi, true);
         }
     }
 }
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index e0cde72..90ad8a5 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2162,6 +2162,15 @@
             }
         }
 
+        if (r.fgRequired) {
+            if (DEBUG_FOREGROUND_SERVICE) {
+                Slog.v(TAG, "Whitelisting " + UserHandle.formatUid(r.appInfo.uid)
+                        + " for fg-service launch");
+            }
+            mAm.tempWhitelistUidLocked(r.appInfo.uid,
+                    SERVICE_START_FOREGROUND_TIMEOUT, "fg-service-launch");
+        }
+
         if (!mPendingServices.contains(r)) {
             mPendingServices.add(r);
         }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c571ec4..5d200ae 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -709,7 +709,7 @@
 
     public boolean canShowErrorDialogs() {
         return mShowDialogs && !mSleeping && !mShuttingDown
-                && !mKeyguardController.isKeyguardShowing()
+                && !mKeyguardController.isKeyguardShowing(DEFAULT_DISPLAY)
                 && !(UserManager.isDeviceInDemoMode(mContext)
                         && mUserController.getCurrentUser().isDemo());
     }
@@ -9957,7 +9957,7 @@
             enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
                     "getTaskDescription()");
             final TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(id,
-                    MATCH_TASK_IN_STACKS_OR_RECENT_TASKS, INVALID_STACK_ID);
+                    MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
             if (tr != null) {
                 return tr.lastTaskDescription;
             }
@@ -10070,7 +10070,7 @@
     public void setTaskResizeable(int taskId, int resizeableMode) {
         synchronized (this) {
             final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(
-                    taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS, INVALID_STACK_ID);
+                    taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
             if (task == null) {
                 Slog.w(TAG, "setTaskResizeable: taskId=" + taskId + " not found");
                 return;
@@ -10133,7 +10133,7 @@
         try {
             synchronized (this) {
                 final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId,
-                        MATCH_TASK_IN_STACKS_OR_RECENT_TASKS, INVALID_STACK_ID);
+                        MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
                 if (task == null) {
                     Slog.w(TAG, "getTaskBounds: taskId=" + taskId + " not found");
                     return rect;
@@ -10165,7 +10165,7 @@
         try {
             synchronized (this) {
                 final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId,
-                        MATCH_TASK_IN_STACKS_ONLY, INVALID_STACK_ID);
+                        MATCH_TASK_IN_STACKS_ONLY);
                 if (task == null) {
                     Slog.w(TAG, "cancelTaskWindowTransition: taskId=" + taskId + " not found");
                     return;
@@ -10184,7 +10184,7 @@
         try {
             synchronized (this) {
                 final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId,
-                        MATCH_TASK_IN_STACKS_ONLY, INVALID_STACK_ID);
+                        MATCH_TASK_IN_STACKS_ONLY);
                 if (task == null) {
                     Slog.w(TAG, "cancelTaskThumbnailTransition: taskId=" + taskId + " not found");
                     return;
@@ -10204,7 +10204,7 @@
             final TaskRecord task;
             synchronized (this) {
                 task = mStackSupervisor.anyTaskForIdLocked(taskId,
-                        MATCH_TASK_IN_STACKS_OR_RECENT_TASKS, INVALID_STACK_ID);
+                        MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
                 if (task == null) {
                     Slog.w(TAG, "getTaskSnapshot: taskId=" + taskId + " not found");
                     return null;
@@ -10518,56 +10518,6 @@
         }
     }
 
-    @Override
-    public void swapDockedAndFullscreenStack() throws RemoteException {
-        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "swapDockedAndFullscreenStack()");
-        synchronized (this) {
-            long ident = Binder.clearCallingIdentity();
-            try {
-                final ActivityStack fullscreenStack = mStackSupervisor.getStack(
-                        FULLSCREEN_WORKSPACE_STACK_ID);
-                final TaskRecord topTask = fullscreenStack != null ? fullscreenStack.topTask()
-                        : null;
-                final ActivityStack dockedStack = mStackSupervisor.getStack(DOCKED_STACK_ID);
-                final ArrayList<TaskRecord> tasks = dockedStack != null ? dockedStack.getAllTasks()
-                        : null;
-                if (topTask == null || tasks == null || tasks.size() == 0) {
-                    Slog.w(TAG,
-                            "Unable to swap tasks, either docked or fullscreen stack is empty.");
-                    return;
-                }
-
-                // TODO: App transition
-                mWindowManager.prepareAppTransition(TRANSIT_ACTIVITY_RELAUNCH, false);
-
-                // Defer the resume until we move all the docked tasks to the fullscreen stack below
-                topTask.reparent(DOCKED_STACK_ID, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE,
-                        DEFER_RESUME, "swapDockedAndFullscreenStack - DOCKED_STACK");
-                final int size = tasks.size();
-                for (int i = 0; i < size; i++) {
-                    final int id = tasks.get(i).taskId;
-                    if (id == topTask.taskId) {
-                        continue;
-                    }
-
-                    // Defer the resume until after all the tasks have been moved
-                    tasks.get(i).reparent(FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP,
-                            REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, DEFER_RESUME,
-                            "swapDockedAndFullscreenStack - FULLSCREEN_STACK");
-                }
-
-                // Because we deferred the resume to avoid conflicts with stack switches while
-                // resuming, we need to do it after all the tasks are moved.
-                mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
-                mStackSupervisor.resumeFocusedStackTopActivityLocked();
-
-                mWindowManager.executeAppTransition();
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
-        }
-    }
-
     /**
      * Moves the input task to the docked stack.
      *
@@ -12451,7 +12401,7 @@
     }
 
     @Override
-    public void setLockScreenShown(boolean showing) {
+    public void setLockScreenShown(boolean showing, int secondaryDisplayShowing) {
         if (checkCallingPermission(android.Manifest.permission.DEVICE_POWER)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Requires permission "
@@ -12461,7 +12411,7 @@
         synchronized(this) {
             long ident = Binder.clearCallingIdentity();
             try {
-                mKeyguardController.setKeyguardShown(showing);
+                mKeyguardController.setKeyguardShown(showing, secondaryDisplayShowing);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -23878,7 +23828,7 @@
         @Override
         public void notifyKeyguardTrustedChanged() {
             synchronized (ActivityManagerService.this) {
-                if (mKeyguardController.isKeyguardShowing()) {
+                if (mKeyguardController.isKeyguardShowing(DEFAULT_DISPLAY)) {
                     mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
                 }
             }
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 6901d2d..0aca9ea 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -75,6 +75,8 @@
 import static android.app.ActivityManager.RESIZE_MODE_USER;
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.view.Display.INVALID_DISPLAY;
 
 import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
@@ -115,7 +117,8 @@
     private boolean mStreaming;   // Streaming the profiling output to a file.
     private String mAgent;  // Agent to attach on startup.
     private int mDisplayId;
-    private int mStackId;
+    private int mWindowingMode;
+    private int mActivityType;
     private int mTaskId;
     private boolean mIsTaskOverlay;
 
@@ -271,7 +274,8 @@
         mStreaming = false;
         mUserId = defUser;
         mDisplayId = INVALID_DISPLAY;
-        mStackId = INVALID_STACK_ID;
+        mWindowingMode = WINDOWING_MODE_UNDEFINED;
+        mActivityType = ACTIVITY_TYPE_UNDEFINED;
         mTaskId = INVALID_TASK_ID;
         mIsTaskOverlay = false;
 
@@ -308,8 +312,10 @@
                     mReceiverPermission = getNextArgRequired();
                 } else if (opt.equals("--display")) {
                     mDisplayId = Integer.parseInt(getNextArgRequired());
-                } else if (opt.equals("--stack")) {
-                    mStackId = Integer.parseInt(getNextArgRequired());
+                } else if (opt.equals("--windowingMode")) {
+                    mWindowingMode = Integer.parseInt(getNextArgRequired());
+                } else if (opt.equals("--activityType")) {
+                    mActivityType = Integer.parseInt(getNextArgRequired());
                 } else if (opt.equals("--task")) {
                     mTaskId = Integer.parseInt(getNextArgRequired());
                 } else if (opt.equals("--task-overlay")) {
@@ -396,9 +402,17 @@
                 options = ActivityOptions.makeBasic();
                 options.setLaunchDisplayId(mDisplayId);
             }
-            if (mStackId != INVALID_STACK_ID) {
-                options = ActivityOptions.makeBasic();
-                options.setLaunchStackId(mStackId);
+            if (mWindowingMode != WINDOWING_MODE_UNDEFINED) {
+                if (options == null) {
+                    options = ActivityOptions.makeBasic();
+                }
+                options.setLaunchWindowingMode(mWindowingMode);
+            }
+            if (mActivityType != ACTIVITY_TYPE_UNDEFINED) {
+                if (options == null) {
+                    options = ActivityOptions.makeBasic();
+                }
+                options.setLaunchActivityType(mActivityType);
             }
             if (mTaskId != INVALID_TASK_ID) {
                 options = ActivityOptions.makeBasic();
@@ -2685,7 +2699,8 @@
             pw.println("      --track-allocation: enable tracking of object allocations");
             pw.println("      --user <USER_ID> | current: Specify which user to run as; if not");
             pw.println("          specified then run as the current user.");
-            pw.println("      --stack <STACK_ID>: Specify into which stack should the activity be put.");
+            pw.println("      --windowingMode <WINDOWING_MODE>: The windowing mode to launch the activity into.");
+            pw.println("      --activityType <ACTIVITY_TYPE>: The activity type to launch the activity as.");
             pw.println("  start-service [--user <USER_ID> | current] <INTENT>");
             pw.println("      Start a Service.  Options are:");
             pw.println("      --user <USER_ID> | current: Specify which user to run as; if not");
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 0ccb45f..4908233 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -17,7 +17,6 @@
 package com.android.server.am;
 
 import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
-import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID;
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
@@ -36,7 +35,6 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.activityTypeToString;
 import static android.content.Intent.ACTION_MAIN;
@@ -89,10 +87,8 @@
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SAVED_STATE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SCREENSHOTS;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STATES;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_THUMBNAILS;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -1038,7 +1034,7 @@
             }
         } else if (realActivity.getClassName().contains(RECENTS_PACKAGE_NAME)) {
             activityType = ACTIVITY_TYPE_RECENTS;
-        } else if (options != null && options.getLaunchStackId() == ASSISTANT_STACK_ID
+        } else if (options != null && options.getLaunchActivityType() == ACTIVITY_TYPE_ASSISTANT
                 && canLaunchAssistActivity(launchedFromPackage)) {
             activityType = ACTIVITY_TYPE_ASSISTANT;
         }
@@ -1157,8 +1153,15 @@
      *         can be put a secondary screen.
      */
     boolean canBeLaunchedOnDisplay(int displayId) {
+        final TaskRecord task = getTask();
+
+        // The resizeability of an Activity's parent task takes precendence over the ActivityInfo.
+        // This allows for a non resizable activity to be launched into a resizeable task.
+        final boolean resizeable =
+                task != null ? task.isResizeable() : supportsResizeableMultiWindow();
+
         return service.mStackSupervisor.canPlaceEntityOnDisplay(displayId,
-                supportsResizeableMultiWindow(), launchedFromPid, launchedFromUid, info);
+                resizeable, launchedFromPid, launchedFromUid, info);
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index a6a702f..6140c26 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1962,7 +1962,8 @@
     boolean checkKeyguardVisibility(ActivityRecord r, boolean shouldBeVisible,
             boolean isTop) {
         final boolean isInPinnedStack = r.getStack().getStackId() == PINNED_STACK_ID;
-        final boolean keyguardShowing = mStackSupervisor.mKeyguardController.isKeyguardShowing();
+        final boolean keyguardShowing = mStackSupervisor.mKeyguardController.isKeyguardShowing(
+                mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY);
         final boolean keyguardLocked = mStackSupervisor.mKeyguardController.isKeyguardLocked();
         final boolean showWhenLocked = r.canShowWhenLocked() && !isInPinnedStack;
         final boolean dismissKeyguard = r.hasDismissKeyguardWindows();
@@ -5194,8 +5195,8 @@
                 voiceInteractor);
         // add the task to stack first, mTaskPositioner might need the stack association
         addTask(task, toTop, "createTaskRecord");
-        final boolean isLockscreenShown =
-                mService.mStackSupervisor.mKeyguardController.isKeyguardShowing();
+        final boolean isLockscreenShown = mService.mStackSupervisor.mKeyguardController
+                .isKeyguardShowing(mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY);
         if (!layoutTaskInStack(task, info.windowLayout) && mBounds != null && task.isResizeable()
                 && !isLockscreenShown) {
             task.updateOverrideConfiguration(mBounds);
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index c8a2a23..ffe5fd4 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -21,6 +21,7 @@
 import static android.Manifest.permission.START_ANY_ACTIVITY;
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
 import static android.app.ActivityManager.START_TASK_TO_FRONT;
+import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID;
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
 import static android.app.ActivityManager.StackId.FIRST_STATIC_STACK_ID;
@@ -31,13 +32,20 @@
 import static android.app.ActivityManager.StackId.LAST_STATIC_STACK_ID;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
+import static android.app.ActivityManager.StackId.getStackIdForActivityType;
+import static android.app.ActivityManager.StackId.getStackIdForWindowingMode;
 import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY;
 import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.pm.PackageManager.PERMISSION_DENIED;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
@@ -83,6 +91,7 @@
 import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING;
 import static com.android.server.am.ActivityStack.STACK_INVISIBLE;
 import static com.android.server.am.ActivityStack.STACK_VISIBLE;
+import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
 import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
@@ -94,6 +103,7 @@
 import android.Manifest;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.Activity;
 import android.app.ActivityManager;
@@ -707,24 +717,26 @@
     }
 
     TaskRecord anyTaskForIdLocked(int id) {
-        return anyTaskForIdLocked(id, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE,
-                INVALID_STACK_ID);
+        return anyTaskForIdLocked(id, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE);
+    }
+
+    TaskRecord anyTaskForIdLocked(int id, @AnyTaskForIdMatchTaskMode int matchMode) {
+        return anyTaskForIdLocked(id, matchMode, null);
     }
 
     /**
      * Returns a {@link TaskRecord} for the input id if available. {@code null} otherwise.
      * @param id Id of the task we would like returned.
      * @param matchMode The mode to match the given task id in.
-     * @param stackId The stack to restore the task to (default launch stack will be used if
-     *                stackId is {@link android.app.ActivityManager.StackId#INVALID_STACK_ID}). Only
-     *                valid if the matchMode is
-     *                {@link #MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE}.
+     * @param aOptions The activity options to use for restoration. Can be null.
      */
-    TaskRecord anyTaskForIdLocked(int id, @AnyTaskForIdMatchTaskMode int matchMode, int stackId) {
+    TaskRecord anyTaskForIdLocked(int id, @AnyTaskForIdMatchTaskMode int matchMode,
+            @Nullable ActivityOptions aOptions) {
         // If there is a stack id set, ensure that we are attempting to actually restore a task
-        if (matchMode != MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE &&
-                stackId != INVALID_STACK_ID) {
-            throw new IllegalArgumentException("Should not specify stackId for non-restore lookup");
+        // TODO: Don't really know if this is needed...
+        if (matchMode != MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE && aOptions != null) {
+            throw new IllegalArgumentException("Should not specify activity options for non-restore"
+                    + " lookup");
         }
 
         int numDisplays = mActivityDisplays.size();
@@ -762,7 +774,7 @@
         }
 
         // Implicitly, this case is MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE
-        if (!restoreRecentTaskLocked(task, stackId)) {
+        if (!restoreRecentTaskLocked(task, aOptions)) {
             if (DEBUG_RECENTS) Slog.w(TAG_RECENTS,
                     "Couldn't restore task id=" + id + " found in recents");
             return null;
@@ -857,8 +869,8 @@
         // was 10, user 0 could only have taskIds 0 to 9, user 1: 10 to 19, user 2: 20 to 29, so on.
         int candidateTaskId = nextTaskIdForUser(currentTaskId, userId);
         while (mRecentTasks.taskIdTakenForUserLocked(candidateTaskId, userId)
-                || anyTaskForIdLocked(candidateTaskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS,
-                        INVALID_STACK_ID) != null) {
+                || anyTaskForIdLocked(
+                        candidateTaskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS) != null) {
             candidateTaskId = nextTaskIdForUser(candidateTaskId, userId);
             if (candidateTaskId == currentTaskId) {
                 // Something wrong!
@@ -2084,38 +2096,35 @@
             // we'll just indicate that this task returns to the home task.
             task.setTaskToReturnTo(ACTIVITY_TYPE_HOME);
         }
-        ActivityStack currentStack = task.getStack();
+        final ActivityStack currentStack = task.getStack();
         if (currentStack == null) {
             Slog.e(TAG, "findTaskToMoveToFrontLocked: can't move task="
                     + task + " to front. Stack is null");
             return;
         }
 
-        if (task.isResizeable() && options != null) {
-            int stackId = options.getLaunchStackId();
-            if (canUseActivityOptionsLaunchBounds(options, stackId)) {
-                final Rect bounds = TaskRecord.validateBounds(options.getLaunchBounds());
-                task.updateOverrideConfiguration(bounds);
-                if (stackId == INVALID_STACK_ID) {
-                    stackId = task.getLaunchStackId();
-                }
-                if (stackId != currentStack.mStackId) {
-                    task.reparent(stackId, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE,
-                            DEFER_RESUME, "findTaskToMoveToFrontLocked");
-                    stackId = currentStack.mStackId;
-                    // moveTaskToStackUncheckedLocked() should already placed the task on top,
-                    // still need moveTaskToFrontLocked() below for any transition settings.
-                }
-                if (StackId.resizeStackWithLaunchBounds(stackId)) {
-                    resizeStackLocked(stackId, bounds,
-                            null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
-                            !PRESERVE_WINDOWS, true /* allowResizeInDockedMode */, !DEFER_RESUME);
-                } else {
-                    // WM resizeTask must be done after the task is moved to the correct stack,
-                    // because Task's setBounds() also updates dim layer's bounds, but that has
-                    // dependency on the stack.
-                    task.resizeWindowContainer();
-                }
+        if (task.isResizeable() && canUseActivityOptionsLaunchBounds(options)) {
+            final Rect bounds = TaskRecord.validateBounds(options.getLaunchBounds());
+            task.updateOverrideConfiguration(bounds);
+
+            int stackId = getLaunchStackId(null, options, task);
+
+            if (stackId != currentStack.mStackId) {
+                task.reparent(stackId, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE,
+                        DEFER_RESUME, "findTaskToMoveToFrontLocked");
+                stackId = currentStack.mStackId;
+                // moveTaskToStackUncheckedLocked() should already placed the task on top,
+                // still need moveTaskToFrontLocked() below for any transition settings.
+            }
+            if (StackId.resizeStackWithLaunchBounds(stackId)) {
+                resizeStackLocked(stackId, bounds,
+                        null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
+                        !PRESERVE_WINDOWS, true /* allowResizeInDockedMode */, !DEFER_RESUME);
+            } else {
+                // WM resizeTask must be done after the task is moved to the correct stack,
+                // because Task's setBounds() also updates dim layer's bounds, but that has
+                // dependency on the stack.
+                task.resizeWindowContainer();
             }
         }
 
@@ -2126,17 +2135,18 @@
         if (DEBUG_STACK) Slog.d(TAG_STACK,
                 "findTaskToMoveToFront: moved to front of stack=" + currentStack);
 
-        handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, DEFAULT_DISPLAY,
+        handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED, DEFAULT_DISPLAY,
                 currentStack.mStackId, forceNonResizeable);
     }
 
-    boolean canUseActivityOptionsLaunchBounds(ActivityOptions options, int launchStackId) {
+    boolean canUseActivityOptionsLaunchBounds(ActivityOptions options) {
         // We use the launch bounds in the activity options is the device supports freeform
         // window management or is launching into the pinned stack.
-        if (options.getLaunchBounds() == null) {
+        if (options == null || options.getLaunchBounds() == null) {
             return false;
         }
-        return (mService.mSupportsPictureInPicture && launchStackId == PINNED_STACK_ID)
+        return (mService.mSupportsPictureInPicture
+                && options.getLaunchWindowingMode() == WINDOWING_MODE_PINNED)
                 || mService.mSupportsFreeformWindowManagement;
     }
 
@@ -2161,6 +2171,179 @@
         return (T) createStackOnDisplay(stackId, DEFAULT_DISPLAY, createOnTop);
     }
 
+    private int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
+            @Nullable TaskRecord task) {
+
+        // First preference if the windowing mode in the activity options if set.
+        int windowingMode = (options != null)
+                ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
+
+        // If windowing mode is unset, then next preference is the candidate task, then the
+        // activity record.
+        if (windowingMode == WINDOWING_MODE_UNDEFINED) {
+            if (task != null) {
+                windowingMode = task.getWindowingMode();
+            }
+            if (windowingMode == WINDOWING_MODE_UNDEFINED && r != null) {
+                windowingMode = r.getWindowingMode();
+            }
+        }
+
+        // Make sure the windowing mode we are trying to use makes sense for what is supported.
+        if (!mService.mSupportsMultiWindow && windowingMode != WINDOWING_MODE_FULLSCREEN) {
+            windowingMode = WINDOWING_MODE_FULLSCREEN;
+        }
+
+        if (!mService.mSupportsSplitScreenMultiWindow
+                && (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+                || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY)) {
+            windowingMode = WINDOWING_MODE_FULLSCREEN;
+        }
+
+        if (windowingMode == WINDOWING_MODE_FREEFORM
+                && !mService.mSupportsFreeformWindowManagement) {
+            windowingMode = WINDOWING_MODE_FULLSCREEN;
+        }
+
+        return windowingMode;
+    }
+
+    private int resolveActivityType(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
+            @Nullable TaskRecord task) {
+        // First preference if the activity type in the activity options if set.
+        int activityType = (options != null)
+                ? options.getLaunchActivityType() : ACTIVITY_TYPE_UNDEFINED;
+
+        if (activityType != ACTIVITY_TYPE_UNDEFINED) {
+            return activityType;
+        }
+
+        // If activity type is unset, then next preference is the task, then the activity record.
+        if (task != null) {
+            activityType = task.getActivityType();
+        }
+        if (activityType == ACTIVITY_TYPE_UNDEFINED && r != null) {
+            activityType = r.getActivityType();
+        }
+        return activityType;
+    }
+
+    int getLaunchStackId(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
+            @Nullable TaskRecord candidateTask) {
+        return getLaunchStackId(r, options, candidateTask, INVALID_DISPLAY);
+    }
+
+    /**
+     * Returns the right stack to use for launching factoring in all the input parameters.
+     *
+     * @param r The activity we are trying to launch. Can be null.
+     * @param options The activity options used to the launch. Can be null.
+     * @param candidateTask The possible task the activity might be launched in. Can be null.
+     *
+     * @return The stack to use for the launch or INVALID_STACK_ID.
+     */
+    int getLaunchStackId(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
+            @Nullable TaskRecord candidateTask, int candidateDisplayId) {
+        int taskId = INVALID_TASK_ID;
+        int displayId = INVALID_DISPLAY;
+        //Rect bounds = null;
+
+        // We give preference to the launch preference in activity options.
+        if (options != null) {
+            taskId = options.getLaunchTaskId();
+            displayId = options.getLaunchDisplayId();
+            // TODO: Need to work this into the equation...
+            //bounds = options.getLaunchBounds();
+        }
+
+        // First preference for stack goes to the task Id set in the activity options. Use the stack
+        // associated with that if possible.
+        if (taskId != INVALID_TASK_ID) {
+            // Temporarily set the task id to invalid in case in re-entry.
+            options.setLaunchTaskId(INVALID_TASK_ID);
+            final TaskRecord task = anyTaskForIdLocked(taskId,
+                    MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, options);
+            options.setLaunchTaskId(taskId);
+            if (task != null) {
+                return task.getStack().mStackId;
+            }
+        }
+
+        final int windowingMode = resolveWindowingMode(r, options, candidateTask);
+        final int activityType = resolveActivityType(r, options, candidateTask);
+        ActivityStack stack = null;
+
+        // Next preference for stack goes to the display Id set in the activity options or the
+        // candidate display.
+        if (displayId == INVALID_DISPLAY) {
+            displayId = candidateDisplayId;
+        }
+        if (displayId != INVALID_DISPLAY) {
+            if (r != null) {
+                // TODO: This should also take in the windowing mode and activity type into account.
+                stack = getValidLaunchStackOnDisplay(displayId, r);
+                if (stack != null) {
+                    return stack.mStackId;
+                }
+            }
+            final ActivityDisplay display = getActivityDisplayOrCreateLocked(displayId);
+            if (display != null) {
+                for (int i = display.mStacks.size() - 1; i >= 0; --i) {
+                    stack = display.mStacks.get(i);
+                    if (stack.getWindowingMode() == windowingMode
+                            && stack.getActivityType() == activityType) {
+                        return stack.mStackId;
+                    }
+                }
+                // TODO: We should create the stack we want on the display at this point.
+            }
+        }
+
+        // Give preference to the stack and display of the input task and activity if they match the
+        // mode we want to launch into.
+        if (candidateTask != null) {
+            stack = candidateTask.getStack();
+        }
+        if (stack == null && r != null) {
+            stack = r.getStack();
+        }
+        if (stack != null) {
+            if (stack.getWindowingMode() == windowingMode
+                    && stack.getActivityType() == activityType) {
+                return stack.mStackId;
+            }
+            ActivityDisplay display = stack.getDisplay();
+
+            if (display != null) {
+                for (int i = display.mStacks.size() - 1; i >= 0; --i) {
+                    stack = display.mStacks.get(i);
+                    if (stack.getWindowingMode() == windowingMode
+                            && stack.getActivityType() == activityType) {
+                        return stack.mStackId;
+                    }
+                }
+            }
+        }
+
+        // Give preference to the type of activity we are trying to launch followed by the windowing
+        // mode.
+        int stackId = getStackIdForActivityType(activityType);
+        if (stackId != INVALID_STACK_ID) {
+            return stackId;
+        }
+        stackId = getStackIdForWindowingMode(windowingMode);
+        if (stackId != INVALID_STACK_ID) {
+            return stackId;
+        }
+
+        // Whatever...return some default for now.
+        if (candidateTask != null && candidateTask.mBounds != null
+                && mService.mSupportsFreeformWindowManagement) {
+            return FREEFORM_WORKSPACE_STACK_ID;
+        }
+        return FULLSCREEN_WORKSPACE_STACK_ID;
+    }
+
     /**
      * Get a topmost stack on the display, that is a valid launch stack for specified activity.
      * If there is no such stack, new dynamic stack can be created.
@@ -2178,7 +2361,7 @@
         // Return the topmost valid stack on the display.
         for (int i = activityDisplay.mStacks.size() - 1; i >= 0; --i) {
             final ActivityStack stack = activityDisplay.mStacks.get(i);
-            if (mService.mActivityStarter.isValidLaunchStackId(stack.mStackId, displayId, r)) {
+            if (isValidLaunchStackId(stack.mStackId, displayId, r)) {
                 return stack;
             }
         }
@@ -2186,7 +2369,7 @@
         // If there is no valid stack on the external display - check if new dynamic stack will do.
         if (displayId != Display.DEFAULT_DISPLAY) {
             final int newDynamicStackId = getNextStackId();
-            if (mService.mActivityStarter.isValidLaunchStackId(newDynamicStackId, displayId, r)) {
+            if (isValidLaunchStackId(newDynamicStackId, displayId, r)) {
                 return createStackOnDisplay(newDynamicStackId, displayId, true /*onTop*/);
             }
         }
@@ -2195,6 +2378,32 @@
         return null;
     }
 
+    boolean isValidLaunchStackId(int stackId, int displayId, ActivityRecord r) {
+        switch (stackId) {
+            case INVALID_STACK_ID:
+            case HOME_STACK_ID:
+                return false;
+            case FULLSCREEN_WORKSPACE_STACK_ID:
+                return true;
+            case FREEFORM_WORKSPACE_STACK_ID:
+                return r.supportsFreeform();
+            case DOCKED_STACK_ID:
+                return r.supportsSplitScreen();
+            case PINNED_STACK_ID:
+                return r.supportsPictureInPicture();
+            case RECENTS_STACK_ID:
+                return r.isActivityTypeRecents();
+            case ASSISTANT_STACK_ID:
+                return r.isActivityTypeAssistant();
+            default:
+                if (StackId.isDynamicStack(stackId)) {
+                    return r.canBeLaunchedOnDisplay(displayId);
+                }
+                Slog.e(TAG, "isValidLaunchStackId: Unexpected stackId=" + stackId);
+                return false;
+        }
+    }
+
     ArrayList<ActivityStack> getStacks() {
         ArrayList<ActivityStack> allStacks = new ArrayList<>();
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
@@ -2345,8 +2554,7 @@
         continueUpdateBounds(RECENTS_STACK_ID);
         for (int i = mResizingTasksDuringAnimation.size() - 1; i >= 0; i--) {
             final int taskId = mResizingTasksDuringAnimation.valueAt(i);
-            final TaskRecord task =
-                    anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_ONLY, INVALID_STACK_ID);
+            final TaskRecord task = anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_ONLY);
             if (task != null) {
                 task.setTaskDockedResizing(false);
             }
@@ -2641,8 +2849,7 @@
      */
     boolean removeTaskByIdLocked(int taskId, boolean killProcess, boolean removeFromRecents,
             boolean pauseImmediately) {
-        final TaskRecord tr = anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS,
-                INVALID_STACK_ID);
+        final TaskRecord tr = anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
         if (tr != null) {
             tr.removeTaskActivitiesLocked(pauseImmediately);
             cleanUpRemovedTaskLocked(tr, killProcess, removeFromRecents);
@@ -2741,23 +2948,11 @@
     /**
      * Restores a recent task to a stack
      * @param task The recent task to be restored.
-     * @param stackId The stack to restore the task to (default launch stack will be used
-     *                if stackId is {@link android.app.ActivityManager.StackId#INVALID_STACK_ID}
-     *                or is not a static stack).
+     * @param aOptions The activity options to use for restoration.
      * @return true if the task has been restored successfully.
      */
-    boolean restoreRecentTaskLocked(TaskRecord task, int stackId) {
-        if (!StackId.isStaticStack(stackId)) {
-            // If stack is not static (or stack id is invalid) - use the default one.
-            // This means that tasks that were on external displays will be restored on the
-            // primary display.
-            stackId = task.getLaunchStackId();
-        } else if (stackId == DOCKED_STACK_ID && !task.supportsSplitScreen()) {
-            // Preferred stack is the docked stack, but the task can't go in the docked stack.
-            // Put it in the fullscreen stack.
-            stackId = FULLSCREEN_WORKSPACE_STACK_ID;
-        }
-
+    boolean restoreRecentTaskLocked(TaskRecord task, ActivityOptions aOptions) {
+        final int stackId = getLaunchStackId(null, aOptions, task);
         final ActivityStack currentStack = task.getStack();
         if (currentStack != null) {
             // Task has already been restored once. See if we need to do anything more
@@ -2770,15 +2965,7 @@
             currentStack.removeTask(task, "restoreRecentTaskLocked", REMOVE_TASK_MODE_MOVING);
         }
 
-        final ActivityStack stack =
-                getStack(stackId, CREATE_IF_NEEDED, !ON_TOP);
-
-        if (stack == null) {
-            // What does this mean??? Not sure how we would get here...
-            if (DEBUG_RECENTS) Slog.v(TAG_RECENTS,
-                    "Unable to find/create stack to restore recent task=" + task);
-            return false;
-        }
+        final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, !ON_TOP);
 
         stack.addTask(task, false /* toTop */, "restoreRecentTask");
         // TODO: move call for creation here and other place into Stack.addTask()
@@ -4015,21 +4202,20 @@
         return list;
     }
 
-    void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredStackId,
+    void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredWindowingMode,
             int preferredDisplayId, int actualStackId) {
-        handleNonResizableTaskIfNeeded(task, preferredStackId, preferredDisplayId, actualStackId,
-                false /* forceNonResizable */);
+        handleNonResizableTaskIfNeeded(task, preferredWindowingMode, preferredDisplayId,
+                actualStackId, false /* forceNonResizable */);
     }
 
-    void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredStackId,
+    void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredWindowingMode,
             int preferredDisplayId, int actualStackId, boolean forceNonResizable) {
         final boolean isSecondaryDisplayPreferred =
-                (preferredDisplayId != DEFAULT_DISPLAY && preferredDisplayId != INVALID_DISPLAY)
-                || StackId.isDynamicStack(preferredStackId);
+                (preferredDisplayId != DEFAULT_DISPLAY && preferredDisplayId != INVALID_DISPLAY);
         final ActivityStack actualStack = getStack(actualStackId);
         final boolean inSplitScreenMode = actualStack != null
                 && actualStack.inSplitScreenWindowingMode();
-        if (((!inSplitScreenMode && preferredStackId != DOCKED_STACK_ID)
+        if (((!inSplitScreenMode && preferredWindowingMode != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)
                 && !isSecondaryDisplayPreferred) || task.isActivityTypeHome()) {
             return;
         }
@@ -4424,18 +4610,22 @@
         final String callingPackage;
         final Intent intent;
         final int userId;
+        int activityType = ACTIVITY_TYPE_UNDEFINED;
+        int windowingMode = WINDOWING_MODE_UNDEFINED;
         final ActivityOptions activityOptions = (bOptions != null)
                 ? new ActivityOptions(bOptions) : null;
-        final int launchStackId = (activityOptions != null)
-                ? activityOptions.getLaunchStackId() : INVALID_STACK_ID;
-        if (StackId.isHomeOrRecentsStack(launchStackId)) {
+        if (activityOptions != null) {
+            activityType = activityOptions.getLaunchActivityType();
+            windowingMode = activityOptions.getLaunchWindowingMode();
+        }
+        if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) {
             throw new IllegalArgumentException("startActivityFromRecentsInner: Task "
                     + taskId + " can't be launch in the home/recents stack.");
         }
 
         mWindowManager.deferSurfaceLayout();
         try {
-            if (launchStackId == DOCKED_STACK_ID) {
+            if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
                 mWindowManager.setDockedStackCreateState(
                         activityOptions.getDockCreateMode(), null /* initialBounds */);
 
@@ -4447,7 +4637,7 @@
             }
 
             task = anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE,
-                    launchStackId);
+                    activityOptions);
             if (task == null) {
                 continueUpdateBounds(RECENTS_STACK_ID);
                 mWindowManager.executeAppTransition();
@@ -4458,14 +4648,13 @@
             // Since we don't have an actual source record here, we assume that the currently
             // focused activity was the source.
             final ActivityStack focusedStack = getFocusedStack();
-            final ActivityRecord sourceRecord =
-                    focusedStack != null ? focusedStack.topActivity() : null;
+            final ActivityRecord sourceRecord = focusedStack != null
+                    ? focusedStack.topActivity() : null;
+            final int stackId = getLaunchStackId(null, activityOptions, task);
 
-            if (launchStackId != INVALID_STACK_ID) {
-                if (task.getStackId() != launchStackId) {
-                    task.reparent(launchStackId, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, ANIMATE,
-                            DEFER_RESUME, "startActivityFromRecents");
-                }
+            if (stackId != INVALID_STACK_ID && task.getStackId() != stackId) {
+                task.reparent(stackId, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME,
+                        "startActivityFromRecents");
             }
 
             // If the user must confirm credentials (e.g. when first launching a work app and the
@@ -4484,7 +4673,7 @@
                 // If we are launching the task in the docked stack, put it into resizing mode so
                 // the window renders full-screen with the background filling the void. Also only
                 // call this at the end to make sure that tasks exists on the window manager side.
-                if (launchStackId == DOCKED_STACK_ID) {
+                if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
                     setResizingDuringAnimation(task);
                 }
 
@@ -4502,7 +4691,7 @@
             userId = task.userId;
             int result = mService.startActivityInPackage(callingUid, callingPackage, intent, null,
                     null, null, 0, 0, bOptions, userId, task, "startActivityFromRecents");
-            if (launchStackId == DOCKED_STACK_ID) {
+            if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
                 setResizingDuringAnimation(task);
             }
             return result;
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 16abcfb..d94e866 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -39,6 +39,8 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
@@ -1024,10 +1026,12 @@
 
         ActivityRecord reusedActivity = getReusableIntentActivity();
 
-        final int preferredLaunchStackId =
-                (mOptions != null) ? mOptions.getLaunchStackId() : INVALID_STACK_ID;
-        final int preferredLaunchDisplayId =
-                (mOptions != null) ? mOptions.getLaunchDisplayId() : DEFAULT_DISPLAY;
+        int preferredWindowingMode = WINDOWING_MODE_UNDEFINED;
+        int preferredLaunchDisplayId = DEFAULT_DISPLAY;
+        if (mOptions != null) {
+            preferredWindowingMode = mOptions.getLaunchWindowingMode();
+            preferredLaunchDisplayId = mOptions.getLaunchDisplayId();
+        }
 
         if (reusedActivity != null) {
             // When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused but
@@ -1158,7 +1162,7 @@
 
             // Don't use mStartActivity.task to show the toast. We're not starting a new activity
             // but reusing 'top'. Fields in mStartActivity may not be fully initialized.
-            mSupervisor.handleNonResizableTaskIfNeeded(top.getTask(), preferredLaunchStackId,
+            mSupervisor.handleNonResizableTaskIfNeeded(top.getTask(), preferredWindowingMode,
                     preferredLaunchDisplayId, topStack.mStackId);
 
             return START_DELIVERED_TO_TOP;
@@ -1173,8 +1177,7 @@
         if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
                 && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
             newTask = true;
-            result = setTaskFromReuseOrCreateNewTask(
-                    taskToAffiliate, preferredLaunchStackId, topStack);
+            result = setTaskFromReuseOrCreateNewTask(taskToAffiliate, topStack);
         } else if (mSourceRecord != null) {
             result = setTaskFromSourceRecord();
         } else if (mInTask != null) {
@@ -1241,7 +1244,7 @@
         }
         mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
 
-        mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(), preferredLaunchStackId,
+        mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(), preferredWindowingMode,
                 preferredLaunchDisplayId, mTargetStack.mStackId);
 
         return START_SUCCESS;
@@ -1654,8 +1657,8 @@
             mTargetStack.moveToFront("intentActivityFound");
         }
 
-        mSupervisor.handleNonResizableTaskIfNeeded(intentActivity.getTask(), INVALID_STACK_ID,
-                DEFAULT_DISPLAY, mTargetStack.mStackId);
+        mSupervisor.handleNonResizableTaskIfNeeded(intentActivity.getTask(),
+                WINDOWING_MODE_UNDEFINED, DEFAULT_DISPLAY, mTargetStack.mStackId);
 
         // If the caller has requested that the target task be reset, then do so.
         if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
@@ -1675,8 +1678,7 @@
             // Task will be launched over the home stack, so return home.
             task.setTaskToReturnTo(ACTIVITY_TYPE_HOME);
             return;
-        } else if (focusedStack != null && focusedStack != task.getStack() &&
-                focusedStack.isActivityTypeAssistant()) {
+        } else if (focusedStack != task.getStack() && focusedStack.isActivityTypeAssistant()) {
             // Task was launched over the assistant stack, so return there
             task.setTaskToReturnTo(ACTIVITY_TYPE_ASSISTANT);
             return;
@@ -1779,7 +1781,7 @@
     }
 
     private int setTaskFromReuseOrCreateNewTask(
-            TaskRecord taskToAffiliate, int preferredLaunchStackId, ActivityStack topStack) {
+            TaskRecord taskToAffiliate, ActivityStack topStack) {
         mTargetStack = computeStackFocus(
                 mStartActivity, true, mLaunchBounds, mLaunchFlags, mOptions);
 
@@ -1821,8 +1823,10 @@
             // If stack id is specified in activity options, usually it means that activity is
             // launched not from currently focused stack (e.g. from SysUI or from shell) - in
             // that case we check the target stack.
+            // TODO: Not sure I understand the value or use of the commented out code and the
+            // comment above. See if this causes any issues and why...
             updateTaskReturnToType(mStartActivity.getTask(), mLaunchFlags,
-                    preferredLaunchStackId != INVALID_STACK_ID ? mTargetStack : topStack);
+                    /*preferredLaunchStackId != INVALID_STACK_ID ? mTargetStack : */topStack);
         }
         if (mDoResume) {
             mTargetStack.moveToFront("reuseOrNewTask");
@@ -1964,7 +1968,8 @@
 
         if (mLaunchBounds != null) {
             mInTask.updateOverrideConfiguration(mLaunchBounds);
-            int stackId = mInTask.getLaunchStackId();
+            // TODO: Shouldn't we already know what stack to use by the time we get here?
+            int stackId = mSupervisor.getLaunchStackId(null, null, mInTask);
             if (stackId != mInTask.getStackId()) {
                 mInTask.reparent(stackId, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE,
                         DEFER_RESUME, "inTaskToFront");
@@ -2102,9 +2107,10 @@
                 }
             }
             // If there is no suitable dynamic stack then we figure out which static stack to use.
-            final int stackId = task != null ? task.getLaunchStackId() :
-                    bounds != null ? FREEFORM_WORKSPACE_STACK_ID :
-                            FULLSCREEN_WORKSPACE_STACK_ID;
+            final int stackId = task != null ? mSupervisor.getLaunchStackId(r, aOptions, task)
+                    // TODO: This should go in mSupervisor.getLaunchStackId method...
+                    : bounds != null && mService.mSupportsFreeformWindowManagement
+                            ? FREEFORM_WORKSPACE_STACK_ID : FULLSCREEN_WORKSPACE_STACK_ID;
             stack = mSupervisor.getStack(stackId, CREATE_IF_NEEDED, ON_TOP);
         }
         if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: New stack r="
@@ -2165,18 +2171,16 @@
             return mSupervisor.getStack(ASSISTANT_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
         }
 
-        final int launchDisplayId =
-                (aOptions != null) ? aOptions.getLaunchDisplayId() : INVALID_DISPLAY;
-
-        final int launchStackId =
-                (aOptions != null) ? aOptions.getLaunchStackId() : INVALID_STACK_ID;
-
-        if (launchStackId != INVALID_STACK_ID && launchDisplayId != INVALID_DISPLAY) {
-            throw new IllegalArgumentException(
-                    "Stack and display id can't be set at the same time.");
+        int launchDisplayId = INVALID_DISPLAY;
+        int launchStackId = INVALID_STACK_ID;
+        if (aOptions != null) {
+            launchDisplayId = aOptions.getLaunchDisplayId();
+            final int vrDisplayId = mUsingVr2dDisplay ? mSourceDisplayId : INVALID_DISPLAY;
+            launchStackId = mSupervisor.getLaunchStackId(r, aOptions, task, vrDisplayId);
         }
 
-        if (isValidLaunchStackId(launchStackId, launchDisplayId, r)) {
+        // TODO: Will no longer be needed once we are on longer using static stack ids.
+        if (mSupervisor.isValidLaunchStackId(launchStackId, launchDisplayId, r)) {
             return mSupervisor.getStack(launchStackId, CREATE_IF_NEEDED, ON_TOP);
         }
         if (launchStackId == DOCKED_STACK_ID) {
@@ -2184,12 +2188,14 @@
             // for this activity, so we put the activity in the fullscreen stack.
             return mSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
         }
+        // TODO: Can probably be removed since ASS.getLaunchStackId() does display resolution.
         if (launchDisplayId != INVALID_DISPLAY) {
             // Stack id has higher priority than display id.
             return mSupervisor.getValidLaunchStackOnDisplay(launchDisplayId, r);
         }
 
         // If we are using Vr2d display, find the virtual display stack.
+        // TODO: Can be removed.
         if (mUsingVr2dDisplay) {
             ActivityStack as = mSupervisor.getValidLaunchStackOnDisplay(mSourceDisplayId, r);
             if (DEBUG_STACK) {
@@ -2240,39 +2246,11 @@
         }
     }
 
-    boolean isValidLaunchStackId(int stackId, int displayId, ActivityRecord r) {
-        switch (stackId) {
-            case INVALID_STACK_ID:
-            case HOME_STACK_ID:
-                return false;
-            case FULLSCREEN_WORKSPACE_STACK_ID:
-                return true;
-            case FREEFORM_WORKSPACE_STACK_ID:
-                return r.supportsFreeform();
-            case DOCKED_STACK_ID:
-                return r.supportsSplitScreen();
-            case PINNED_STACK_ID:
-                return r.supportsPictureInPicture();
-            case RECENTS_STACK_ID:
-                return r.isActivityTypeRecents();
-            case ASSISTANT_STACK_ID:
-                return r.isActivityTypeAssistant();
-            default:
-                if (StackId.isDynamicStack(stackId)) {
-                    return r.canBeLaunchedOnDisplay(displayId);
-                }
-                Slog.e(TAG, "isValidLaunchStackId: Unexpected stackId=" + stackId);
-                return false;
-        }
-    }
-
-    Rect getOverrideBounds(ActivityRecord r, ActivityOptions options, TaskRecord inTask) {
+    private Rect getOverrideBounds(ActivityRecord r, ActivityOptions options, TaskRecord inTask) {
         Rect newBounds = null;
-        if (options != null && (r.isResizeable() || (inTask != null && inTask.isResizeable()))) {
-            if (mSupervisor.canUseActivityOptionsLaunchBounds(
-                    options, options.getLaunchStackId())) {
-                newBounds = TaskRecord.validateBounds(options.getLaunchBounds());
-            }
+        if (mSupervisor.canUseActivityOptionsLaunchBounds(options)
+                && (r.isResizeable() || (inTask != null && inTask.isResizeable()))) {
+            newBounds = TaskRecord.validateBounds(options.getLaunchBounds());
         }
         return newBounds;
     }
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index cea80c8..8596113 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -19,6 +19,7 @@
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
 import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
 import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
 import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
@@ -66,6 +67,7 @@
     private int mBeforeUnoccludeTransit;
     private int mVisibilityTransactionDepth;
     private SleepToken mSleepToken;
+    private int mSecondaryDisplayShowing = INVALID_DISPLAY;
 
     KeyguardController(ActivityManagerService service,
             ActivityStackSupervisor stackSupervisor) {
@@ -78,10 +80,12 @@
     }
 
     /**
-     * @return true if Keyguard is showing, not going away, and not being occluded, false otherwise
+     * @return true if Keyguard is showing, not going away, and not being occluded on the given
+     *         display, false otherwise
      */
-    boolean isKeyguardShowing() {
-        return mKeyguardShowing && !mKeyguardGoingAway && !mOccluded;
+    boolean isKeyguardShowing(int displayId) {
+        return mKeyguardShowing && !mKeyguardGoingAway &&
+                (displayId == DEFAULT_DISPLAY ? !mOccluded : displayId == mSecondaryDisplayShowing);
     }
 
     /**
@@ -94,15 +98,19 @@
     /**
      * Update the Keyguard showing state.
      */
-    void setKeyguardShown(boolean showing) {
-        if (showing == mKeyguardShowing) {
+    void setKeyguardShown(boolean showing, int secondaryDisplayShowing) {
+        boolean showingChanged = showing != mKeyguardShowing;
+        if (!showingChanged && secondaryDisplayShowing == mSecondaryDisplayShowing) {
             return;
         }
         mKeyguardShowing = showing;
-        dismissDockedStackIfNeeded();
-        if (showing) {
-            setKeyguardGoingAway(false);
-            mDismissalRequested = false;
+        mSecondaryDisplayShowing = secondaryDisplayShowing;
+        if (showingChanged) {
+            dismissDockedStackIfNeeded();
+            if (showing) {
+                setKeyguardGoingAway(false);
+                mDismissalRequested = false;
+            }
         }
         mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
         updateKeyguardSleepToken();
@@ -337,9 +345,9 @@
     }
 
     private void updateKeyguardSleepToken() {
-        if (mSleepToken == null && isKeyguardShowing()) {
+        if (mSleepToken == null && isKeyguardShowing(DEFAULT_DISPLAY)) {
             mSleepToken = mService.acquireSleepToken("Keyguard", DEFAULT_DISPLAY);
-        } else if (mSleepToken != null && !isKeyguardShowing()) {
+        } else if (mSleepToken != null && !isKeyguardShowing(DEFAULT_DISPLAY)) {
             mSleepToken.release();
             mSleepToken = null;
         }
diff --git a/services/core/java/com/android/server/am/LockTaskController.java b/services/core/java/com/android/server/am/LockTaskController.java
index 241e583..72b5de8 100644
--- a/services/core/java/com/android/server/am/LockTaskController.java
+++ b/services/core/java/com/android/server/am/LockTaskController.java
@@ -25,6 +25,7 @@
 import static android.app.StatusBarManager.DISABLE_MASK;
 import static android.app.StatusBarManager.DISABLE_NONE;
 import static android.app.StatusBarManager.DISABLE_RECENT;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.Context.DEVICE_POLICY_SERVICE;
 import static android.content.Context.STATUS_BAR_SERVICE;
 import static android.os.UserHandle.USER_ALL;
@@ -431,8 +432,8 @@
             mSupervisor.resumeFocusedStackTopActivityLocked();
             mWindowManager.executeAppTransition();
         } else if (lockTaskModeState != LOCK_TASK_MODE_NONE) {
-            mSupervisor.handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, DEFAULT_DISPLAY,
-                    task.getStackId(), true /* forceNonResizable */);
+            mSupervisor.handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED,
+                    DEFAULT_DISPLAY, task.getStackId(), true /* forceNonResizable */);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index 74c4826..f6e20cd 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -472,8 +472,7 @@
 
                                 final int taskId = task.taskId;
                                 if (mStackSupervisor.anyTaskForIdLocked(taskId,
-                                        MATCH_TASK_IN_STACKS_OR_RECENT_TASKS,
-                                        INVALID_STACK_ID) != null) {
+                                        MATCH_TASK_IN_STACKS_OR_RECENT_TASKS) != null) {
                                     // Should not happen.
                                     Slog.wtf(TAG, "Existing task with taskId " + taskId + "found");
                                 } else if (userId != task.userId) {
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 48da655..28b71d9 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -26,6 +26,7 @@
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
+import static android.app.ActivityManager.StackId.getWindowingModeForStackId;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
@@ -507,8 +508,7 @@
             updateOverrideConfiguration(bounds);
             if (getStackId() != FREEFORM_WORKSPACE_STACK_ID) {
                 // re-restore the task so it can have the proper stack association.
-                mService.mStackSupervisor.restoreRecentTaskLocked(this,
-                        FREEFORM_WORKSPACE_STACK_ID);
+                mService.mStackSupervisor.restoreRecentTaskLocked(this, null);
             }
             return true;
         }
@@ -729,7 +729,8 @@
         }
 
         // TODO: Handle incorrect request to move before the actual move, not after.
-        supervisor.handleNonResizableTaskIfNeeded(this, preferredStackId, DEFAULT_DISPLAY, stackId);
+        supervisor.handleNonResizableTaskIfNeeded(this, getWindowingModeForStackId(preferredStackId,
+                        supervisor.getStack(DOCKED_STACK_ID) != null), DEFAULT_DISPLAY, stackId);
 
         boolean successful = (preferredStackId == stackId);
         if (successful && stackId == DOCKED_STACK_ID) {
@@ -2079,27 +2080,6 @@
         }
     }
 
-    /**
-     * Returns the correct stack to use based on task type and currently set bounds,
-     * regardless of the focused stack and current stack association of the task.
-     * The task will be moved (and stack focus changed) later if necessary.
-     */
-    int getLaunchStackId() {
-        if (isActivityTypeRecents()) {
-            return RECENTS_STACK_ID;
-        }
-        if (isActivityTypeHome()) {
-            return HOME_STACK_ID;
-        }
-        if (isActivityTypeAssistant()) {
-            return ASSISTANT_STACK_ID;
-        }
-        if (mBounds != null) {
-            return FREEFORM_WORKSPACE_STACK_ID;
-        }
-        return FULLSCREEN_WORKSPACE_STACK_ID;
-    }
-
     /** Returns the bounds that should be used to launch this task. */
     private Rect getLaunchBounds() {
         if (mStack == null) {
diff --git a/services/core/java/com/android/server/display/NightDisplayService.java b/services/core/java/com/android/server/display/NightDisplayService.java
index aafc631..9cf1367 100644
--- a/services/core/java/com/android/server/display/NightDisplayService.java
+++ b/services/core/java/com/android/server/display/NightDisplayService.java
@@ -48,8 +48,10 @@
 import com.android.server.twilight.TwilightManager;
 import com.android.server.twilight.TwilightState;
 
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
 import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.Calendar;
 import java.util.TimeZone;
 
 import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
@@ -306,7 +308,7 @@
     }
 
     @Override
-    public void onCustomStartTimeChanged(NightDisplayController.LocalTime startTime) {
+    public void onCustomStartTimeChanged(LocalTime startTime) {
         Slog.d(TAG, "onCustomStartTimeChanged: startTime=" + startTime);
 
         if (mAutoMode != null) {
@@ -315,7 +317,7 @@
     }
 
     @Override
-    public void onCustomEndTimeChanged(NightDisplayController.LocalTime endTime) {
+    public void onCustomEndTimeChanged(LocalTime endTime) {
         Slog.d(TAG, "onCustomEndTimeChanged: endTime=" + endTime);
 
         if (mAutoMode != null) {
@@ -414,6 +416,36 @@
         outTemp[10] = blue;
     }
 
+    /**
+     * Returns the first date time corresponding to the local time that occurs before the
+     * provided date time.
+     *
+     * @param compareTime the LocalDateTime to compare against
+     * @return the prior LocalDateTime corresponding to this local time
+     */
+    public static LocalDateTime getDateTimeBefore(LocalTime localTime, LocalDateTime compareTime) {
+        final LocalDateTime ldt = LocalDateTime.of(compareTime.getYear(), compareTime.getMonth(),
+                compareTime.getDayOfMonth(), localTime.getHour(), localTime.getMinute());
+
+        // Check if the local time has passed, if so return the same time yesterday.
+        return ldt.isAfter(compareTime) ? ldt.minusDays(1) : ldt;
+    }
+
+    /**
+     * Returns the first date time corresponding to this local time that occurs after the
+     * provided date time.
+     *
+     * @param compareTime the LocalDateTime to compare against
+     * @return the next LocalDateTime corresponding to this local time
+     */
+    public static LocalDateTime getDateTimeAfter(LocalTime localTime, LocalDateTime compareTime) {
+        final LocalDateTime ldt = LocalDateTime.of(compareTime.getYear(), compareTime.getMonth(),
+                compareTime.getDayOfMonth(), localTime.getHour(), localTime.getMinute());
+
+        // Check if the local time has passed, if so return the same time tomorrow.
+        return ldt.isBefore(compareTime) ? ldt.plusDays(1) : ldt;
+    }
+
     private abstract class AutoMode implements NightDisplayController.Callback {
         public abstract void onStart();
 
@@ -425,10 +457,10 @@
         private final AlarmManager mAlarmManager;
         private final BroadcastReceiver mTimeChangedReceiver;
 
-        private NightDisplayController.LocalTime mStartTime;
-        private NightDisplayController.LocalTime mEndTime;
+        private LocalTime mStartTime;
+        private LocalTime mEndTime;
 
-        private Calendar mLastActivatedTime;
+        private LocalDateTime mLastActivatedTime;
 
         CustomAutoMode() {
             mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
@@ -441,31 +473,15 @@
         }
 
         private void updateActivated() {
-            final Calendar now = Calendar.getInstance();
-            final Calendar startTime = mStartTime.getDateTimeBefore(now);
-            final Calendar endTime = mEndTime.getDateTimeAfter(startTime);
+            final LocalDateTime now = LocalDateTime.now();
+            final LocalDateTime start = getDateTimeBefore(mStartTime, now);
+            final LocalDateTime end = getDateTimeAfter(mEndTime, start);
+            boolean activate = now.isBefore(end);
 
-            boolean activate = now.before(endTime);
             if (mLastActivatedTime != null) {
-                // Convert mLastActivatedTime to the current timezone if needed.
-                final TimeZone currentTimeZone = now.getTimeZone();
-                if (!currentTimeZone.equals(mLastActivatedTime.getTimeZone())) {
-                    final int year = mLastActivatedTime.get(Calendar.YEAR);
-                    final int dayOfYear = mLastActivatedTime.get(Calendar.DAY_OF_YEAR);
-                    final int hourOfDay = mLastActivatedTime.get(Calendar.HOUR_OF_DAY);
-                    final int minute = mLastActivatedTime.get(Calendar.MINUTE);
-
-                    mLastActivatedTime.setTimeZone(currentTimeZone);
-                    mLastActivatedTime.set(Calendar.YEAR, year);
-                    mLastActivatedTime.set(Calendar.DAY_OF_YEAR, dayOfYear);
-                    mLastActivatedTime.set(Calendar.HOUR_OF_DAY, hourOfDay);
-                    mLastActivatedTime.set(Calendar.MINUTE, minute);
-                }
-
                 // Maintain the existing activated state if within the current period.
-                if (mLastActivatedTime.before(now)
-                        && mLastActivatedTime.after(startTime)
-                        && (mLastActivatedTime.after(endTime) || now.before(endTime))) {
+                if (mLastActivatedTime.isBefore(now) && mLastActivatedTime.isAfter(start)
+                        && (mLastActivatedTime.isAfter(end) || now.isBefore(end))) {
                     activate = mController.isActivated();
                 }
             }
@@ -473,14 +489,16 @@
             if (mIsActivated == null || mIsActivated != activate) {
                 mController.setActivated(activate);
             }
+
             updateNextAlarm(mIsActivated, now);
         }
 
-        private void updateNextAlarm(@Nullable Boolean activated, @NonNull Calendar now) {
+        private void updateNextAlarm(@Nullable Boolean activated, @NonNull LocalDateTime now) {
             if (activated != null) {
-                final Calendar next = activated ? mEndTime.getDateTimeAfter(now)
-                        : mStartTime.getDateTimeAfter(now);
-                mAlarmManager.setExact(AlarmManager.RTC, next.getTimeInMillis(), TAG, this, null);
+                final LocalDateTime next = activated ? getDateTimeAfter(mEndTime, now)
+                        : getDateTimeAfter(mStartTime, now);
+                final long millis = next.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
+                mAlarmManager.setExact(AlarmManager.RTC, millis, TAG, this, null);
             }
         }
 
@@ -510,18 +528,18 @@
         @Override
         public void onActivated(boolean activated) {
             mLastActivatedTime = mController.getLastActivatedTime();
-            updateNextAlarm(activated, Calendar.getInstance());
+            updateNextAlarm(activated, LocalDateTime.now());
         }
 
         @Override
-        public void onCustomStartTimeChanged(NightDisplayController.LocalTime startTime) {
+        public void onCustomStartTimeChanged(LocalTime startTime) {
             mStartTime = startTime;
             mLastActivatedTime = null;
             updateActivated();
         }
 
         @Override
-        public void onCustomEndTimeChanged(NightDisplayController.LocalTime endTime) {
+        public void onCustomEndTimeChanged(LocalTime endTime) {
             mEndTime = endTime;
             mLastActivatedTime = null;
             updateActivated();
@@ -550,15 +568,14 @@
             }
 
             boolean activate = state.isNight();
-            final Calendar lastActivatedTime = mController.getLastActivatedTime();
+            final LocalDateTime lastActivatedTime = mController.getLastActivatedTime();
             if (lastActivatedTime != null) {
-                final Calendar now = Calendar.getInstance();
-                final Calendar sunrise = state.sunrise();
-                final Calendar sunset = state.sunset();
-
+                final LocalDateTime now = LocalDateTime.now();
+                final LocalDateTime sunrise = state.sunrise();
+                final LocalDateTime sunset = state.sunset();
                 // Maintain the existing activated state if within the current period.
-                if (lastActivatedTime.before(now)
-                        && (lastActivatedTime.after(sunrise) ^ lastActivatedTime.after(sunset))) {
+                if (lastActivatedTime.isBefore(now) && (lastActivatedTime.isBefore(sunrise)
+                        ^ lastActivatedTime.isBefore(sunset))) {
                     activate = mController.isActivated();
                 }
             }
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 0f580d8..4fafe34 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -438,16 +438,7 @@
                     PackageDexUsage.DexUseInfo dexUseInfo = e.getValue();
                     pw.println(dex);
                     pw.increaseIndent();
-                    for (String isa : dexUseInfo.getLoaderIsas()) {
-                        String status = null;
-                        try {
-                            status = DexFile.getDexFileStatus(path, isa);
-                        } catch (IOException ioe) {
-                             status = "[Exception]: " + ioe.getMessage();
-                        }
-                        pw.println(isa + ": " + status);
-                    }
-
+                    // TODO(calin): get the status of the oat file (needs installd call)
                     pw.println("class loader context: " + dexUseInfo.getClassLoaderContext());
                     if (dexUseInfo.isUsedByOtherApps()) {
                         pw.println("used be other apps: " + dexUseInfo.getLoadingPackages());
@@ -474,8 +465,9 @@
         }
 
         if (isProfileGuidedCompilerFilter(targetCompilerFilter) && isUsedByOtherApps) {
-            // If the dex files is used by other apps, we cannot use profile-guided compilation.
-            return getNonProfileGuidedCompilerFilter(targetCompilerFilter);
+            // If the dex files is used by other apps, apply the shared filter.
+            return PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
+                    PackageManagerService.REASON_SHARED);
         }
 
         return targetCompilerFilter;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ff52e0e..8852a4d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -578,8 +578,9 @@
     public static final int REASON_BACKGROUND_DEXOPT = 3;
     public static final int REASON_AB_OTA = 4;
     public static final int REASON_INACTIVE_PACKAGE_DOWNGRADE = 5;
+    public static final int REASON_SHARED = 6;
 
-    public static final int REASON_LAST = REASON_INACTIVE_PACKAGE_DOWNGRADE;
+    public static final int REASON_LAST = REASON_SHARED;
 
     /** All dangerous permission names in the same order as the events in MetricsEvent */
     private static final List<String> ALL_DANGEROUS_PERMISSIONS = Arrays.asList(
@@ -9819,19 +9820,6 @@
                     compilerFilter,
                     dexoptFlags));
 
-            if (pkg.isSystemApp()) {
-                // Only dexopt shared secondary dex files belonging to system apps to not slow down
-                // too much boot after an OTA.
-                int secondaryDexoptFlags = dexoptFlags |
-                        DexoptOptions.DEXOPT_ONLY_SECONDARY_DEX |
-                        DexoptOptions.DEXOPT_ONLY_SHARED_DEX;
-                mDexManager.dexoptSecondaryDex(new DexoptOptions(
-                        pkg.packageName,
-                        compilerFilter,
-                        secondaryDexoptFlags));
-            }
-
-            // TODO(shubhamajmera): Record secondary dexopt stats.
             switch (primaryDexOptStaus) {
                 case PackageDexOptimizer.DEX_OPT_PERFORMED:
                     numberOfPackagesOptimized++;
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
index 1a97a72..19b0d9b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
@@ -26,14 +26,19 @@
 public class PackageManagerServiceCompilerMapping {
     // Names for compilation reasons.
     static final String REASON_STRINGS[] = {
-            "first-boot", "boot", "install", "bg-dexopt", "ab-ota", "inactive"
+            "first-boot", "boot", "install", "bg-dexopt", "ab-ota", "inactive", "shared"
     };
 
+    static final int REASON_SHARED_INDEX = 6;
+
     // Static block to ensure the strings array is of the right length.
     static {
         if (PackageManagerService.REASON_LAST + 1 != REASON_STRINGS.length) {
             throw new IllegalStateException("REASON_STRINGS not correct");
         }
+        if (!"shared".equals(REASON_STRINGS[REASON_SHARED_INDEX])) {
+            throw new IllegalStateException("REASON_STRINGS not correct because of shared index");
+        }
     }
 
     private static String getSystemPropertyName(int reason) {
@@ -52,11 +57,18 @@
                 !DexFile.isValidCompilerFilter(sysPropValue)) {
             throw new IllegalStateException("Value \"" + sysPropValue +"\" not valid "
                     + "(reason " + REASON_STRINGS[reason] + ")");
+        } else if (!isFilterAllowedForReason(reason, sysPropValue)) {
+            throw new IllegalStateException("Value \"" + sysPropValue +"\" not allowed "
+                    + "(reason " + REASON_STRINGS[reason] + ")");
         }
 
         return sysPropValue;
     }
 
+    private static boolean isFilterAllowedForReason(int reason, String filter) {
+        return reason != REASON_SHARED_INDEX || !DexFile.isProfileGuidedCompilerFilter(filter);
+    }
+
     // Check that the properties are set and valid.
     // Note: this is done in a separate method so this class can be statically initialized.
     static void checkProperties() {
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 1dac15f..70cd54ff 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -1,5 +1,7 @@
 package com.android.server.policy.keyguard;
 
+import static android.view.Display.INVALID_DISPLAY;
+
 import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.content.Context;
@@ -202,7 +204,10 @@
             mKeyguardState.reset();
             mHandler.post(() -> {
                 try {
-                    ActivityManager.getService().setLockScreenShown(true);
+                    // There are no longer any keyguard windows on secondary displays, so pass
+                    // INVALID_DISPLAY. All that means is that showWhenLocked activities on
+                    // secondary displays now get to show.
+                    ActivityManager.getService().setLockScreenShown(true, INVALID_DISPLAY);
                 } catch (RemoteException e) {
                     // Local call.
                 }
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
new file mode 100644
index 0000000..cf81e5b
--- /dev/null
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.stats;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IStatsCompanionService;
+import android.os.IStatsManager;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Slog;
+
+import com.android.server.SystemService;
+
+/**
+ * Helper service for statsd (the native stats management service in cmds/statsd/).
+ * Used for registering and receiving alarms on behalf of statsd.
+ */
+public class StatsCompanionService extends IStatsCompanionService.Stub {
+    static final String TAG = "StatsCompanionService";
+    static final boolean DEBUG = true;
+
+    private final Context mContext;
+    private final AlarmManager mAlarmManager;
+    private static IStatsManager sStatsd;
+
+    private final PendingIntent mAnomalyAlarmIntent;
+    private final PendingIntent mPollingAlarmIntent;
+
+    public final static class AnomalyAlarmReceiver extends BroadcastReceiver  {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            Slog.i(TAG, "StatsCompanionService believes an anomaly has occurred.");
+            try {
+                // TODO: should be twoway so device won't sleep before acting?
+                getStatsdService().informAnomalyAlarmFired();
+            } catch (RemoteException e) {
+                Slog.e(TAG, "failed to inform statsd of anomaly alarm firing", e);
+            } catch (NullPointerException e) {
+                Slog.e(TAG, "could not access statsd to inform it of anomaly alarm firing", e);
+            }
+            // AlarmManager releases its own wakelock here.
+        }
+    };
+
+    public final static class PollingAlarmReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (DEBUG) Slog.d(TAG, "Time to poll something.");
+            if (DEBUG) Slog.d(TAG, "Time to poll something.");
+            try {
+                // TODO: should be twoway so device won't sleep before acting?
+                getStatsdService().informPollAlarmFired();
+            } catch (RemoteException e) {
+                Slog.e(TAG, "failed to inform statsd of polling alarm firing",e);
+            } catch (NullPointerException e) {
+                Slog.e(TAG, "could not access statsd to inform it of polling alarm firing", e);
+            }
+            // AlarmManager releases its own wakelock here.
+        }
+    };
+
+    public StatsCompanionService(Context context) {
+        super();
+        mContext = context;
+        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+
+        mAnomalyAlarmIntent = PendingIntent.getBroadcast(mContext, 0,
+                new Intent(mContext, AnomalyAlarmReceiver.class), 0);
+        mPollingAlarmIntent = PendingIntent.getBroadcast(mContext, 0,
+                new Intent(mContext, PollingAlarmReceiver.class), 0);
+    }
+
+    /** Returns the statsd IBinder service */
+    public static IStatsManager getStatsdService() {
+        if (sStatsd != null) {
+            return sStatsd;
+        }
+        sStatsd = IStatsManager.Stub.asInterface(ServiceManager.getService("stats"));
+        return sStatsd;
+    }
+
+    public static final class Lifecycle extends SystemService {
+        private StatsCompanionService mStatsCompanionService;
+
+        public Lifecycle(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onStart() {
+            mStatsCompanionService = new StatsCompanionService(getContext());
+            try {
+                publishBinderService(Context.STATS_COMPANION_SERVICE, mStatsCompanionService);
+                if (DEBUG) Slog.d(TAG, "Published " + Context.STATS_COMPANION_SERVICE);
+            } catch (Exception e) {
+                Slog.e(TAG, "Failed to publishBinderService", e);
+            }
+        }
+    }
+
+    @Override // Binder call
+    public void setAnomalyAlarm(long timestampMs) {
+        enforceCallingPermission();
+        if (DEBUG) Slog.d(TAG, "Setting anomaly alarm for " + timestampMs);
+        final long callingToken = Binder.clearCallingIdentity();
+        try {
+            // using RTC, not RTC_WAKEUP, so if device is asleep, will only fire when it awakens.
+            // This alarm is inexact, leaving its exactness completely up to the OS optimizations.
+            // AlarmManager will automatically cancel any previous mAnomalyAlarmIntent alarm.
+            mAlarmManager.set(AlarmManager.RTC, timestampMs, mAnomalyAlarmIntent);
+        } finally {
+            Binder.restoreCallingIdentity(callingToken);
+        }
+    }
+
+    @Override // Binder call
+    public void cancelAnomalyAlarm() {
+        enforceCallingPermission();
+        if (DEBUG) Slog.d(TAG, "Cancelling anomaly alarm");
+        final long callingToken = Binder.clearCallingIdentity();
+        try {
+            mAlarmManager.cancel(mAnomalyAlarmIntent);
+        } finally {
+            Binder.restoreCallingIdentity(callingToken);
+        }
+    }
+
+    @Override // Binder call
+    public void setPollingAlarms(long timestampMs, long intervalMs) {
+        enforceCallingPermission();
+        if (DEBUG) Slog.d(TAG, "Setting polling alarm for " + timestampMs
+                + " every " + intervalMs + "ms");
+        final long callingToken = Binder.clearCallingIdentity();
+        try {
+            // using RTC, not RTC_WAKEUP, so if device is asleep, will only fire when it awakens.
+            // This alarm is inexact, leaving its exactness completely up to the OS optimizations.
+            // TODO: totally inexact means that stats per bucket could be quite off. Is this okay?
+            mAlarmManager.setRepeating(AlarmManager.RTC, timestampMs, intervalMs,
+                    mPollingAlarmIntent);
+        } finally {
+            Binder.restoreCallingIdentity(callingToken);
+        }
+    }
+
+    @Override // Binder call
+    public void cancelPollingAlarms() {
+        enforceCallingPermission();
+        if (DEBUG) Slog.d(TAG, "Cancelling polling alarm");
+        final long callingToken = Binder.clearCallingIdentity();
+        try {
+            mAlarmManager.cancel(mPollingAlarmIntent);
+        } finally {
+            Binder.restoreCallingIdentity(callingToken);
+        }
+    }
+
+    private void enforceCallingPermission() {
+        if (Binder.getCallingPid() == Process.myPid()) {
+            return;
+        }
+        mContext.enforceCallingPermission(android.Manifest.permission.STATSCOMPANION, null);
+    }
+
+}
diff --git a/services/core/java/com/android/server/twilight/TwilightState.java b/services/core/java/com/android/server/twilight/TwilightState.java
index 30a8ccc..71304a7 100644
--- a/services/core/java/com/android/server/twilight/TwilightState.java
+++ b/services/core/java/com/android/server/twilight/TwilightState.java
@@ -18,7 +18,10 @@
 
 import android.text.format.DateFormat;
 
-import java.util.Calendar;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.TimeZone;
 
 /**
  * The twilight state, consisting of the sunrise and sunset times (in millis) for the current
@@ -45,12 +48,11 @@
     }
 
     /**
-     * Returns a new {@link Calendar} instance initialized to {@link #sunriseTimeMillis()}.
+     * Returns a new {@link LocalDateTime} instance initialized to {@link #sunriseTimeMillis()}.
      */
-    public Calendar sunrise() {
-        final Calendar sunrise = Calendar.getInstance();
-        sunrise.setTimeInMillis(mSunriseTimeMillis);
-        return sunrise;
+    public LocalDateTime sunrise() {
+        final ZoneId zoneId = TimeZone.getDefault().toZoneId();
+        return LocalDateTime.ofInstant(Instant.ofEpochMilli(mSunriseTimeMillis), zoneId);
     }
 
     /**
@@ -62,12 +64,11 @@
     }
 
     /**
-     * Returns a new {@link Calendar} instance initialized to {@link #sunsetTimeMillis()}.
+     * Returns a new {@link LocalDateTime} instance initialized to {@link #sunsetTimeMillis()}.
      */
-    public Calendar sunset() {
-        final Calendar sunset = Calendar.getInstance();
-        sunset.setTimeInMillis(mSunsetTimeMillis);
-        return sunset;
+    public LocalDateTime sunset() {
+        final ZoneId zoneId = TimeZone.getDefault().toZoneId();
+        return LocalDateTime.ofInstant(Instant.ofEpochMilli(mSunsetTimeMillis), zoneId);
     }
 
     /**
diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java
index bf769ed..1e334b8 100644
--- a/services/core/java/com/android/server/webkit/SystemImpl.java
+++ b/services/core/java/com/android/server/webkit/SystemImpl.java
@@ -304,6 +304,6 @@
 
     // flags declaring we want extra info from the package manager for webview providers
     private final static int PACKAGE_FLAGS = PackageManager.GET_META_DATA
-            | PackageManager.GET_SIGNATURES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING
-            | PackageManager.MATCH_ANY_USER;
+            | PackageManager.GET_SIGNATURES | PackageManager.GET_SHARED_LIBRARY_FILES
+            | PackageManager.MATCH_DEBUG_TRIAGED_MISSING | PackageManager.MATCH_ANY_USER;
 }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 817a01c..98a1bd3 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1722,21 +1722,22 @@
         out.set(mContentRect);
     }
 
-    TaskStack addStackToDisplay(int stackId, boolean onTop) {
+    TaskStack addStackToDisplay(int stackId, boolean onTop, StackWindowController controller) {
         if (DEBUG_STACK) Slog.d(TAG_WM, "Create new stackId=" + stackId + " on displayId="
                 + mDisplayId);
 
         TaskStack stack = getStackById(stackId);
         if (stack != null) {
-            // It's already attached to the display...clear mDeferRemoval and move stack to
-            // appropriate z-order on display as needed.
+            // It's already attached to the display...clear mDeferRemoval, set controller, and move
+            // stack to appropriate z-order on display as needed.
             stack.mDeferRemoval = false;
+            stack.setController(controller);
             // We're not moving the display to front when we're adding stacks, only when
             // requested to change the position of stack explicitly.
             mTaskStackContainers.positionChildAt(onTop ? POSITION_TOP : POSITION_BOTTOM, stack,
                     false /* includingParents */);
         } else {
-            stack = new TaskStack(mService, stackId);
+            stack = new TaskStack(mService, stackId, controller);
             mTaskStackContainers.addStackToDisplay(stack, onTop);
         }
 
diff --git a/services/core/java/com/android/server/wm/StackWindowController.java b/services/core/java/com/android/server/wm/StackWindowController.java
index a50ed71..c0a4cb7 100644
--- a/services/core/java/com/android/server/wm/StackWindowController.java
+++ b/services/core/java/com/android/server/wm/StackWindowController.java
@@ -18,8 +18,6 @@
 
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 
-import android.app.ActivityManager.StackId;
-import android.app.WindowConfiguration;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Handler;
@@ -76,8 +74,7 @@
                         + " to unknown displayId=" + displayId);
             }
 
-            final TaskStack stack = dc.addStackToDisplay(stackId, onTop);
-            stack.setController(this);
+            dc.addStackToDisplay(stackId, onTop, this);
             getRawBounds(outBounds);
         }
     }
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 126d820..7cb90de 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -149,9 +149,10 @@
 
     Rect mPreAnimationBounds = new Rect();
 
-    TaskStack(WindowManagerService service, int stackId) {
+    TaskStack(WindowManagerService service, int stackId, StackWindowController controller) {
         mService = service;
         mStackId = stackId;
+        setController(controller);
         mDockedStackMinimizeThickness = service.mContext.getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.docked_stack_minimize_thickness);
         EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 2815da6..948c028 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -103,6 +103,7 @@
 import com.android.server.security.KeyAttestationApplicationIdProviderService;
 import com.android.server.security.KeyChainSystemService;
 import com.android.server.soundtrigger.SoundTriggerService;
+import com.android.server.stats.StatsCompanionService;
 import com.android.server.statusbar.StatusBarManagerService;
 import com.android.server.storage.DeviceStorageMonitorService;
 import com.android.server.telecom.TelecomLoaderService;
@@ -1523,6 +1524,11 @@
             traceEnd();
         }
 
+        // Statsd helper
+        traceBeginAndSlog("StartStatsCompanionService");
+        mSystemServiceManager.startService(StatsCompanionService.Lifecycle.class);
+        traceEnd();
+
         // Before things start rolling, be sure we have decided whether
         // we are in safe mode.
         final boolean safeMode = wm.detectSafeMode();
diff --git a/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java
index 58a4456..3a92d63 100644
--- a/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java
@@ -30,13 +30,14 @@
 import android.test.mock.MockContentResolver;
 
 import com.android.internal.app.NightDisplayController;
-import com.android.internal.app.NightDisplayController.LocalTime;
 import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.server.display.DisplayTransformManager;
 import com.android.server.display.NightDisplayService;
 import com.android.server.twilight.TwilightListener;
 import com.android.server.twilight.TwilightManager;
 import com.android.server.twilight.TwilightState;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -45,6 +46,7 @@
 
 import java.util.Calendar;
 import java.util.HashMap;
+import java.time.LocalTime;
 import java.util.Map;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -926,11 +928,10 @@
      */
     private void setActivated(boolean activated, int lastActivatedTimeOffset) {
         mNightDisplayController.setActivated(activated);
-
-        final Calendar c = Calendar.getInstance();
-        c.add(Calendar.MINUTE, lastActivatedTimeOffset);
-        Secure.putLongForUser(mContext.getContentResolver(),
-                Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, c.getTimeInMillis(), mUserId);
+        Secure.putStringForUser(mContext.getContentResolver(),
+                Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
+                LocalDateTime.now().plusMinutes(lastActivatedTimeOffset).toString(),
+                mUserId);
     }
 
     /**
@@ -969,7 +970,7 @@
     private static LocalTime getLocalTimeRelativeToNow(int offsetMinutes) {
         final Calendar c = Calendar.getInstance();
         c.add(Calendar.MINUTE, offsetMinutes);
-        return new LocalTime(c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE));
+        return LocalTime.of(c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE));
     }
 
     /**
@@ -984,13 +985,27 @@
         final LocalTime sunset = getLocalTimeRelativeToNow(sunsetOffset);
         final LocalTime sunrise = getLocalTimeRelativeToNow(sunriseOffset);
 
-        final Calendar now = Calendar.getInstance();
-        long sunsetMillis = sunset.getDateTimeBefore(now).getTimeInMillis();
-        long sunriseMillis = sunrise.getDateTimeBefore(now).getTimeInMillis();
+        final LocalDateTime now = LocalDateTime.now();
+        final ZoneId zoneId = ZoneId.systemDefault();
+
+        long sunsetMillis = NightDisplayService.getDateTimeBefore(sunset, now)
+                .atZone(zoneId)
+                .toInstant()
+                .toEpochMilli();
+        long sunriseMillis = NightDisplayService.getDateTimeBefore(sunrise, now)
+                .atZone(zoneId)
+                .toInstant()
+                .toEpochMilli();
         if (sunsetMillis < sunriseMillis) {
-            sunsetMillis = sunset.getDateTimeAfter(now).getTimeInMillis();
+            sunsetMillis = NightDisplayService.getDateTimeAfter(sunset, now)
+                    .atZone(zoneId)
+                    .toInstant()
+                    .toEpochMilli();
         } else {
-            sunriseMillis = sunrise.getDateTimeAfter(now).getTimeInMillis();
+            sunriseMillis = NightDisplayService.getDateTimeAfter(sunrise, now)
+                    .atZone(zoneId)
+                    .toInstant()
+                    .toEpochMilli();
         }
 
         return new TwilightState(sunriseMillis, sunsetMillis);
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
index 47a3a72..526f815 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
@@ -20,15 +20,19 @@
 import static android.view.WindowManagerPolicy.NAV_BAR_LEFT;
 import static android.view.WindowManagerPolicy.NAV_BAR_RIGHT;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.when;
 
 import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.MediumTest;
 import android.support.test.runner.AndroidJUnit4;
 
+import android.view.Display;
 import org.junit.runner.RunWith;
 import org.junit.Test;
 
@@ -46,6 +50,8 @@
 
     private final ComponentName testActivityComponent =
             ComponentName.unflattenFromString("com.foo/.BarActivity");
+    private final ComponentName secondaryActivityComponent =
+            ComponentName.unflattenFromString("com.foo/.BarActivity2");
     @Test
     public void testStackCleanupOnClearingTask() throws Exception {
         final ActivityManagerService service = createActivityManagerService();
@@ -131,4 +137,45 @@
         record.ensureActivityConfigurationLocked(0 /* globalChanges */, false /* preserveWindow */);
         assertEquals(expectedActivityBounds, record.getBounds());
     }
+
+
+    @Test
+    public void testCanBeLaunchedOnDisplay() throws Exception {
+        testSupportsLaunchingResizeable(false /*taskPresent*/, true /*taskResizeable*/,
+                true /*activityResizeable*/, true /*expected*/);
+
+        testSupportsLaunchingResizeable(false /*taskPresent*/, true /*taskResizeable*/,
+                false /*activityResizeable*/, false /*expected*/);
+
+        testSupportsLaunchingResizeable(true /*taskPresent*/, false /*taskResizeable*/,
+                true /*activityResizeable*/, false /*expected*/);
+
+        testSupportsLaunchingResizeable(true /*taskPresent*/, true /*taskResizeable*/,
+                false /*activityResizeable*/, true /*expected*/);
+    }
+
+    private void testSupportsLaunchingResizeable(boolean taskPresent, boolean taskResizeable,
+            boolean activityResizeable, boolean expected) {
+        final ActivityManagerService service = createActivityManagerService();
+        service.mSupportsMultiWindow = true;
+
+
+        final TaskRecord task = taskPresent
+                ? createTask(service, testActivityComponent, TEST_STACK_ID) : null;
+
+        if (task != null) {
+            task.setResizeMode(taskResizeable ? ActivityInfo.RESIZE_MODE_RESIZEABLE
+                    : ActivityInfo.RESIZE_MODE_UNRESIZEABLE);
+        }
+
+        final ActivityRecord record = createActivity(service, secondaryActivityComponent,
+                task);
+        record.info.resizeMode = activityResizeable ? ActivityInfo.RESIZE_MODE_RESIZEABLE
+                : ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+
+        record.canBeLaunchedOnDisplay(Display.DEFAULT_DISPLAY);
+
+        assertEquals(((TestActivityStackSupervisor) service.mStackSupervisor)
+                .getLastResizeableFromCanPlaceEntityOnDisplay(), expected);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
index 661dd4f..cd1843b 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
@@ -17,7 +17,10 @@
 package com.android.server.am;
 
 import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.HOME_STACK_ID;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
@@ -60,7 +63,7 @@
     public void testRestoringInvalidTask() throws Exception {
         final ActivityManagerService service = createActivityManagerService();
         TaskRecord task = service.mStackSupervisor.anyTaskForIdLocked(0 /*taskId*/,
-                MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, 0 /*stackId*/);
+                MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, null);
         assertNull(task);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index b534544..0cf1df8 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -163,6 +163,7 @@
      */
     protected static class TestActivityStackSupervisor extends ActivityStackSupervisor {
         private final ActivityDisplay mDisplay;
+        private boolean mLastResizeable;
 
         public TestActivityStackSupervisor(ActivityManagerService service, Looper looper) {
             super(service, looper);
@@ -170,6 +171,22 @@
             mDisplay = new ActivityDisplay();
         }
 
+        // TODO: Use Mockito spy instead. Currently not possible due to TestActivityStackSupervisor
+        // access to ActivityDisplay
+        @Override
+        boolean canPlaceEntityOnDisplay(int displayId, boolean resizeable, int callingPid,
+                int callingUid, ActivityInfo activityInfo) {
+            mLastResizeable = resizeable;
+            return super.canPlaceEntityOnDisplay(displayId, resizeable, callingPid, callingUid,
+                    activityInfo);
+        }
+
+        // TODO: remove and use Mockito verify once {@link #canPlaceEntityOnDisplay} override is
+        // removed.
+        public boolean getLastResizeableFromCanPlaceEntityOnDisplay() {
+            return mLastResizeable;
+        }
+
         // No home stack is set.
         @Override
         void moveHomeStackToFront(String reason) {
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
index e39ccca..5d2bb4d 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
@@ -102,7 +102,7 @@
         sWm.mSystemDecorLayer = 10000;
 
         mWindowToken = new WindowTestUtils.TestAppWindowToken(sWm.getDefaultDisplayContentLocked());
-        mStubStack = new TaskStack(sWm, 0);
+        mStubStack = new TaskStack(sWm, 0, null);
     }
 
     public void assertRect(Rect rect, int left, int top, int right, int bottom) {
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
index 2ae10aa..0315c8d 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
@@ -78,7 +78,7 @@
      */
     public static class TestTaskStack extends TaskStack {
         TestTaskStack(WindowManagerService service, int stackId) {
-            super(service, stackId);
+            super(service, stackId, null);
         }
 
         @Override
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 3788cf3..b040a63 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -20,6 +20,7 @@
 import static android.app.ActivityManager.START_ASSISTANT_NOT_ACTIVE_SESSION;
 import static android.app.ActivityManager.START_VOICE_HIDDEN_SESSION;
 import static android.app.ActivityManager.START_VOICE_NOT_ACTIVE_SESSION;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
 
 import android.app.ActivityManager;
 import android.app.ActivityManager.StackId;
@@ -222,8 +223,8 @@
             }
             intent = new Intent(intent);
             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            ActivityOptions options = ActivityOptions.makeBasic();
-            options.setLaunchStackId(StackId.ASSISTANT_STACK_ID);
+            final ActivityOptions options = ActivityOptions.makeBasic();
+            options.setLaunchActivityType(ACTIVITY_TYPE_ASSISTANT);
             return mAm.startAssistantActivity(mComponent.getPackageName(), callingPid, callingUid,
                     intent, resolvedType, options.toBundle(), mUser);
         } catch (RemoteException e) {
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index 629173d..7a53ef6 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -161,7 +161,7 @@
 
             // Second byte is the MSG_LEN, length of the message
             // See 3GPP2 C.S0023 3.4.27
-            int size = data[1];
+            int size = data[1] & 0xFF;
 
             // Note: Data may include trailing FF's.  That's OK; message
             // should still parse correctly.