diff options
159 files changed, 3704 insertions, 1400 deletions
diff --git a/Android.mk b/Android.mk index 7bb64482df73..aa7caa547e43 100644 --- a/Android.mk +++ b/Android.mk @@ -270,6 +270,7 @@ LOCAL_SRC_FILES += \ 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 a54a79a689b8..a62bffca7f64 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -4052,10 +4052,11 @@ package android.app { 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 @@ package android.app { 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 @@ -10197,6 +10199,7 @@ package android.content.pm { field public static final int PERSIST_ACROSS_REBOOTS = 2; // 0x2 field public static final int PERSIST_NEVER = 1; // 0x1 field public static final int PERSIST_ROOT_ONLY = 0; // 0x0 + field public static final int RESIZE_MODE_RESIZEABLE = 2; // 0x2 field public static final int SCREEN_ORIENTATION_BEHIND = 3; // 0x3 field public static final int SCREEN_ORIENTATION_FULL_SENSOR = 10; // 0xa field public static final int SCREEN_ORIENTATION_FULL_USER = 13; // 0xd diff --git a/cmds/incidentd/tests/EncodedBuffer_test.cpp b/cmds/incidentd/tests/EncodedBuffer_test.cpp index 98c39bded512..37a938a6de07 100644 --- a/cmds/incidentd/tests/EncodedBuffer_test.cpp +++ b/cmds/incidentd/tests/EncodedBuffer_test.cpp @@ -42,40 +42,17 @@ const string FIX64_FIELD_3 = "\x19\xff\xff\xff\xff\xff\xff\xff\xff"; // -1 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 @@ public: 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 9c2e63e42933..b9ee7ff201d5 100644 --- a/cmds/statsd/Android.mk +++ b/cmds/statsd/Android.mk @@ -40,8 +40,10 @@ include $(CLEAR_VARS) LOCAL_MODULE := statsd LOCAL_SRC_FILES := \ + ../../core/java/android/os/IStatsCompanionService.aidl \ ../../core/java/android/os/IStatsManager.aidl \ src/StatsService.cpp \ + src/AnomalyMonitor.cpp \ src/LogEntryPrinter.cpp \ src/LogReader.cpp \ src/main.cpp \ @@ -117,8 +119,10 @@ LOCAL_C_INCLUDES += $(LOCAL_PATH)/src \ STATSD_PROTO_INCLUDES LOCAL_SRC_FILES := \ + ../../core/java/android/os/IStatsCompanionService.aidl \ ../../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 000000000000..2d3454a831f9 --- /dev/null +++ b/cmds/statsd/src/AnomalyMonitor.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "AnomalyMonitor" +#define DEBUG true + +#include "AnomalyMonitor.h" + +#include <cutils/log.h> + +namespace android { +namespace os { +namespace statsd { + +AnomalyMonitor::AnomalyMonitor(uint32_t minDiffToUpdateRegisteredAlarmTimeSec) + : mRegisteredAlarmTimeSec(0), + mMinUpdateTimeSec(minDiffToUpdateRegisteredAlarmTimeSec) { +} + +AnomalyMonitor::~AnomalyMonitor() { +} + +void AnomalyMonitor::setStatsCompanionService(sp<IStatsCompanionService> statsCompanionService) { + std::lock_guard<std::mutex> lock(mLock); + sp<IStatsCompanionService> tmpForLock = mStatsCompanionService; + mStatsCompanionService = statsCompanionService; + if (statsCompanionService == nullptr) { + if (DEBUG) ALOGD("Erasing link to statsCompanionService"); + return; + } + if (DEBUG) ALOGD("Creating link to statsCompanionService"); + const sp<const AnomalyAlarm> top = mPq.top(); + if (top != nullptr) { + updateRegisteredAlarmTime_l(top->timestampSec); + } +} + +void AnomalyMonitor::add(sp<const AnomalyAlarm> alarm) { + std::lock_guard<std::mutex> lock(mLock); + 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; + } + // 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_l(alarm->timestampSec); + } +} + +void AnomalyMonitor::remove(sp<const AnomalyAlarm> alarm) { + std::lock_guard<std::mutex> lock(mLock); + if (alarm == nullptr) { + ALOGW("Asked to remove a null alarm."); + return; + } + 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; + if (mStatsCompanionService != nullptr) { + mStatsCompanionService->cancelAnomalyAlarm(); + } + return; + } + uint32_t soonestAlarmTimeSec = mPq.top()->timestampSec; + if (DEBUG) ALOGD("Soonest alarm is %u", soonestAlarmTimeSec); + if (soonestAlarmTimeSec > mRegisteredAlarmTimeSec + mMinUpdateTimeSec) { + updateRegisteredAlarmTime_l(soonestAlarmTimeSec); + } +} + +void AnomalyMonitor::updateRegisteredAlarmTime_l(uint32_t timestampSec) { + if (DEBUG) ALOGD("Updating reg alarm time to %u", timestampSec); + mRegisteredAlarmTimeSec = timestampSec; + if (mStatsCompanionService != nullptr) { + mStatsCompanionService->setAnomalyAlarm(secToMs(mRegisteredAlarmTimeSec)); + } +} + +int64_t AnomalyMonitor::secToMs(uint32_t timeSec) { + return ((int64_t) timeSec) * 1000; +} + +} // namespace statsd +} // namespace os +} // namespace android diff --git a/cmds/statsd/src/AnomalyMonitor.h b/cmds/statsd/src/AnomalyMonitor.h new file mode 100644 index 000000000000..e89afa8a6497 --- /dev/null +++ b/cmds/statsd/src/AnomalyMonitor.h @@ -0,0 +1,138 @@ +/* + * 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; + +using android::os::IStatsCompanionService; + +namespace android { +namespace os { +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 RefBase { + 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(); + + /** + * Tells AnomalyMonitor what IStatsCompanionService to use and, if + * applicable, immediately registers an existing alarm with it. + * If nullptr, AnomalyMonitor will continue to add/remove alarms, but won't + * update IStatsCompanionService (until such time as it is set non-null). + */ + void setStatsCompanionService(sp<IStatsCompanionService> statsCompanionService); + + /** + * 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: + 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> mStatsCompanionService = nullptr; + + /** + * Amount by which the soonest projected alarm must differ from + * mRegisteredAlarmTimeSec before updateRegisteredAlarmTime_l is called. + */ + uint32_t mMinUpdateTimeSec; + + /** + * Updates the alarm registered with StatsCompanionService to the given time. + * Also correspondingly updates mRegisteredAlarmTimeSec. + */ + void updateRegisteredAlarmTime_l(uint32_t timestampSec); + + /** Converts uint32 timestamp in seconds to a Java long in msec. */ + int64_t secToMs(uint32_t timeSec); +}; + +} // namespace statsd +} // namespace os +} // namespace android + +#endif // ANOMALY_MONITOR_H
\ No newline at end of file diff --git a/cmds/statsd/src/DropboxReader.cpp b/cmds/statsd/src/DropboxReader.cpp index cda2f431e435..307e7712e5aa 100644 --- a/cmds/statsd/src/DropboxReader.cpp +++ b/cmds/statsd/src/DropboxReader.cpp @@ -23,11 +23,14 @@ using android::sp; using android::String16; using android::binder::Status; using android::base::unique_fd; -using android::os::statsd::EventMetricData; using android::os::DropBoxManager; using android::ZipUtils; using std::vector; +namespace android { +namespace os { +namespace statsd { + status_t DropboxReader::readStatsLogs(FILE* out, const string& tag, long msec) { sp<DropBoxManager> dropbox = new DropBoxManager(); StatsLogReport logReport; @@ -117,3 +120,7 @@ void DropboxReader::printLog(FILE* out, const StatsLogReport& logReport) { } fprintf(out, "\n"); } + +} // namespace statsd +} // namespace os +} // namespace android diff --git a/cmds/statsd/src/DropboxReader.h b/cmds/statsd/src/DropboxReader.h index f7d5a8205f57..b7f8739c9ad6 100644 --- a/cmds/statsd/src/DropboxReader.h +++ b/cmds/statsd/src/DropboxReader.h @@ -23,10 +23,13 @@ #include <stdio.h> using android::base::unique_fd; -using android::os::statsd::StatsLogReport; using android::status_t; using std::string; +namespace android { +namespace os { +namespace statsd { + class DropboxReader { public: // msec is the start timestamp. @@ -42,4 +45,8 @@ private: }; }; +} // namespace statsd +} // namespace os +} // namespace android + #endif //DROPBOX_READER_H diff --git a/cmds/statsd/src/DropboxWriter.cpp b/cmds/statsd/src/DropboxWriter.cpp index 01a9eac317d8..b9d48fa362d5 100644 --- a/cmds/statsd/src/DropboxWriter.cpp +++ b/cmds/statsd/src/DropboxWriter.cpp @@ -18,12 +18,16 @@ #include "DropboxWriter.h" -using android::os::DropBoxManager; using android::binder::Status; +using android::os::DropBoxManager; using android::sp; using android::String16; using std::vector; +namespace android { +namespace os { +namespace statsd { + DropboxWriter::DropboxWriter(const string& tag) : mTag(tag), mLogReport(), mBufferSize(0) { } @@ -57,3 +61,7 @@ void DropboxWriter::flush() { mLogReport.Clear(); mBufferSize = 0; } + +} // namespace statsd +} // namespace os +} // namespace android diff --git a/cmds/statsd/src/DropboxWriter.h b/cmds/statsd/src/DropboxWriter.h index 31b3f2764bb9..59629fb65b22 100644 --- a/cmds/statsd/src/DropboxWriter.h +++ b/cmds/statsd/src/DropboxWriter.h @@ -20,7 +20,10 @@ #include <frameworks/base/cmds/statsd/src/stats_log.pb.h> using std::string; -using android::os::statsd::StatsLogReport; + +namespace android { +namespace os { +namespace statsd { class DropboxWriter { public: @@ -62,4 +65,8 @@ private: }; +} // namespace statsd +} // namespace os +} // namespace android + #endif //DROPBOX_WRITER_H diff --git a/cmds/statsd/src/LogEntryPrinter.cpp b/cmds/statsd/src/LogEntryPrinter.cpp index ba07308086ca..c877b0545795 100644 --- a/cmds/statsd/src/LogEntryPrinter.cpp +++ b/cmds/statsd/src/LogEntryPrinter.cpp @@ -22,6 +22,10 @@ using namespace android; +namespace android { +namespace os { +namespace statsd { + LogEntryPrinter::LogEntryPrinter(int out) :m_out(out) { @@ -59,3 +63,7 @@ LogEntryPrinter::OnLogEvent(const log_msg& msg) } } +} // namespace statsd +} // namespace os +} // namespace android + diff --git a/cmds/statsd/src/LogEntryPrinter.h b/cmds/statsd/src/LogEntryPrinter.h index 61ffddca0916..ed720dcd17ac 100644 --- a/cmds/statsd/src/LogEntryPrinter.h +++ b/cmds/statsd/src/LogEntryPrinter.h @@ -23,6 +23,10 @@ #include <stdio.h> +namespace android { +namespace os { +namespace statsd { + /** * Decodes the log entry and prints it to the supplied file descriptor. */ @@ -51,4 +55,8 @@ private: AndroidLogFormat* m_format; }; +} // namespace statsd +} // namespace os +} // namespace android + #endif // LOG_ENTRY_PRINTER_H diff --git a/cmds/statsd/src/LogReader.cpp b/cmds/statsd/src/LogReader.cpp index 2a9e5005499c..c9164f914cd2 100644 --- a/cmds/statsd/src/LogReader.cpp +++ b/cmds/statsd/src/LogReader.cpp @@ -26,6 +26,10 @@ using namespace android; using namespace std; +namespace android { +namespace os { +namespace statsd { + #define SNOOZE_INITIAL_MS 100 #define SNOOZE_MAX_MS (10 * 60 * 1000) // Ten minutes @@ -141,3 +145,6 @@ LogReader::connect_and_read() return lineCount; } +} // namespace statsd +} // namespace os +} // namespace android diff --git a/cmds/statsd/src/LogReader.h b/cmds/statsd/src/LogReader.h index 08a17a31aa18..4c2afe8ba43f 100644 --- a/cmds/statsd/src/LogReader.h +++ b/cmds/statsd/src/LogReader.h @@ -18,11 +18,14 @@ #define LOGREADER_H #include <log/log_read.h> - #include <utils/RefBase.h> #include <vector> +namespace android { +namespace os { +namespace statsd { + /** * Callback for LogReader */ @@ -78,4 +81,8 @@ private: int connect_and_read(); }; +} // namespace statsd +} // namespace os +} // namespace android + #endif // LOGREADER_H diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp index c2fffd8a2d84..1ae23ef8af13 100644 --- a/cmds/statsd/src/StatsLogProcessor.cpp +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -21,8 +21,10 @@ #include <parse_util.h> using namespace android; -using android::os::statsd::EventMetricData; -using android::os::statsd::StatsLogReport; + +namespace android { +namespace os { +namespace statsd { StatsLogProcessor::StatsLogProcessor() : m_dropbox_writer("all-logs") { @@ -71,3 +73,7 @@ StatsLogProcessor::UpdateConfig(const int config_source, StatsdConfig config) m_configs[config_source] = config; ALOGD("Updated configuration for source %i", config_source); } + +} // namespace statsd +} // namespace os +} // namespace android diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h index 5df84245a406..a6d182cac47a 100644 --- a/cmds/statsd/src/StatsLogProcessor.h +++ b/cmds/statsd/src/StatsLogProcessor.h @@ -20,7 +20,9 @@ #include <unordered_map> -using android::os::statsd::StatsdConfig; +namespace android { +namespace os { +namespace statsd { class StatsLogProcessor : public LogListener { @@ -51,4 +53,9 @@ private: */ std::unordered_map<int, StatsdConfig> m_configs; }; + +} // namespace statsd +} // namespace os +} // namespace android + #endif //STATS_LOG_PROCESSOR_H diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index 24413f65fb9f..965c9b7192de 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -15,6 +15,7 @@ */ #define LOG_TAG "statsd" +#define DEBUG true #include "StatsService.h" #include "DropboxReader.h" @@ -33,10 +34,13 @@ #include <stdlib.h> using namespace android; -using android::os::statsd::StatsdConfig; -// ================================================================================ +namespace android { +namespace os { +namespace statsd { + StatsService::StatsService(const sp<Looper>& handlerLooper) + : mAnomalyMonitor(new AnomalyMonitor(2)) // TODO: Change this based on the config { ALOGD("stats service constructed"); } @@ -162,6 +166,38 @@ StatsService::doLoadConfig(FILE* in) } Status +StatsService::informAnomalyAlarmFired() +{ + if (DEBUG) ALOGD("StatsService::informAnomalyAlarmFired was called"); + + if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) { + return Status::fromExceptionCode(Status::EX_SECURITY, + "Only system uid can call informAnomalyAlarmFired"); + } + + if (DEBUG) ALOGD("StatsService::informAnomalyAlarmFired succeeded"); + // TODO: check through all counters/timers and see if an anomaly has indeed occurred. + + return Status::ok(); +} + +Status +StatsService::informPollAlarmFired() +{ + if (DEBUG) ALOGD("StatsService::informPollAlarmFired was called"); + + if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) { + return Status::fromExceptionCode(Status::EX_SECURITY, + "Only system uid can call informPollAlarmFired"); + } + + if (DEBUG) 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) { @@ -172,9 +208,68 @@ StatsService::systemRunning() // When system_server is up and running, schedule the dropbox task to run. ALOGD("StatsService::systemRunning"); + sayHiToStatsCompanion(); + + return Status::ok(); +} + +void +StatsService::sayHiToStatsCompanion() +{ + // TODO: This method needs to be private. It is temporarily public and unsecured for testing purposes. + sp<IStatsCompanionService> statsCompanion = getStatsCompanionService(); + if (statsCompanion != nullptr) { + if (DEBUG) ALOGD("Telling statsCompanion that statsd is ready"); + statsCompanion->statsdReady(); + } else { + if (DEBUG) ALOGD("Could not access statsCompanion"); + } +} + +sp<IStatsCompanionService> +StatsService::getStatsCompanionService() { + sp<IStatsCompanionService> statsCompanion = nullptr; + // Get statscompanion service from service manager + const sp<IServiceManager> sm(defaultServiceManager()); + if (sm != nullptr) { + const String16 name("statscompanion"); + statsCompanion = interface_cast<IStatsCompanionService>(sm->checkService(name)); + if (statsCompanion == nullptr) { + ALOGW("statscompanion service unavailable!"); + return nullptr; + } + } + return statsCompanion; +} + +Status +StatsService::statsCompanionReady() +{ + if (DEBUG) ALOGD("StatsService::statsCompanionReady was called"); + + if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) { + return Status::fromExceptionCode(Status::EX_SECURITY, + "Only system uid can call statsCompanionReady"); + } + + sp<IStatsCompanionService> statsCompanion = getStatsCompanionService(); + if (statsCompanion == nullptr) { + return Status::fromExceptionCode(Status::EX_NULL_POINTER, + "statscompanion unavailable despite it contacting statsd!"); + } + if (DEBUG) ALOGD("StatsService::statsCompanionReady linking to statsCompanion."); + IInterface::asBinder(statsCompanion)->linkToDeath(new StatsdDeathRecipient(mAnomalyMonitor)); + mAnomalyMonitor->setStatsCompanionService(statsCompanion); + return Status::ok(); } +void +StatsdDeathRecipient::binderDied(const wp<IBinder>& who) { + ALOGW("statscompanion service died"); + mAnmlyMntr->setStatsCompanionService(nullptr); +} + status_t StatsService::doPrintStatsLog(FILE* out, const Vector<String8>& args) { long msec = 0; @@ -191,3 +286,7 @@ StatsService::printCmdHelp(FILE* out) { fprintf(out, "\t print-stats-log [tag_required] [timestamp_nsec_optional]\n"); fprintf(out, "\t config\t Loads a new config from command-line (must be proto in wire-encoded format).\n"); } + +} // namespace statsd +} // namespace os +} // namespace android diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index ef52b5628c29..57276d2425e9 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -17,9 +17,11 @@ #ifndef STATS_SERVICE_H #define STATS_SERVICE_H +#include "AnomalyMonitor.h" #include "StatsLogProcessor.h" #include <android/os/BnStatsManager.h> +#include <android/os/IStatsCompanionService.h> #include <binder/IResultReceiver.h> #include <binder/IShellCallback.h> #include <frameworks/base/cmds/statsd/src/statsd_config.pb.h> @@ -33,9 +35,11 @@ using namespace android::base; using namespace android::binder; using namespace android::os; using namespace std; -using android::os::statsd::StatsdConfig; -// ================================================================================ +namespace android { +namespace os { +namespace statsd { + class StatsService : public BnStatsManager { public: StatsService(const sp<Looper>& handlerLooper); @@ -49,13 +53,49 @@ public: virtual Status systemRunning(); + // Inform statsd that statsCompanion is ready. + virtual Status statsCompanionReady(); + + virtual Status informAnomalyAlarmFired(); + + virtual Status informPollAlarmFired(); + virtual status_t setProcessor(const sp<StatsLogProcessor>& main_processor); + // TODO: public for testing since statsd doesn't run when system starts. Change to private later. + /** Inform statsCompanion that statsd is ready. */ + virtual void sayHiToStatsCompanion(); + private: sp<StatsLogProcessor> m_processor; // Reference to the processor for updating configs. + + const sp<AnomalyMonitor> mAnomalyMonitor; // TODO: Move this to a more logical file/class + status_t doPrintStatsLog(FILE* out, const Vector<String8>& args); + void printCmdHelp(FILE* out); + status_t doLoadConfig(FILE* in); + + /** Fetches the StatsCompanionService. */ + sp<IStatsCompanionService> getStatsCompanionService(); +}; + +// --- StatsdDeathRecipient --- +class StatsdDeathRecipient : public IBinder::DeathRecipient { +public: + StatsdDeathRecipient(sp<AnomalyMonitor> anomalyMonitor) + : mAnmlyMntr(anomalyMonitor) { + } + + virtual void binderDied(const wp<IBinder>& who); + +private: + const sp<AnomalyMonitor> mAnmlyMntr; }; +} // namespace statsd +} // namespace os +} // namespace android + #endif // STATS_SERVICE_H diff --git a/cmds/statsd/src/indexed_priority_queue.h b/cmds/statsd/src/indexed_priority_queue.h new file mode 100644 index 000000000000..76409c07523a --- /dev/null +++ b/cmds/statsd/src/indexed_priority_queue.h @@ -0,0 +1,199 @@ +/* + * 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 android { +namespace os { +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 +} // namespace os +} // namespace android + +#endif //STATSD_INDEXED_PRIORITY_QUEUE_H diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp index f9265c642dfb..c1dad4f1ed3f 100644 --- a/cmds/statsd/src/main.cpp +++ b/cmds/statsd/src/main.cpp @@ -36,6 +36,7 @@ #include <unistd.h> using namespace android; +using namespace android::os::statsd; // ================================================================================ /** @@ -129,6 +130,10 @@ main(int /*argc*/, char** /*argv*/) return -1; } + // TODO: This line is temporary, since statsd doesn't start up automatically (and therefore + // the call in StatsService::SystemRunning() won't ever be called right now). + service->sayHiToStatsCompanion(); + // Start the log reader thread err = start_log_reader_thread(service); if (err != NO_ERROR) { diff --git a/cmds/statsd/src/parse_util.cpp b/cmds/statsd/src/parse_util.cpp index 9caeacf3b538..ffce88424d93 100644 --- a/cmds/statsd/src/parse_util.cpp +++ b/cmds/statsd/src/parse_util.cpp @@ -17,6 +17,7 @@ #include <parse_util.h> #include <log/log_event_list.h> +using android::os::statsd::EVENT_TIMESTAMP; using android::os::statsd::EventMetricData; using android::os::statsd::KeyId; using android::os::statsd::KeyId_IsValid; @@ -29,6 +30,13 @@ EventMetricData parse(log_msg msg) // dump all statsd logs to dropbox for now. // TODO: Add filtering, aggregation, etc. EventMetricData eventMetricData; + + // set timestamp of the event. + KeyValuePair *keyValuePair = eventMetricData.add_key_value_pair(); + keyValuePair->set_key(EVENT_TIMESTAMP); + keyValuePair->set_value_int(msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec); + + // start iterating k,v pairs. android_log_context context = create_android_log_parser(const_cast<log_msg*>(&msg)->msg() + sizeof(uint32_t), const_cast<log_msg*>(&msg)->len() diff --git a/cmds/statsd/src/stats_constants.proto b/cmds/statsd/src/stats_constants.proto index 3f8bd1c5a9fc..9758a2e0cb89 100644 --- a/cmds/statsd/src/stats_constants.proto +++ b/cmds/statsd/src/stats_constants.proto @@ -24,7 +24,8 @@ option java_outer_classname = "StatsConstantsProto"; enum TagId { WAKELOCK = 1; - SCREEN = 1003; + SCREEN = 2; + PROCESS = 1112; // TODO: Temporary usage only for testing. } enum KeyId { 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 000000000000..1aad08918ad9 --- /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 android::os::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 c8297286b784..df68f14efec9 100644 --- a/config/compiled-classes-phone +++ b/config/compiled-classes-phone @@ -3824,7 +3824,6 @@ android.system.PacketSocketAddress android.system.StructAddrinfo android.system.StructFlock android.system.StructGroupReq -android.system.StructGroupSourceReq android.system.StructIcmpHdr android.system.StructIfaddrs android.system.StructLinger @@ -5243,7 +5242,6 @@ com.android.internal.app.IVoiceInteractor 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 cb3cbe196230..337d7a0ad8bb 100644 --- a/config/preloaded-classes +++ b/config/preloaded-classes @@ -2006,7 +2006,6 @@ android.system.PacketSocketAddress android.system.StructAddrinfo android.system.StructFlock android.system.StructGroupReq -android.system.StructGroupSourceReq android.system.StructIfaddrs android.system.StructLinger android.system.StructPasswd @@ -2786,7 +2785,6 @@ com.android.internal.app.IVoiceInteractionManagerService$Stub 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/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index a8665037f8d3..78d05f5123c8 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -770,21 +770,6 @@ public class ActivityManager { } /** - * 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 @@ public class ActivityManager { 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 @@ public class ActivityManager { } 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 0bffc9e6cee5..a68c3a5c29a6 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -18,6 +18,8 @@ package android.app; 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 @@ public class ActivityOptions { 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 @@ public class ActivityOptions { 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 @@ public class ActivityOptions { 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 @@ public class ActivityOptions { } /** @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 @@ public class ActivityOptions { 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 c567946a830d..eccb264796f8 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -553,11 +553,6 @@ interface IActivityManager { */ 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/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl index b5b101773f15..a56965bdbd4d 100644 --- a/core/java/android/app/ITaskStackListener.aidl +++ b/core/java/android/app/ITaskStackListener.aidl @@ -30,7 +30,7 @@ oneway interface ITaskStackListener { void onTaskStackChanged(); /** Called whenever an Activity is moved to the pinned stack from another stack. */ - void onActivityPinned(String packageName, int taskId); + void onActivityPinned(String packageName, int userId, int taskId); /** Called whenever an Activity is moved from the pinned stack to another stack. */ void onActivityUnpinned(); diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index ee6c1cbaecfe..60f4ed01805c 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -67,7 +67,6 @@ import android.text.style.TextAppearanceSpan; import android.util.ArraySet; import android.util.Log; import android.util.SparseArray; -import android.util.TypedValue; import android.view.Gravity; import android.view.NotificationHeaderView; import android.view.View; @@ -3906,7 +3905,6 @@ public class Notification implements Parcelable if (p.title != null) { contentView.setViewVisibility(R.id.title, View.VISIBLE); contentView.setTextViewText(R.id.title, processTextSpans(p.title)); - updateTextSizePrimary(contentView, R.id.title); if (!p.ambient) { setTextViewColorPrimary(contentView, R.id.title); } @@ -3918,7 +3916,6 @@ public class Notification implements Parcelable int textId = showProgress ? com.android.internal.R.id.text_line_1 : com.android.internal.R.id.text; contentView.setTextViewText(textId, processTextSpans(p.text)); - updateTextSizeSecondary(contentView, textId); if (!p.ambient) { setTextViewColorSecondary(contentView, textId); } @@ -3930,25 +3927,6 @@ public class Notification implements Parcelable return contentView; } - private void updateTextSizeSecondary(RemoteViews contentView, int textId) { - updateTextSizeColorized(contentView, textId, - com.android.internal.R.dimen.notification_text_size_colorized, - com.android.internal.R.dimen.notification_text_size); - } - - private void updateTextSizePrimary(RemoteViews contentView, int textId) { - updateTextSizeColorized(contentView, textId, - com.android.internal.R.dimen.notification_title_text_size_colorized, - com.android.internal.R.dimen.notification_title_text_size); - } - - private void updateTextSizeColorized(RemoteViews contentView, int textId, - int colorizedDimen, int normalDimen) { - int size = mContext.getResources().getDimensionPixelSize(isColorized() - ? colorizedDimen : normalDimen); - contentView.setTextViewTextSize(textId, TypedValue.COMPLEX_UNIT_PX, size); - } - private CharSequence processTextSpans(CharSequence text) { if (hasForegroundColor()) { return NotificationColorUtil.clearColorSpans(text); @@ -5874,7 +5852,6 @@ public class Notification implements Parcelable builder.setTextViewColorSecondary(contentView, R.id.big_text); contentView.setViewVisibility(R.id.big_text, TextUtils.isEmpty(bigTextText) ? View.GONE : View.VISIBLE); - builder.updateTextSizeSecondary(contentView, R.id.big_text); contentView.setBoolean(R.id.big_text, "setHasImage", builder.mN.hasLargeIcon()); } } @@ -6208,7 +6185,6 @@ public class Notification implements Parcelable contentView.setViewVisibility(rowId, View.VISIBLE); contentView.setTextViewText(rowId, mBuilder.processTextSpans( makeMessageLine(m, mBuilder))); - mBuilder.updateTextSizeSecondary(contentView, rowId); mBuilder.setTextViewColorSecondary(contentView, rowId); if (contractedMessage == m) { @@ -6576,7 +6552,6 @@ public class Notification implements Parcelable contentView.setViewVisibility(rowIds[i], View.VISIBLE); contentView.setTextViewText(rowIds[i], mBuilder.processTextSpans(mBuilder.processLegacyText(str))); - mBuilder.updateTextSizeSecondary(contentView, rowIds[i]); mBuilder.setTextViewColorSecondary(contentView, rowIds[i]); contentView.setViewPadding(rowIds[i], 0, topPadding, 0, 0); handleInboxImageMargin(contentView, rowIds[i], first); diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java index a52ca0a64cd2..4674c9cd2389 100644 --- a/core/java/android/app/TaskStackListener.java +++ b/core/java/android/app/TaskStackListener.java @@ -31,7 +31,8 @@ public abstract class TaskStackListener extends ITaskStackListener.Stub { } @Override - public void onActivityPinned(String packageName, int taskId) throws RemoteException { + public void onActivityPinned(String packageName, int userId, int taskId) + throws RemoteException { } @Override diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java index 07eb5de15d9f..0cb38046826f 100644 --- a/core/java/android/app/WindowConfiguration.java +++ b/core/java/android/app/WindowConfiguration.java @@ -63,8 +63,21 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu /** * 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 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu 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/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java index 8a1eae2da976..dc9970a7ca42 100644 --- a/core/java/android/appwidget/AppWidgetHostView.java +++ b/core/java/android/appwidget/AppWidgetHostView.java @@ -23,17 +23,12 @@ import android.content.pm.LauncherApps; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.Canvas; import android.graphics.Color; -import android.graphics.Paint; import android.graphics.Rect; import android.os.Build; import android.os.Bundle; import android.os.CancellationSignal; -import android.os.Parcel; import android.os.Parcelable; -import android.os.SystemClock; import android.util.AttributeSet; import android.util.Log; import android.util.SparseArray; @@ -58,17 +53,17 @@ import java.util.concurrent.Executor; * {@link RemoteViews}. */ public class AppWidgetHostView extends FrameLayout { + static final String TAG = "AppWidgetHostView"; + private static final String KEY_JAILED_ARRAY = "jail"; + static final boolean LOGD = false; - static final boolean CROSSFADE = false; static final int VIEW_MODE_NOINIT = 0; static final int VIEW_MODE_CONTENT = 1; static final int VIEW_MODE_ERROR = 2; static final int VIEW_MODE_DEFAULT = 3; - static final int FADE_DURATION = 1000; - // When we're inflating the initialLayout for a AppWidget, we only allow // views that are allowed in RemoteViews. static final LayoutInflater.Filter sInflaterFilter = new LayoutInflater.Filter() { @@ -85,9 +80,6 @@ public class AppWidgetHostView extends FrameLayout { View mView; int mViewMode = VIEW_MODE_NOINIT; int mLayoutId = -1; - long mFadeStartTime = -1; - Bitmap mOld; - Paint mOldPaint = new Paint(); private OnClickHandler mOnClickHandler; private Executor mAsyncExecutor; @@ -212,9 +204,12 @@ public class AppWidgetHostView extends FrameLayout { @Override protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { - final ParcelableSparseArray jail = new ParcelableSparseArray(); + final SparseArray<Parcelable> jail = new SparseArray<>(); super.dispatchSaveInstanceState(jail); - container.put(generateId(), jail); + + Bundle bundle = new Bundle(); + bundle.putSparseParcelableArray(KEY_JAILED_ARRAY, jail); + container.put(generateId(), bundle); } private int generateId() { @@ -226,12 +221,12 @@ public class AppWidgetHostView extends FrameLayout { protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { final Parcelable parcelable = container.get(generateId()); - ParcelableSparseArray jail = null; - if (parcelable != null && parcelable instanceof ParcelableSparseArray) { - jail = (ParcelableSparseArray) parcelable; + SparseArray<Parcelable> jail = null; + if (parcelable instanceof Bundle) { + jail = ((Bundle) parcelable).getSparseParcelableArray(KEY_JAILED_ARRAY); } - if (jail == null) jail = new ParcelableSparseArray(); + if (jail == null) jail = new SparseArray<>(); try { super.dispatchRestoreInstanceState(jail); @@ -383,31 +378,10 @@ public class AppWidgetHostView extends FrameLayout { * @hide */ protected void applyRemoteViews(RemoteViews remoteViews, boolean useAsyncIfPossible) { - if (LOGD) Log.d(TAG, "updateAppWidget called mOld=" + mOld); - boolean recycled = false; View content = null; Exception exception = null; - // Capture the old view into a bitmap so we can do the crossfade. - if (CROSSFADE) { - if (mFadeStartTime < 0) { - if (mView != null) { - final int width = mView.getWidth(); - final int height = mView.getHeight(); - try { - mOld = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - } catch (OutOfMemoryError e) { - // we just won't do the fade - mOld = null; - } - if (mOld != null) { - //mView.drawIntoBitmap(mOld); - } - } - } - } - if (mLastExecutionSignal != null) { mLastExecutionSignal.cancel(); mLastExecutionSignal = null; @@ -484,16 +458,6 @@ public class AppWidgetHostView extends FrameLayout { removeView(mView); mView = content; } - - if (CROSSFADE) { - if (mFadeStartTime < 0) { - // if there is already an animation in progress, don't do anything -- - // the new view will pop in on top of the old one during the cross fade, - // and that looks okay. - mFadeStartTime = SystemClock.uptimeMillis(); - invalidate(); - } - } } private void updateContentDescription(AppWidgetProviderInfo info) { @@ -617,45 +581,6 @@ public class AppWidgetHostView extends FrameLayout { } } - @Override - protected boolean drawChild(Canvas canvas, View child, long drawingTime) { - if (CROSSFADE) { - int alpha; - int l = child.getLeft(); - int t = child.getTop(); - if (mFadeStartTime > 0) { - alpha = (int)(((drawingTime-mFadeStartTime)*255)/FADE_DURATION); - if (alpha > 255) { - alpha = 255; - } - Log.d(TAG, "drawChild alpha=" + alpha + " l=" + l + " t=" + t - + " w=" + child.getWidth()); - if (alpha != 255 && mOld != null) { - mOldPaint.setAlpha(255-alpha); - //canvas.drawBitmap(mOld, l, t, mOldPaint); - } - } else { - alpha = 255; - } - int restoreTo = canvas.saveLayerAlpha(l, t, child.getWidth(), child.getHeight(), alpha, - Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG); - boolean rv = super.drawChild(canvas, child, drawingTime); - canvas.restoreToCount(restoreTo); - if (alpha < 255) { - invalidate(); - } else { - mFadeStartTime = -1; - if (mOld != null) { - mOld.recycle(); - mOld = null; - } - } - return rv; - } else { - return super.drawChild(canvas, child, drawingTime); - } - } - /** * Prepare the given view to be shown. This might include adjusting * {@link FrameLayout.LayoutParams} before inserting. @@ -740,36 +665,4 @@ public class AppWidgetHostView extends FrameLayout { super.onInitializeAccessibilityNodeInfoInternal(info); info.setClassName(AppWidgetHostView.class.getName()); } - - private static class ParcelableSparseArray extends SparseArray<Parcelable> implements Parcelable { - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - final int count = size(); - dest.writeInt(count); - for (int i = 0; i < count; i++) { - dest.writeInt(keyAt(i)); - dest.writeParcelable(valueAt(i), 0); - } - } - - public static final Parcelable.Creator<ParcelableSparseArray> CREATOR = - new Parcelable.Creator<ParcelableSparseArray>() { - public ParcelableSparseArray createFromParcel(Parcel source) { - final ParcelableSparseArray array = new ParcelableSparseArray(); - final ClassLoader loader = array.getClass().getClassLoader(); - final int count = source.readInt(); - for (int i = 0; i < count; i++) { - array.put(source.readInt(), source.readParcelable(loader)); - } - return array; - } - - public ParcelableSparseArray[] newArray(int size) { - return new ParcelableSparseArray[size]; - } - }; - } } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 2d8249acb5bf..03e4dfe829de 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -2991,6 +2991,7 @@ public abstract class Context { //@hide: CONTEXTHUB_SERVICE, SYSTEM_HEALTH_SERVICE, //@hide: INCIDENT_SERVICE, + //@hide: STATS_COMPANION_SERVICE, COMPANION_DEVICE_SERVICE }) @Retention(RetentionPolicy.SOURCE) @@ -4020,6 +4021,12 @@ public abstract class Context { 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/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index 486ff43a6467..cd8201f8fb89 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -17,6 +17,7 @@ package android.content.pm; import android.annotation.IntDef; +import android.annotation.TestApi; import android.content.Intent; import android.content.res.Configuration; import android.content.res.Configuration.NativeConfig; @@ -180,6 +181,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { * Activity explicitly requested to be resizeable. * @hide */ + @TestApi public static final int RESIZE_MODE_RESIZEABLE = 2; /** * Activity is resizeable and supported picture-in-picture mode. This flag is now deprecated diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java index f894f0536b52..c28583ea867a 100644 --- a/core/java/android/database/sqlite/SQLiteConnection.java +++ b/core/java/android/database/sqlite/SQLiteConnection.java @@ -104,7 +104,7 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen private PreparedStatement mPreparedStatementPool; // The recent operations log. - private final OperationLog mRecentOperations = new OperationLog(); + private final OperationLog mRecentOperations; // The native SQLiteConnection pointer. (FOR INTERNAL USE ONLY) private long mConnectionPtr; @@ -162,6 +162,7 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen SQLiteDatabaseConfiguration configuration, int connectionId, boolean primaryConnection) { mPool = pool; + mRecentOperations = new OperationLog(mPool); mConfiguration = new SQLiteDatabaseConfiguration(configuration); mConnectionId = connectionId; mIsPrimaryConnection = primaryConnection; @@ -1298,6 +1299,11 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen private final Operation[] mOperations = new Operation[MAX_RECENT_OPERATIONS]; private int mIndex; private int mGeneration; + private final SQLiteConnectionPool mPool; + + OperationLog(SQLiteConnectionPool pool) { + mPool = pool; + } public int beginOperation(String kind, String sql, Object[] bindArgs) { synchronized (mOperations) { @@ -1381,8 +1387,10 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen } operation.mEndTime = SystemClock.uptimeMillis(); operation.mFinished = true; + final long execTime = operation.mEndTime - operation.mStartTime; + mPool.onStatementExecuted(execTime); return SQLiteDebug.DEBUG_LOG_SLOW_QUERIES && SQLiteDebug.shouldLogSlowQuery( - operation.mEndTime - operation.mStartTime); + execTime); } return false; } @@ -1426,11 +1434,16 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen int index = mIndex; Operation operation = mOperations[index]; if (operation != null) { + // Note: SimpleDateFormat is not thread-safe, cannot be compile-time created, + // and is relatively expensive to create during preloading. This method is only + // used when dumping a connection, which is a rare (mainly error) case. + SimpleDateFormat opDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); int n = 0; do { StringBuilder msg = new StringBuilder(); msg.append(" ").append(n).append(": ["); - msg.append(operation.getFormattedStartTime()); + String formattedStartTime = opDF.format(new Date(operation.mStartWallTime)); + msg.append(formattedStartTime); msg.append("] "); operation.describe(msg, verbose); printer.println(msg.toString()); @@ -1518,12 +1531,5 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen return methodName; } - private String getFormattedStartTime() { - // Note: SimpleDateFormat is not thread-safe, cannot be compile-time created, and is - // relatively expensive to create during preloading. This method is only used - // when dumping a connection, which is a rare (mainly error) case. So: - // DO NOT CACHE. - return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date(mStartWallTime)); - } } } diff --git a/core/java/android/database/sqlite/SQLiteConnectionPool.java b/core/java/android/database/sqlite/SQLiteConnectionPool.java index b66bf18fca1d..8b0fef4fe2bc 100644 --- a/core/java/android/database/sqlite/SQLiteConnectionPool.java +++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java @@ -37,6 +37,7 @@ import java.util.ArrayList; import java.util.Map; import java.util.WeakHashMap; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.LockSupport; /** @@ -102,6 +103,8 @@ public final class SQLiteConnectionPool implements Closeable { @GuardedBy("mLock") private IdleConnectionHandler mIdleConnectionHandler; + private final AtomicLong mTotalExecutionTimeCounter = new AtomicLong(0); + // Describes what should happen to an acquired connection when it is returned to the pool. enum AcquiredConnectionStatus { // The connection should be returned to the pool as usual. @@ -523,6 +526,10 @@ public final class SQLiteConnectionPool implements Closeable { mConnectionLeaked.set(true); } + void onStatementExecuted(long executionTimeMs) { + mTotalExecutionTimeCounter.addAndGet(executionTimeMs); + } + // Can't throw. private void closeAvailableConnectionsAndLogExceptionsLocked() { closeAvailableNonPrimaryConnectionsAndLogExceptionsLocked(); @@ -1076,6 +1083,7 @@ public final class SQLiteConnectionPool implements Closeable { printer.println("Connection pool for " + mConfiguration.path + ":"); printer.println(" Open: " + mIsOpen); printer.println(" Max connections: " + mMaxConnectionPoolSize); + printer.println(" Total execution time: " + mTotalExecutionTimeCounter); if (mConfiguration.isLookasideConfigSet()) { printer.println(" Lookaside config: sz=" + mConfiguration.lookasideSlotSize + " cnt=" + mConfiguration.lookasideSlotCount); diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index aa35a6610db7..931b5c913851 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -16,10 +16,11 @@ package android.hardware; -import android.app.ActivityThread; +import static android.system.OsConstants.*; + import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; -import android.app.job.JobInfo; +import android.app.ActivityThread; import android.content.Context; import android.graphics.ImageFormat; import android.graphics.Point; @@ -34,11 +35,11 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.renderscript.Allocation; import android.renderscript.Element; -import android.renderscript.RenderScript; import android.renderscript.RSIllegalArgumentException; +import android.renderscript.RenderScript; import android.renderscript.Type; -import android.util.Log; import android.text.TextUtils; +import android.util.Log; import android.view.Surface; import android.view.SurfaceHolder; @@ -48,8 +49,6 @@ import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; -import static android.system.OsConstants.*; - /** * The Camera class is used to set image capture settings, start/stop preview, * snap pictures, and retrieve frames for encoding for video. This class is a @@ -243,12 +242,19 @@ public class Camera { /** * Returns the number of physical cameras available on this device. + * + * @return total number of accessible camera devices, or 0 if there are no + * cameras or an error was encountered enumerating them. */ public native static int getNumberOfCameras(); /** * Returns the information about a particular camera. * If {@link #getNumberOfCameras()} returns N, the valid id is 0 to N-1. + * + * @throws RuntimeException if an invalid ID is provided, or if there is an + * error retrieving the information (generally due to a hardware or other + * low-level failure). */ public static void getCameraInfo(int cameraId, CameraInfo cameraInfo) { _getCameraInfo(cameraId, cameraInfo); @@ -362,7 +368,10 @@ public class Camera { /** * Creates a new Camera object to access the first back-facing camera on the * device. If the device does not have a back-facing camera, this returns - * null. + * null. Otherwise acts like the {@link #open(int)} call. + * + * @return a new Camera object for the first back-facing camera, or null if there is no + * backfacing camera * @see #open(int) */ public static Camera open() { @@ -609,6 +618,8 @@ public class Camera { * * @throws IOException if a connection cannot be re-established (for * example, if the camera is still in use by another process). + * @throws RuntimeException if release() has been called on this Camera + * instance. */ public native final void reconnect() throws IOException; @@ -637,6 +648,8 @@ public class Camera { * or null to remove the preview surface * @throws IOException if the method fails (for example, if the surface * is unavailable or unsuitable). + * @throws RuntimeException if release() has been called on this Camera + * instance. */ public final void setPreviewDisplay(SurfaceHolder holder) throws IOException { if (holder != null) { @@ -684,6 +697,8 @@ public class Camera { * texture * @throws IOException if the method fails (for example, if the surface * texture is unavailable or unsuitable). + * @throws RuntimeException if release() has been called on this Camera + * instance. */ public native final void setPreviewTexture(SurfaceTexture surfaceTexture) throws IOException; @@ -733,12 +748,20 @@ public class Camera { * {@link #setPreviewCallbackWithBuffer(Camera.PreviewCallback)} were * called, {@link Camera.PreviewCallback#onPreviewFrame(byte[], Camera)} * will be called when preview data becomes available. + * + * @throws RuntimeException if starting preview fails; usually this would be + * because of a hardware or other low-level error, or because release() + * has been called on this Camera instance. */ public native final void startPreview(); /** * Stops capturing and drawing preview frames to the surface, and * resets the camera for a future call to {@link #startPreview()}. + * + * @throws RuntimeException if stopping preview fails; usually this would be + * because of a hardware or other low-level error, or because release() + * has been called on this Camera instance. */ public final void stopPreview() { _stopPreview(); @@ -777,6 +800,8 @@ public class Camera { * * @param cb a callback object that receives a copy of each preview frame, * or null to stop receiving callbacks. + * @throws RuntimeException if release() has been called on this Camera + * instance. * @see android.media.MediaActionSound */ public final void setPreviewCallback(PreviewCallback cb) { @@ -803,6 +828,8 @@ public class Camera { * * @param cb a callback object that receives a copy of the next preview frame, * or null to stop receiving callbacks. + * @throws RuntimeException if release() has been called on this Camera + * instance. * @see android.media.MediaActionSound */ public final void setOneShotPreviewCallback(PreviewCallback cb) { @@ -840,6 +867,8 @@ public class Camera { * * @param cb a callback object that receives a copy of the preview frame, * or null to stop receiving callbacks and clear the buffer queue. + * @throws RuntimeException if release() has been called on this Camera + * instance. * @see #addCallbackBuffer(byte[]) * @see android.media.MediaActionSound */ @@ -1259,6 +1288,9 @@ public class Camera { * success sound to the user.</p> * * @param cb the callback to run + * @throws RuntimeException if starting autofocus fails; usually this would + * be because of a hardware or other low-level error, or because + * release() has been called on this Camera instance. * @see #cancelAutoFocus() * @see android.hardware.Camera.Parameters#setAutoExposureLock(boolean) * @see android.hardware.Camera.Parameters#setAutoWhiteBalanceLock(boolean) @@ -1279,6 +1311,9 @@ public class Camera { * this function will return the focus position to the default. * If the camera does not support auto-focus, this is a no-op. * + * @throws RuntimeException if canceling autofocus fails; usually this would + * be because of a hardware or other low-level error, or because + * release() has been called on this Camera instance. * @see #autoFocus(Camera.AutoFocusCallback) */ public final void cancelAutoFocus() @@ -1333,6 +1368,9 @@ public class Camera { * Sets camera auto-focus move callback. * * @param cb the callback to run + * @throws RuntimeException if enabling the focus move callback fails; + * usually this would be because of a hardware or other low-level error, + * or because release() has been called on this Camera instance. */ public void setAutoFocusMoveCallback(AutoFocusMoveCallback cb) { mAutoFocusMoveCallback = cb; @@ -1384,7 +1422,7 @@ public class Camera { }; /** - * Equivalent to takePicture(shutter, raw, null, jpeg). + * Equivalent to <pre>takePicture(Shutter, raw, null, jpeg)</pre>. * * @see #takePicture(ShutterCallback, PictureCallback, PictureCallback, PictureCallback) */ @@ -1422,6 +1460,9 @@ public class Camera { * @param raw the callback for raw (uncompressed) image data, or null * @param postview callback with postview image data, may be null * @param jpeg the callback for JPEG image data, or null + * @throws RuntimeException if starting picture capture fails; usually this + * would be because of a hardware or other low-level error, or because + * release() has been called on this Camera instance. */ public final void takePicture(ShutterCallback shutter, PictureCallback raw, PictureCallback postview, PictureCallback jpeg) { @@ -1534,6 +1575,9 @@ public class Camera { * * @param degrees the angle that the picture will be rotated clockwise. * Valid values are 0, 90, 180, and 270. + * @throws RuntimeException if setting orientation fails; usually this would + * be because of a hardware or other low-level error, or because + * release() has been called on this Camera instance. * @see #setPreviewDisplay(SurfaceHolder) */ public native final void setDisplayOrientation(int degrees); @@ -1559,6 +1603,9 @@ public class Camera { * changed. {@code false} if the shutter sound state could not be * changed. {@code true} is also returned if shutter sound playback * is already set to the requested state. + * @throws RuntimeException if the call fails; usually this would be because + * of a hardware or other low-level error, or because release() has been + * called on this Camera instance. * @see #takePicture * @see CameraInfo#canDisableShutterSound * @see ShutterCallback @@ -1903,6 +1950,9 @@ public class Camera { * If modifications are made to the returned Parameters, they must be passed * to {@link #setParameters(Camera.Parameters)} to take effect. * + * @throws RuntimeException if reading parameters fails; usually this would + * be because of a hardware or other low-level error, or because + * release() has been called on this Camera instance. * @see #setParameters(Camera.Parameters) */ public Parameters getParameters() { diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl new file mode 100644 index 000000000000..a83d31390775 --- /dev/null +++ b/core/java/android/os/IStatsCompanionService.aidl @@ -0,0 +1,51 @@ +/* + * 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 { + /** + * Tell statscompanion that stastd is up and running. + */ + void statsdReady(); + + /** + * 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 9b5139dc5092..f8f28134063d 100644 --- a/core/java/android/os/IStatsManager.aidl +++ b/core/java/android/os/IStatsManager.aidl @@ -17,12 +17,32 @@ 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 { +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(); + oneway void systemRunning(); + + /** + * Tell the stats daemon that the StatsCompanionService is up and running. + * Two-way binder call so that caller knows message received. + */ + void statsCompanionReady(); + + /** + * Tells statsd that an anomaly may have occurred, so statsd can check whether this is so and + * act accordingly. + * Two-way binder call so that caller's method (and corresponding wakelocks) will linger. + */ + 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. + * Two-way binder call so that caller's method (and corresponding wakelocks) will linger. + */ + void informPollAlarmFired(); } diff --git a/core/java/android/os/ParcelableException.java b/core/java/android/os/ParcelableException.java index d84d62997d93..7f71905d7f28 100644 --- a/core/java/android/os/ParcelableException.java +++ b/core/java/android/os/ParcelableException.java @@ -52,10 +52,12 @@ public final class ParcelableException extends RuntimeException implements Parce final String msg = in.readString(); try { final Class<?> clazz = Class.forName(name, true, Parcelable.class.getClassLoader()); - return (Throwable) clazz.getConstructor(String.class).newInstance(msg); + if (Throwable.class.isAssignableFrom(clazz)) { + return (Throwable) clazz.getConstructor(String.class).newInstance(msg); + } } catch (ReflectiveOperationException e) { - throw new RuntimeException(name + ": " + msg); } + return new RuntimeException(name + ": " + msg); } /** {@hide} */ diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 40ced6ce4815..3c3e466bebb6 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -6966,8 +6966,9 @@ public final class Settings { 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 = @@ -10199,7 +10200,7 @@ public final class Settings { "allow_user_switching_when_system_user_locked"; /** - * Boot count since the device starts running APK level 24. + * Boot count since the device starts running API level 24. * <p> * Type: int */ diff --git a/core/java/android/service/carrier/CarrierService.java b/core/java/android/service/carrier/CarrierService.java index 813acc232289..2707f1467bcf 100644 --- a/core/java/android/service/carrier/CarrierService.java +++ b/core/java/android/service/carrier/CarrierService.java @@ -17,10 +17,13 @@ package android.service.carrier; import android.annotation.CallSuper; import android.app.Service; import android.content.Intent; +import android.os.Bundle; import android.os.IBinder; import android.os.PersistableBundle; import android.os.RemoteException; +import android.os.ResultReceiver; import android.os.ServiceManager; +import android.util.Log; import com.android.internal.telephony.ITelephonyRegistry; @@ -48,6 +51,8 @@ import com.android.internal.telephony.ITelephonyRegistry; */ public abstract class CarrierService extends Service { + private static final String LOG_TAG = "CarrierService"; + public static final String CARRIER_SERVICE_INTERFACE = "android.service.carrier.CarrierService"; private static ITelephonyRegistry sRegistry; @@ -133,11 +138,26 @@ public abstract class CarrierService extends Service { /** * A wrapper around ICarrierService that forwards calls to implementations of * {@link CarrierService}. + * @hide */ - private class ICarrierServiceWrapper extends ICarrierService.Stub { + public class ICarrierServiceWrapper extends ICarrierService.Stub { + /** @hide */ + public static final int RESULT_OK = 0; + /** @hide */ + public static final int RESULT_ERROR = 1; + /** @hide */ + public static final String KEY_CONFIG_BUNDLE = "config_bundle"; + @Override - public PersistableBundle getCarrierConfig(CarrierIdentifier id) { - return CarrierService.this.onLoadConfig(id); + public void getCarrierConfig(CarrierIdentifier id, ResultReceiver result) { + try { + Bundle data = new Bundle(); + data.putParcelable(KEY_CONFIG_BUNDLE, CarrierService.this.onLoadConfig(id)); + result.send(RESULT_OK, data); + } catch (Exception e) { + Log.e(LOG_TAG, "Error in onLoadConfig: " + e.getMessage(), e); + result.send(RESULT_ERROR, null); + } } } } diff --git a/core/java/android/service/carrier/ICarrierService.aidl b/core/java/android/service/carrier/ICarrierService.aidl index 4c875851cfc8..ac6f9614d8f5 100644 --- a/core/java/android/service/carrier/ICarrierService.aidl +++ b/core/java/android/service/carrier/ICarrierService.aidl @@ -17,6 +17,7 @@ package android.service.carrier; import android.os.PersistableBundle; +import android.os.ResultReceiver; import android.service.carrier.CarrierIdentifier; /** @@ -28,5 +29,5 @@ import android.service.carrier.CarrierIdentifier; interface ICarrierService { /** @see android.service.carrier.CarrierService#onLoadConfig */ - PersistableBundle getCarrierConfig(in CarrierIdentifier id); + oneway void getCarrierConfig(in CarrierIdentifier id, in ResultReceiver result); } diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java index 5e40935cf6d2..24260c4f32c3 100644 --- a/core/java/android/text/DynamicLayout.java +++ b/core/java/android/text/DynamicLayout.java @@ -384,7 +384,7 @@ public class DynamicLayout extends Layout private DynamicLayout(@NonNull Builder b) { super(createEllipsizer(b.mEllipsize, b.mDisplay), - b.mPaint, b.mWidth, b.mAlignment, b.mSpacingMult, b.mSpacingAdd); + b.mPaint, b.mWidth, b.mAlignment, b.mTextDir, b.mSpacingMult, b.mSpacingAdd); mDisplay = b.mDisplay; mIncludePad = b.mIncludePad; diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 91932dd40dd8..7198f371bf5e 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -105,8 +105,8 @@ public class SurfaceControl { long surfaceObject, long frame); private static native void nativeReparentChildren(long nativeObject, IBinder handle); - private static native void nativeReparentChild(long nativeObject, - IBinder parentHandle, IBinder childHandle); + private static native void nativeReparent(long nativeObject, + IBinder parentHandle); private static native void nativeSeverChildren(long nativeObject); private static native void nativeSetOverrideScalingMode(long nativeObject, int scalingMode); @@ -455,9 +455,9 @@ public class SurfaceControl { nativeReparentChildren(mNativeObject, newParentHandle); } - /** Re-parents a specific child layer to a new parent */ - public void reparentChild(IBinder newParentHandle, IBinder childHandle) { - nativeReparentChild(mNativeObject, newParentHandle, childHandle); + /** Re-parents this layer to a new parent. */ + public void reparent(IBinder newParentHandle) { + nativeReparent(mNativeObject, newParentHandle); } public void detachChildren() { diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index cac27afa72cb..462dad3fad7a 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -231,6 +231,7 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb updateRequestedVisibility(); mAttachedToWindow = true; + mParent.requestTransparentRegion(SurfaceView.this); if (!mGlobalListenersAdded) { ViewTreeObserver observer = getViewTreeObserver(); observer.addOnScrollChangedListener(mScrollChangedListener); @@ -269,8 +270,6 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb if (mPendingReportDraws > 0) { mDrawFinished = true; if (mAttachedToWindow) { - mParent.requestTransparentRegion(SurfaceView.this); - notifyDrawFinished(); invalidate(); } diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 27eeb2e67fb7..e906a1fa7807 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.AutofillService; 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 @@ public final class AutofillManager { * 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 @@ public final class AutofillManager { * * @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 @@ public final class AutofillManager { * * @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 @@ public final class AutofillManager { } 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 @@ public final class AutofillManager { } 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 @@ public final class AutofillManager { } if (!mEnabled || !isActiveLocked()) { + if (sVerbose && mEnabled) { + Log.v(TAG, "notifyValueChanged(" + view + "): ignoring on state " + + getStateAsStringLocked()); + } return; } @@ -950,10 +983,13 @@ public final class AutofillManager { @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 @@ public final class AutofillManager { } private void finishSessionLocked() { - if (sVerbose) Log.v(TAG, "finishSessionLocked(): " + mState); + if (sVerbose) Log.v(TAG, "finishSessionLocked(): " + getStateAsStringLocked()); if (!isActiveLocked()) return; @@ -987,7 +1023,7 @@ public final class AutofillManager { } private void cancelSessionLocked() { - if (sVerbose) Log.v(TAG, "cancelSessionLocked(): " + mState); + if (sVerbose) Log.v(TAG, "cancelSessionLocked(): " + getStateAsStringLocked()); if (!isActiveLocked()) return; @@ -1306,6 +1342,20 @@ public final class AutofillManager { } } + /** + * Marks the state of the session as finished. + * + * @param newState {@link #STATE_FINISHED} (because the autofill service returned a {@code null} + * FillResponse) or {@link #STATE_UNKNOWN} (because the session was removed). + */ + private void setSessionFinished(int newState) { + synchronized (mLock) { + if (sVerbose) Log.v(TAG, "setSessionFinished(): from " + mState + " to " + newState); + resetSessionLocked(); + mState = newState; + } + } + private void requestHideFillUi(AutofillId id) { final View anchor = findView(id); if (sVerbose) Log.v(TAG, "requestHideFillUi(" + id + "): anchor = " + anchor); @@ -1341,7 +1391,11 @@ public final class AutofillManager { } } - 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 +1415,11 @@ public final class AutofillManager { } else { callback.onAutofillEvent(anchor, AutofillCallback.EVENT_INPUT_UNAVAILABLE); } + } + if (sessionFinished) { + // Callback call was "hijacked" to also update the session state. + setSessionFinished(STATE_FINISHED); } } @@ -1434,8 +1492,7 @@ public final class AutofillManager { 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 +1509,29 @@ public final class AutofillManager { 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 +1863,10 @@ public final class AutofillManager { } @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 +1899,15 @@ public final class AutofillManager { 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(int newState) { + final AutofillManager afm = mAfm.get(); + if (afm != null) { + afm.post(() -> afm.setSessionFinished(newState)); } } } diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl index 0eae85860383..3dabcec8636a 100644 --- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl +++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl @@ -67,9 +67,9 @@ oneway interface IAutoFillManagerClient { 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,11 @@ oneway interface IAutoFillManagerClient { * 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. + * @param newState STATE_FINISHED (because the autofill service returned a null + * FillResponse) or STATE_UNKNOWN (because the session was removed). + */ + void setSessionFinished(int newState); } diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java index 7c4154f5c648..994512f7c897 100644 --- a/core/java/android/webkit/WebViewFactory.java +++ b/core/java/android/webkit/WebViewFactory.java @@ -463,7 +463,7 @@ public final class WebViewFactory { */ 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 @@ public final class WebViewFactory { 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 6e65c7a11d2f..db60ad8d1c05 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 @@ public class WebViewZygote { 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 class WebViewZygote { } } - 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 @@ public class WebViewZygote { 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 bc85fadb5ad9..1653afd1ac0f 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 class RemoteViews implements Parcelable, Filter { 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 @@ public class RemoteViews implements Parcelable, Filter { 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, @@ -2338,20 +2339,12 @@ public class RemoteViews implements Parcelable, Filter { } if (src.mActions != null) { - mActions = new ArrayList<>(); - Parcel p = Parcel.obtain(); - int count = src.mActions.size(); - for (int i = 0; i < count; i++) { - p.setDataPosition(0); - Action a = src.mActions.get(i); - a.writeToParcel( - p, a.hasSameAppInfo(mApplication) ? PARCELABLE_ELIDE_DUPLICATES : 0); - p.setDataPosition(0); - // Since src is already in memory, we do not care about stack overflow as it has - // already been read once. - mActions.add(getActionFromParcel(p, 0)); - } + writeActionsToParcel(p); + p.setDataPosition(0); + // Since src is already in memory, we do not care about stack overflow as it has + // already been read once. + readActionsFromParcel(p, 0); p.recycle(); } @@ -2392,13 +2385,7 @@ public class RemoteViews implements Parcelable, Filter { mLayoutId = parcel.readInt(); mIsWidgetCollectionChild = parcel.readInt() == 1; - int count = parcel.readInt(); - if (count > 0) { - mActions = new ArrayList<>(count); - for (int i = 0; i < count; i++) { - mActions.add(getActionFromParcel(parcel, depth)); - } - } + readActionsFromParcel(parcel, depth); } else { // MODE_HAS_LANDSCAPE_AND_PORTRAIT mLandscape = new RemoteViews(parcel, mBitmapCache, info, depth); @@ -2409,6 +2396,16 @@ public class RemoteViews implements Parcelable, Filter { mReapplyDisallowed = parcel.readInt() == 0; } + private void readActionsFromParcel(Parcel parcel, int depth) { + int count = parcel.readInt(); + if (count > 0) { + mActions = new ArrayList<>(count); + for (int i = 0; i < count; i++) { + mActions.add(getActionFromParcel(parcel, depth)); + } + } + } + private Action getActionFromParcel(Parcel parcel, int depth) { int tag = parcel.readInt(); switch (tag) { @@ -3695,18 +3692,7 @@ public class RemoteViews implements Parcelable, Filter { } dest.writeInt(mLayoutId); dest.writeInt(mIsWidgetCollectionChild ? 1 : 0); - int count; - if (mActions != null) { - count = mActions.size(); - } else { - count = 0; - } - dest.writeInt(count); - for (int i=0; i<count; i++) { - Action a = mActions.get(i); - a.writeToParcel(dest, a.hasSameAppInfo(mApplication) - ? PARCELABLE_ELIDE_DUPLICATES : 0); - } + writeActionsToParcel(dest); } else { dest.writeInt(MODE_HAS_LANDSCAPE_AND_PORTRAIT); // We only write the bitmap cache if we are the root RemoteViews, as this cache @@ -3721,6 +3707,21 @@ public class RemoteViews implements Parcelable, Filter { dest.writeInt(mReapplyDisallowed ? 1 : 0); } + private void writeActionsToParcel(Parcel parcel) { + int count; + if (mActions != null) { + count = mActions.size(); + } else { + count = 0; + } + parcel.writeInt(count); + for (int i = 0; i < count; i++) { + Action a = mActions.get(i); + a.writeToParcel(parcel, a.hasSameAppInfo(mApplication) + ? PARCELABLE_ELIDE_DUPLICATES : 0); + } + } + private static ApplicationInfo getApplicationInfo(String packageName, int userId) { if (packageName == null) { return null; diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java index 2e1e96365f2a..604575fae463 100644 --- a/core/java/android/widget/Switch.java +++ b/core/java/android/widget/Switch.java @@ -248,10 +248,7 @@ public class Switch extends CompoundButton { com.android.internal.R.styleable.Switch_switchPadding, 0); mSplitTrack = a.getBoolean(com.android.internal.R.styleable.Switch_splitTrack, false); - // TODO: replace CUR_DEVELOPMENT with P once P is added to android.os.Build.VERSION_CODES. - // STOPSHIP if the above TODO is not done. - mUseFallbackLineSpacing = - context.getApplicationInfo().targetSdkVersion >= VERSION_CODES.CUR_DEVELOPMENT; + mUseFallbackLineSpacing = context.getApplicationInfo().targetSdkVersion >= VERSION_CODES.P; ColorStateList thumbTintList = a.getColorStateList( com.android.internal.R.styleable.Switch_thumbTint); diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java index 05f7c0a1ee08..f8b6837e2d39 100644 --- a/core/java/android/widget/TabWidget.java +++ b/core/java/android/widget/TabWidget.java @@ -61,7 +61,10 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener { // This value will be set to 0 as soon as the first tab is added to TabHost. private int mSelectedTab = -1; + @Nullable private Drawable mLeftStrip; + + @Nullable private Drawable mRightStrip; private boolean mDrawBottomStrips = true; @@ -374,23 +377,36 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener { final Drawable leftStrip = mLeftStrip; final Drawable rightStrip = mRightStrip; - leftStrip.setState(selectedChild.getDrawableState()); - rightStrip.setState(selectedChild.getDrawableState()); + if (leftStrip != null) { + leftStrip.setState(selectedChild.getDrawableState()); + } + if (rightStrip != null) { + rightStrip.setState(selectedChild.getDrawableState()); + } if (mStripMoved) { final Rect bounds = mBounds; bounds.left = selectedChild.getLeft(); bounds.right = selectedChild.getRight(); final int myHeight = getHeight(); - leftStrip.setBounds(Math.min(0, bounds.left - leftStrip.getIntrinsicWidth()), - myHeight - leftStrip.getIntrinsicHeight(), bounds.left, myHeight); - rightStrip.setBounds(bounds.right, myHeight - rightStrip.getIntrinsicHeight(), - Math.max(getWidth(), bounds.right + rightStrip.getIntrinsicWidth()), myHeight); + if (leftStrip != null) { + leftStrip.setBounds(Math.min(0, bounds.left - leftStrip.getIntrinsicWidth()), + myHeight - leftStrip.getIntrinsicHeight(), bounds.left, myHeight); + } + if (rightStrip != null) { + rightStrip.setBounds(bounds.right, myHeight - rightStrip.getIntrinsicHeight(), + Math.max(getWidth(), bounds.right + rightStrip.getIntrinsicWidth()), + myHeight); + } mStripMoved = false; } - leftStrip.draw(canvas); - rightStrip.draw(canvas); + if (leftStrip != null) { + leftStrip.draw(canvas); + } + if (rightStrip != null) { + rightStrip.draw(canvas); + } } /** diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 2de552777756..791a8fae418f 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -1256,9 +1256,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; mUseInternationalizedInput = targetSdkVersion >= VERSION_CODES.O; - // TODO: replace CUR_DEVELOPMENT with P once P is added to android.os.Build.VERSION_CODES. - // STOPSHIP if the above TODO is not done. - mUseFallbackLineSpacing = targetSdkVersion >= VERSION_CODES.CUR_DEVELOPMENT; + mUseFallbackLineSpacing = targetSdkVersion >= VERSION_CODES.P; if (inputMethod != null) { Class<?> c; diff --git a/core/java/com/android/internal/app/NightDisplayController.java b/core/java/com/android/internal/app/NightDisplayController.java index 860c5c4c3d3b..7a1383c7a01c 100644 --- a/core/java/com/android/internal/app/NightDisplayController.java +++ b/core/java/com/android/internal/app/NightDisplayController.java @@ -32,8 +32,12 @@ import com.android.internal.R; 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 final class NightDisplayController { */ 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 @@ public final class NightDisplayController { * 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 @@ public final class NightDisplayController { } 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 @@ public final class NightDisplayController { R.integer.config_defaultNightDisplayCustomStartTime); } - return LocalTime.valueOf(startTimeValue); + return LocalTime.ofSecondOfDay(startTimeValue / 1000); } /** @@ -221,7 +233,7 @@ public final class NightDisplayController { 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 @@ public final class NightDisplayController { R.integer.config_defaultNightDisplayCustomEndTime); } - return LocalTime.valueOf(endTimeValue); + return LocalTime.ofSecondOfDay(endTimeValue / 1000); } /** @@ -255,7 +267,7 @@ public final class NightDisplayController { 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 @@ public final class NightDisplayController { } /** - * 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 42e9273c5ba2..64e12b4ec05c 100644 --- a/core/jni/android/graphics/BitmapFactory.cpp +++ b/core/jni/android/graphics/BitmapFactory.cpp @@ -560,7 +560,7 @@ static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteA 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 @@ static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fi // 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 b243817803ad..4c10a85c8257 100644 --- a/core/jni/android/graphics/Movie.cpp +++ b/core/jni/android/graphics/Movie.cpp @@ -104,7 +104,8 @@ static jobject movie_decodeStream(JNIEnv* env, jobject clazz, jobject istream) { // 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 8934c1e50aba..630220a4c9ed 100644 --- a/core/jni/android/graphics/Utils.cpp +++ b/core/jni/android/graphics/Utils.cpp @@ -42,7 +42,7 @@ bool AssetStreamAdaptor::isAtEnd() const { 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 fffec5b87b81..69930a581468 100644 --- a/core/jni/android/graphics/Utils.h +++ b/core/jni/android/graphics/Utils.h @@ -36,7 +36,9 @@ public: 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/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp index 863ca8b0bc02..b610b35e45cd 100644 --- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp +++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp @@ -484,14 +484,14 @@ static jint LegacyCameraDevice_nativeDetectSurfaceUsageFlags(JNIEnv* env, jobjec sp<ANativeWindow> anw; if ((anw = getNativeWindow(env, surface)) == NULL) { - jniThrowException(env, "Ljava/lang/UnsupportedOperationException;", + jniThrowException(env, "java/lang/UnsupportedOperationException;", "Could not retrieve native window from surface."); return BAD_VALUE; } int32_t usage = 0; status_t err = anw->query(anw.get(), NATIVE_WINDOW_CONSUMER_USAGE_BITS, &usage); if(err != NO_ERROR) { - jniThrowException(env, "Ljava/lang/UnsupportedOperationException;", + jniThrowException(env, "java/lang/UnsupportedOperationException;", "Error while querying surface usage bits"); return err; } @@ -511,7 +511,7 @@ static jint LegacyCameraDevice_nativeDisconnectSurface(JNIEnv* env, jobject thiz status_t err = native_window_api_disconnect(anw.get(), NATIVE_WINDOW_API_CAMERA); if(err != NO_ERROR) { - jniThrowException(env, "Ljava/lang/UnsupportedOperationException;", + jniThrowException(env, "java/lang/UnsupportedOperationException;", "Error while disconnecting surface"); return err; } diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index 883d4db04890..af5d12bd2510 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -20,8 +20,6 @@ #include "android_os_Parcel.h" #include "android_util_Binder.h" -#include <nativehelper/JNIHelp.h> - #include <fcntl.h> #include <inttypes.h> #include <stdio.h> @@ -44,8 +42,9 @@ #include <utils/SystemClock.h> #include <utils/threads.h> -#include <nativehelper/ScopedUtfChars.h> +#include <nativehelper/JNIHelp.h> #include <nativehelper/ScopedLocalRef.h> +#include <nativehelper/ScopedUtfChars.h> #include "core_jni_helpers.h" @@ -174,8 +173,49 @@ static JNIEnv* javavm_to_jnienv(JavaVM* vm) return vm->GetEnv((void **)&env, JNI_VERSION_1_4) >= 0 ? env : NULL; } -// Report a java.lang.Error (or subclass). This may terminate the runtime. -static void report_java_lang_error(JNIEnv* env, jthrowable error) +// Report a java.lang.Error (or subclass). This will terminate the runtime by +// calling FatalError with a message derived from the given error. +static void report_java_lang_error_fatal_error(JNIEnv* env, jthrowable error, + const char* msg) +{ + // Report an error: reraise the exception and ask the runtime to abort. + + // Try to get the exception string. Sometimes logcat isn't available, + // so try to add it to the abort message. + std::string exc_msg = "(Unknown exception message)"; + { + ScopedLocalRef<jclass> exc_class(env, env->GetObjectClass(error)); + jmethodID method_id = env->GetMethodID(exc_class.get(), "toString", + "()Ljava/lang/String;"); + ScopedLocalRef<jstring> jstr( + env, + reinterpret_cast<jstring>( + env->CallObjectMethod(error, method_id))); + env->ExceptionClear(); // Just for good measure. + if (jstr.get() != nullptr) { + ScopedUtfChars jstr_utf(env, jstr.get()); + if (jstr_utf.c_str() != nullptr) { + exc_msg = jstr_utf.c_str(); + } else { + env->ExceptionClear(); + } + } + } + + env->Throw(error); + ALOGE("java.lang.Error thrown during binder transaction (stack trace follows) : "); + env->ExceptionDescribe(); + + std::string error_msg = base::StringPrintf( + "java.lang.Error thrown during binder transaction: %s", + exc_msg.c_str()); + env->FatalError(error_msg.c_str()); +} + +// Report a java.lang.Error (or subclass). This will terminate the runtime, either by +// the uncaught exception handler, or explicitly by calling +// report_java_lang_error_fatal_error. +static void report_java_lang_error(JNIEnv* env, jthrowable error, const char* msg) { // Try to run the uncaught exception machinery. jobject thread = env->CallStaticObjectMethod(gThreadDispatchOffsets.mClass, @@ -187,77 +227,39 @@ static void report_java_lang_error(JNIEnv* env, jthrowable error) } // Some error occurred that meant that either dispatchUncaughtException could not be // called or that it had an error itself (as this should be unreachable under normal - // conditions). Clear the exception. + // conditions). As the binder code cannot handle Errors, attempt to log the error and + // abort. env->ExceptionClear(); + report_java_lang_error_fatal_error(env, error, msg); } static void report_exception(JNIEnv* env, jthrowable excep, const char* msg) { env->ExceptionClear(); - jstring tagstr = env->NewStringUTF(LOG_TAG); - jstring msgstr = NULL; - if (tagstr != NULL) { - msgstr = env->NewStringUTF(msg); + ScopedLocalRef<jstring> tagstr(env, env->NewStringUTF(LOG_TAG)); + ScopedLocalRef<jstring> msgstr(env); + if (tagstr != nullptr) { + msgstr.reset(env->NewStringUTF(msg)); } - if ((tagstr == NULL) || (msgstr == NULL)) { + if ((tagstr != nullptr) && (msgstr != nullptr)) { + env->CallStaticIntMethod(gLogOffsets.mClass, gLogOffsets.mLogE, + tagstr.get(), msgstr.get(), excep); + if (env->ExceptionCheck()) { + // Attempting to log the failure has failed. + ALOGW("Failed trying to log exception, msg='%s'\n", msg); + env->ExceptionClear(); + } + } else { env->ExceptionClear(); /* assume exception (OOM?) was thrown */ ALOGE("Unable to call Log.e()\n"); ALOGE("%s", msg); - goto bail; - } - - env->CallStaticIntMethod( - gLogOffsets.mClass, gLogOffsets.mLogE, tagstr, msgstr, excep); - if (env->ExceptionCheck()) { - /* attempting to log the failure has failed */ - ALOGW("Failed trying to log exception, msg='%s'\n", msg); - env->ExceptionClear(); } if (env->IsInstanceOf(excep, gErrorOffsets.mClass)) { - // Try to report the error. This should not return under normal circumstances. - report_java_lang_error(env, excep); - // The traditional handling: re-raise and abort. - - /* - * It's an Error: Reraise the exception and ask the runtime to abort. - */ - - // Try to get the exception string. Sometimes logcat isn't available, - // so try to add it to the abort message. - std::string exc_msg = "(Unknown exception message)"; - { - ScopedLocalRef<jclass> exc_class(env, env->GetObjectClass(excep)); - jmethodID method_id = env->GetMethodID(exc_class.get(), - "toString", - "()Ljava/lang/String;"); - ScopedLocalRef<jstring> jstr( - env, - reinterpret_cast<jstring>( - env->CallObjectMethod(excep, method_id))); - env->ExceptionClear(); // Just for good measure. - if (jstr.get() != nullptr) { - ScopedUtfChars jstr_utf(env, jstr.get()); - exc_msg = jstr_utf.c_str(); - } - } - - env->Throw(excep); - ALOGE("java.lang.Error thrown during binder transaction (stack trace follows) : "); - env->ExceptionDescribe(); - - std::string error_msg = base::StringPrintf( - "java.lang.Error thrown during binder transaction: %s", - exc_msg.c_str()); - env->FatalError(error_msg.c_str()); + report_java_lang_error(env, excep, msg); } - -bail: - /* discard local refs created for us by VM */ - env->DeleteLocalRef(tagstr); - env->DeleteLocalRef(msgstr); } class JavaBBinderHolder; @@ -309,14 +311,11 @@ protected: code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags); if (env->ExceptionCheck()) { - jthrowable excep = env->ExceptionOccurred(); - report_exception(env, excep, + ScopedLocalRef<jthrowable> excep(env, env->ExceptionOccurred()); + report_exception(env, excep.get(), "*** Uncaught remote exception! " "(Exceptions are not yet supported across processes.)"); res = JNI_FALSE; - - /* clean up JNI local ref -- we don't return to Java code */ - env->DeleteLocalRef(excep); } // Check if the strict mode state changed while processing the @@ -328,11 +327,9 @@ protected: } if (env->ExceptionCheck()) { - jthrowable excep = env->ExceptionOccurred(); - report_exception(env, excep, + ScopedLocalRef<jthrowable> excep(env, env->ExceptionOccurred()); + report_exception(env, excep.get(), "*** Uncaught exception in onBinderStrictModePolicyChange"); - /* clean up JNI local ref -- we don't return to Java code */ - env->DeleteLocalRef(excep); } // Need to always call through the native implementation of @@ -475,9 +472,8 @@ public: if (mObject != NULL) { result = env->IsSameObject(obj, mObject); } else { - jobject me = env->NewLocalRef(mObjectWeak); - result = env->IsSameObject(obj, me); - env->DeleteLocalRef(me); + ScopedLocalRef<jobject> me(env, env->NewLocalRef(mObjectWeak)); + result = env->IsSameObject(obj, me.get()); } return result; } diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 33f1c7d393af..bf8bbf53295a 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -736,13 +736,11 @@ static void nativeReparentChildren(JNIEnv* env, jclass clazz, jlong nativeObject ctrl->reparentChildren(handle); } -static void nativeReparentChild(JNIEnv* env, jclass clazz, jlong nativeObject, - jobject newParentObject, jobject childObject) { +static void nativeReparent(JNIEnv* env, jclass clazz, jlong nativeObject, + jobject newParentObject) { auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject); sp<IBinder> parentHandle = ibinderForJavaObject(env, newParentObject); - sp<IBinder> childHandle = ibinderForJavaObject(env, childObject); - - ctrl->reparentChild(parentHandle, childHandle); + ctrl->reparent(parentHandle); } static void nativeSeverChildren(JNIEnv* env, jclass clazz, jlong nativeObject) { @@ -868,8 +866,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeDeferTransactionUntilSurface }, {"nativeReparentChildren", "(JLandroid/os/IBinder;)V", (void*)nativeReparentChildren } , - {"nativeReparentChild", "(JLandroid/os/IBinder;Landroid/os/IBinder;)V", - (void*)nativeReparentChild }, + {"nativeReparent", "(JLandroid/os/IBinder;)V", + (void*)nativeReparent }, {"nativeSeverChildren", "(J)V", (void*)nativeSeverChildren } , {"nativeSetOverrideScalingMode", "(JI)V", diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto new file mode 100644 index 000000000000..d5ecacc8f72c --- /dev/null +++ b/core/proto/android/server/activitymanagerservice.proto @@ -0,0 +1,84 @@ +/* + * 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. + */ + +syntax = "proto3"; + +import "frameworks/base/core/proto/android/server/windowmanagerservice.proto"; +import "frameworks/base/core/proto/android/graphics/rect.proto"; + +package com.android.server.am.proto; + +option java_multiple_files = true; + +message ActivityManagerServiceProto { + ActivityStackSupervisorProto activities = 1; +} + +message ActivityStackSupervisorProto { + .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1; + repeated ActivityDisplayProto displays = 2; + KeyguardControllerProto keyguard_controller = 3; + int32 focused_stack_id = 4; + .com.android.server.wm.proto.IdentifierProto resumed_activity = 5; +} + +/* represents ActivityStackSupervisor.ActivityDisplay */ +message ActivityDisplayProto { + .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1; + int32 id = 2; + repeated ActivityStackProto stacks = 3; +} + +message ActivityStackProto { + .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1; + int32 id = 2; + repeated TaskRecordProto tasks = 3; + .com.android.server.wm.proto.IdentifierProto resumed_activity = 4; + int32 display_id = 5; + bool fullscreen = 6; + .android.graphics.RectProto bounds = 7; +} + +message TaskRecordProto { + .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1; + int32 id = 2; + repeated ActivityRecordProto activities = 3; + int32 stack_id = 4; + .android.graphics.RectProto last_non_fullscreen_bounds = 5; + string real_activity = 6; + string orig_activity = 7; + int32 activity_type = 8; + int32 return_to_type = 9; + int32 resize_mode = 10; + bool fullscreen = 11; + .android.graphics.RectProto bounds = 12; + int32 min_width = 13; + int32 min_height = 14; +} + +message ActivityRecordProto { + .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1; + .com.android.server.wm.proto.IdentifierProto identifier = 2; + string state = 3; + bool visible = 4; + bool front_of_task = 5; + int32 proc_id = 6; +} + +message KeyguardControllerProto { + bool keyguard_showing = 1; + bool keyguard_occluded = 2; +}
\ No newline at end of file diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index aa94e0ff19e6..695fdac70280 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/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 2c64789f2121..16c857894d05 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -346,11 +346,6 @@ <dimen name="notification_text_size">14sp</dimen> <!-- Size of notification text titles (see TextAppearance.StatusBar.EventContent.Title) --> <dimen name="notification_title_text_size">14sp</dimen> - - <!-- Size of notification text (see TextAppearance.StatusBar.EventContent) when colorized --> - <dimen name="notification_text_size_colorized">16sp</dimen> - <!-- Size of notification text titles (see TextAppearance.StatusBar.EventContent.Title) when colorized --> - <dimen name="notification_title_text_size_colorized">20sp</dimen> <!-- Size of smaller notification text (see TextAppearance.StatusBar.EventContent.Line2, Info, Time) --> <dimen name="notification_subtext_size">12sp</dimen> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index c4a45ee11098..1877d421736f 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3058,9 +3058,6 @@ <java-symbol type="array" name="config_allowedSystemInstantAppSettings" /> <java-symbol type="array" name="config_allowedSecureInstantAppSettings" /> - <java-symbol type="dimen" name="notification_text_size_colorized" /> - <java-symbol type="dimen" name="notification_title_text_size_colorized" /> - <java-symbol type="bool" name="config_handleVolumeKeysInWindowManager" /> <java-symbol type="dimen" name="config_inCallNotificationVolume" /> <java-symbol type="string" name="config_inCallNotificationSound" /> diff --git a/core/tests/coretests/src/android/text/DynamicLayoutTest.java b/core/tests/coretests/src/android/text/DynamicLayoutTest.java index ed6bfbfa3491..639cefbcf26b 100644 --- a/core/tests/coretests/src/android/text/DynamicLayoutTest.java +++ b/core/tests/coretests/src/android/text/DynamicLayoutTest.java @@ -259,4 +259,21 @@ public class DynamicLayoutTest { assertEquals(2 * textSize, layout.getLineDescent(2)); } } + + @Test + public void testBuilder_defaultTextDirection() { + final DynamicLayout.Builder builder = DynamicLayout.Builder + .obtain("", new TextPaint(), WIDTH); + final DynamicLayout layout = builder.build(); + assertEquals(TextDirectionHeuristics.FIRSTSTRONG_LTR, layout.getTextDirectionHeuristic()); + } + + @Test + public void testBuilder_setTextDirection() { + final DynamicLayout.Builder builder = DynamicLayout.Builder + .obtain("", new TextPaint(), WIDTH) + .setTextDirection(TextDirectionHeuristics.ANYRTL_LTR); + final DynamicLayout layout = builder.build(); + assertEquals(TextDirectionHeuristics.ANYRTL_LTR, layout.getTextDirectionHeuristic()); + } } diff --git a/core/tests/coretests/src/android/widget/RemoteViewsTest.java b/core/tests/coretests/src/android/widget/RemoteViewsTest.java index d26437eafa07..ddf9876d3dae 100644 --- a/core/tests/coretests/src/android/widget/RemoteViewsTest.java +++ b/core/tests/coretests/src/android/widget/RemoteViewsTest.java @@ -20,7 +20,9 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import android.app.PendingIntent; import android.content.Context; +import android.content.Intent; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; @@ -382,4 +384,19 @@ public class RemoteViewsTest { RemoteViews.CREATOR.createFromParcel(p); p.recycle(); } + + @Test + public void copyWithBinders() throws Exception { + RemoteViews views = new RemoteViews(mPackage, R.layout.remote_views_test); + for (int i = 1; i < 10; i++) { + PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, + new Intent("android.widget.RemoteViewsTest_" + i), PendingIntent.FLAG_ONE_SHOT); + views.setOnClickPendingIntent(i, pi); + } + try { + new RemoteViews(views); + } catch (Throwable t) { + throw new Exception(t); + } + } } diff --git a/data/etc/platform.xml b/data/etc/platform.xml index 7e245309e756..2333feceb1db 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -160,6 +160,9 @@ <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" /> + <assign-permission name="android.permission.ACCESS_LOWPAN_STATE" uid="lowpan" /> + <assign-permission name="android.permission.MANAGE_LOWPAN_INTERFACES" uid="lowpan" /> + <!-- This is a list of all the libraries available for application code to link against. --> diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java index fe427a73bf96..8707ad017f51 100644 --- a/media/java/android/media/MediaRouter.java +++ b/media/java/android/media/MediaRouter.java @@ -204,7 +204,6 @@ public class MediaRouter { 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 @@ public class MediaRouter { } 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/res/layout/preference_two_target.xml b/packages/SettingsLib/res/layout/preference_two_target.xml index 2309ec6f1f8d..c2167f3e608d 100644 --- a/packages/SettingsLib/res/layout/preference_two_target.xml +++ b/packages/SettingsLib/res/layout/preference_two_target.xml @@ -33,6 +33,7 @@ android:background="?android:attr/selectableItemBackground" android:gravity="start|center_vertical" android:clipToPadding="false" + android:layout_marginStart="4dp" android:paddingStart="?android:attr/listPreferredItemPaddingStart" android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"> diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java index 9b75c00aeb3a..35ba6ae975d8 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.pm.ResolveInfo; 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 @@ public class TileUtils { 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 @@ public class TileUtils { 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 @@ public class TileUtils { String summary = null; String keyHint = null; boolean isIconTintable = false; - RemoteViews remoteViews = null; // Get the activity's meta-data try { @@ -428,7 +437,8 @@ public class TileUtils { } 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 @@ public class TileUtils { // Suggest a key for this tile tile.key = keyHint; tile.isIconTintable = isIconTintable; - tile.remoteViews = remoteViews; return true; } @@ -470,6 +479,26 @@ public class TileUtils { 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 class TileUtils { } } - 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 00f32b2839af..56b84415e907 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 @@ public class SuggestionParser { 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 76f6a20959fb..3e90435b21d7 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.any; 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.Mock; 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 @@ import java.util.Map; @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 @@ public class TileUtilsTest { } @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 @@ public class TileUtilsTest { 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 @@ public class TileUtilsTest { } } + @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 baefdd51ef7c..000000000000 --- a/packages/SystemUI/OWNERS +++ /dev/null @@ -1,8 +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 -per-file Android.mk = build.master@android.com  # special file expert -per-file Android.mk = android-sysui-eng+reviews@google.com - -android-sysui-eng+reviews@google.com diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index e6a357fc7be8..9901f6ff8fda 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -80,12 +80,6 @@ <!-- Height of a small notification in the status bar which was used before android N --> <dimen name="notification_min_height_legacy">64dp</dimen> - <!-- The increase in minHeight that is allowed when the notification is colorized --> - <dimen name="notification_height_increase_colorized">11sp</dimen> - - <!-- The increase in minHeight that is allowed when the notification is colorized and has increased height (i.e messages) --> - <dimen name="notification_height_increase_colorized_increased">13sp</dimen> - <!-- Height of a large notification in the status bar --> <dimen name="notification_max_height">284dp</dimen> diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java index b3f992db1b6b..bae9ef8abfba 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -30,6 +30,7 @@ import android.graphics.Rect; import android.os.Handler; import android.os.RemoteException; import android.util.Log; +import android.util.Pair; import android.view.IPinnedStackController; import android.view.IPinnedStackListener; import android.view.IWindowManager; @@ -70,11 +71,11 @@ public class PipManager implements BasePipManager { */ TaskStackListener mTaskStackListener = new TaskStackListener() { @Override - public void onActivityPinned(String packageName, int taskId) { + public void onActivityPinned(String packageName, int userId, int taskId) { mTouchHandler.onActivityPinned(); mMediaController.onActivityPinned(); mMenuController.onActivityPinned(); - mNotificationController.onActivityPinned(packageName, + mNotificationController.onActivityPinned(packageName, userId, true /* deferUntilAnimationEnds */); SystemServicesProxy.getInstance(mContext).setPipVisibility(true); @@ -82,13 +83,15 @@ public class PipManager implements BasePipManager { @Override public void onActivityUnpinned() { - ComponentName topPipActivity = PipUtils.getTopPinnedActivity(mContext, - mActivityManager); - mMenuController.onActivityUnpinned(topPipActivity); - mTouchHandler.onActivityUnpinned(topPipActivity); - mNotificationController.onActivityUnpinned(topPipActivity); - - SystemServicesProxy.getInstance(mContext).setPipVisibility(topPipActivity != null); + final Pair<ComponentName, Integer> topPipActivityInfo = PipUtils.getTopPinnedActivity( + mContext, mActivityManager); + final ComponentName topActivity = topPipActivityInfo.first; + final int userId = topActivity != null ? topPipActivityInfo.second : 0; + mMenuController.onActivityUnpinned(); + mTouchHandler.onActivityUnpinned(topActivity); + mNotificationController.onActivityUnpinned(topActivity, userId); + + SystemServicesProxy.getInstance(mContext).setPipVisibility(topActivity != null); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java index b3a0794f742f..174a7ef19cbd 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java @@ -230,7 +230,7 @@ public class PipMediaController { private void resolveActiveMediaController(List<MediaController> controllers) { if (controllers != null) { final ComponentName topActivity = PipUtils.getTopPinnedActivity(mContext, - mActivityManager); + mActivityManager).first; if (topActivity != null) { for (int i = 0; i < controllers.size(); i++) { final MediaController controller = controllers.get(i); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java index 34666fb30689..68743b34884d 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java @@ -223,7 +223,7 @@ public class PipMenuActivityController { } } - public void onActivityUnpinned(ComponentName topPipActivity) { + public void onActivityUnpinned() { hideMenu(); setStartActivityRequested(false); } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java index 696fdbc811e7..6d083e9d601d 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java @@ -35,10 +35,15 @@ import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; -import android.content.res.Resources; -import android.graphics.drawable.Icon; +import android.graphics.Bitmap; +import android.graphics.Bitmap.Config; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; import android.net.Uri; +import android.os.UserHandle; +import android.util.IconDrawableFactory; import android.util.Log; +import android.util.Pair; import com.android.systemui.R; import com.android.systemui.SystemUI; @@ -57,22 +62,29 @@ public class PipNotificationController { private IActivityManager mActivityManager; private AppOpsManager mAppOpsManager; private NotificationManager mNotificationManager; + private IconDrawableFactory mIconDrawableFactory; private PipMotionHelper mMotionHelper; // Used when building a deferred notification private String mDeferredNotificationPackageName; + private int mDeferredNotificationUserId; private AppOpsManager.OnOpChangedListener mAppOpsChangedListener = new OnOpChangedListener() { @Override public void onOpChanged(String op, String packageName) { try { // Dismiss the PiP once the user disables the app ops setting for that package - final ApplicationInfo appInfo = mContext.getPackageManager().getApplicationInfo( - packageName, 0); - if (mAppOpsManager.checkOpNoThrow(OP_PICTURE_IN_PICTURE, appInfo.uid, packageName) - != MODE_ALLOWED) { - mMotionHelper.dismissPip(); + final Pair<ComponentName, Integer> topPipActivityInfo = + PipUtils.getTopPinnedActivity(mContext, mActivityManager); + if (topPipActivityInfo.first != null) { + final ApplicationInfo appInfo = mContext.getPackageManager() + .getApplicationInfoAsUser(packageName, 0, topPipActivityInfo.second); + if (appInfo.packageName.equals(topPipActivityInfo.first.getPackageName()) && + mAppOpsManager.checkOpNoThrow(OP_PICTURE_IN_PICTURE, appInfo.uid, + packageName) != MODE_ALLOWED) { + mMotionHelper.dismissPip(); + } } } catch (NameNotFoundException e) { // Unregister the listener if the package can't be found @@ -88,16 +100,18 @@ public class PipNotificationController { mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); mNotificationManager = NotificationManager.from(context); mMotionHelper = motionHelper; + mIconDrawableFactory = IconDrawableFactory.newInstance(context); } - public void onActivityPinned(String packageName, boolean deferUntilAnimationEnds) { + public void onActivityPinned(String packageName, int userId, boolean deferUntilAnimationEnds) { // Clear any existing notification mNotificationManager.cancel(NOTIFICATION_TAG, NOTIFICATION_ID); if (deferUntilAnimationEnds) { mDeferredNotificationPackageName = packageName; + mDeferredNotificationUserId = userId; } else { - showNotificationForApp(mDeferredNotificationPackageName); + showNotificationForApp(packageName, userId); } // Register for changes to the app ops setting for this package while it is in PiP @@ -106,22 +120,25 @@ public class PipNotificationController { public void onPinnedStackAnimationEnded() { if (mDeferredNotificationPackageName != null) { - showNotificationForApp(mDeferredNotificationPackageName); + showNotificationForApp(mDeferredNotificationPackageName, mDeferredNotificationUserId); mDeferredNotificationPackageName = null; + mDeferredNotificationUserId = 0; } } - public void onActivityUnpinned(ComponentName topPipActivity) { + public void onActivityUnpinned(ComponentName topPipActivity, int userId) { // Unregister for changes to the previously PiP'ed package unregisterAppOpsListener(); // Reset the deferred notification package mDeferredNotificationPackageName = null; + mDeferredNotificationUserId = 0; if (topPipActivity != null) { // onActivityUnpinned() is only called after the transition is complete, so we don't // need to defer until the animation ends to update the notification - onActivityPinned(topPipActivity.getPackageName(), false /* deferUntilAnimationEnds */); + onActivityPinned(topPipActivity.getPackageName(), userId, + false /* deferUntilAnimationEnds */); } else { mNotificationManager.cancel(NOTIFICATION_TAG, NOTIFICATION_ID); } @@ -130,20 +147,27 @@ public class PipNotificationController { /** * Builds and shows the notification for the given app. */ - private void showNotificationForApp(String packageName) { + private void showNotificationForApp(String packageName, int userId) { // Build a new notification - final Notification.Builder builder = - new Notification.Builder(mContext, NotificationChannels.GENERAL) - .setLocalOnly(true) - .setOngoing(true) - .setSmallIcon(R.drawable.pip_notification_icon) - .setColor(mContext.getColor( - com.android.internal.R.color.system_notification_accent_color)); - if (updateNotificationForApp(builder, packageName)) { - SystemUI.overrideNotificationAppName(mContext, builder); - - // Show the new notification - mNotificationManager.notify(NOTIFICATION_TAG, NOTIFICATION_ID, builder.build()); + try { + final UserHandle user = UserHandle.of(userId); + final Context userContext = mContext.createPackageContextAsUser( + mContext.getPackageName(), 0, user); + final Notification.Builder builder = + new Notification.Builder(userContext, NotificationChannels.GENERAL) + .setLocalOnly(true) + .setOngoing(true) + .setSmallIcon(R.drawable.pip_notification_icon) + .setColor(mContext.getColor( + com.android.internal.R.color.system_notification_accent_color)); + if (updateNotificationForApp(builder, packageName, user)) { + SystemUI.overrideNotificationAppName(mContext, builder); + + // Show the new notification + mNotificationManager.notify(NOTIFICATION_TAG, NOTIFICATION_ID, builder.build()); + } + } catch (NameNotFoundException e) { + Log.e(TAG, "Could not show notification for application", e); } } @@ -151,33 +175,33 @@ public class PipNotificationController { * Updates the notification builder with app-specific information, returning whether it was * successful. */ - private boolean updateNotificationForApp(Notification.Builder builder, String packageName) { + private boolean updateNotificationForApp(Notification.Builder builder, String packageName, + UserHandle user) throws NameNotFoundException { final PackageManager pm = mContext.getPackageManager(); final ApplicationInfo appInfo; try { - appInfo = pm.getApplicationInfo(packageName, 0); + appInfo = pm.getApplicationInfoAsUser(packageName, 0, user.getIdentifier()); } catch (NameNotFoundException e) { Log.e(TAG, "Could not update notification for application", e); return false; } if (appInfo != null) { - final String appName = pm.getApplicationLabel(appInfo).toString(); + final String appName = pm.getUserBadgedLabel(pm.getApplicationLabel(appInfo), user) + .toString(); final String message = mContext.getString(R.string.pip_notification_message, appName); final Intent settingsIntent = new Intent(ACTION_PICTURE_IN_PICTURE_SETTINGS, Uri.fromParts("package", packageName, null)); + settingsIntent.putExtra(Intent.EXTRA_USER_HANDLE, user); settingsIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK); - final Icon appIcon = appInfo.icon != 0 - ? Icon.createWithResource(packageName, appInfo.icon) - : Icon.createWithResource(Resources.getSystem(), - com.android.internal.R.drawable.sym_def_app_icon); + final Drawable iconDrawable = mIconDrawableFactory.getBadgedIcon(appInfo); builder.setContentTitle(mContext.getString(R.string.pip_notification_title, appName)) .setContentText(message) - .setContentIntent(PendingIntent.getActivity(mContext, packageName.hashCode(), - settingsIntent, FLAG_CANCEL_CURRENT)) + .setContentIntent(PendingIntent.getActivityAsUser(mContext, packageName.hashCode(), + settingsIntent, FLAG_CANCEL_CURRENT, null, user)) .setStyle(new Notification.BigTextStyle().bigText(message)) - .setLargeIcon(appIcon); + .setLargeIcon(createBitmap(iconDrawable).createAshmemBitmap()); return true; } return false; @@ -191,4 +215,17 @@ public class PipNotificationController { private void unregisterAppOpsListener() { mAppOpsManager.stopWatchingMode(mAppOpsChangedListener); } + + /** + * Bakes a drawable into a bitmap. + */ + private Bitmap createBitmap(Drawable d) { + Bitmap bitmap = Bitmap.createBitmap(d.getIntrinsicWidth(), d.getIntrinsicHeight(), + Config.ARGB_8888); + Canvas c = new Canvas(bitmap); + d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight()); + d.draw(c); + c.setBitmap(null); + return bitmap; + } } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java index a8cdd1bdb802..56275fd043cf 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java @@ -24,16 +24,17 @@ import android.content.ComponentName; import android.content.Context; import android.os.RemoteException; import android.util.Log; +import android.util.Pair; public class PipUtils { private static final String TAG = "PipUtils"; /** - * @return the ComponentName of the top non-SystemUI activity in the pinned stack, or null if - * none exists. + * @return the ComponentName and user id of the top non-SystemUI activity in the pinned stack. + * The component name may be null if no such activity exists. */ - public static ComponentName getTopPinnedActivity(Context context, + public static Pair<ComponentName, Integer> getTopPinnedActivity(Context context, IActivityManager activityManager) { try { final String sysUiPackageName = context.getPackageName(); @@ -44,13 +45,13 @@ public class PipUtils { ComponentName cn = ComponentName.unflattenFromString( pinnedStackInfo.taskNames[i]); if (cn != null && !cn.getPackageName().equals(sysUiPackageName)) { - return cn; + return new Pair<>(cn, pinnedStackInfo.taskUserIds[i]); } } } } catch (RemoteException e) { Log.w(TAG, "Unable to get pinned stack."); } - return null; + return new Pair<>(null, 0); } } diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java index e8c129521010..186de5c4e121 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java @@ -654,7 +654,7 @@ public class PipManager implements BasePipManager { } @Override - public void onActivityPinned(String packageName, int taskId) { + public void onActivityPinned(String packageName, int userId, int taskId) { if (DEBUG) Log.d(TAG, "onActivityPinned()"); if (!checkCurrentUserId(mContext, DEBUG)) { return; diff --git a/packages/SystemUI/src/com/android/systemui/qs/AlphaControlledSignalTileView.java b/packages/SystemUI/src/com/android/systemui/qs/AlphaControlledSignalTileView.java new file mode 100644 index 000000000000..2c7ec70a5fff --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/AlphaControlledSignalTileView.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs; + +import android.content.Context; +import android.content.res.ColorStateList; +import android.graphics.drawable.Drawable; +import com.android.systemui.qs.tileimpl.SlashImageView; + + +/** + * Creates AlphaControlledSlashImageView instead of SlashImageView + */ +public class AlphaControlledSignalTileView extends SignalTileView { + public AlphaControlledSignalTileView(Context context) { + super(context); + } + + @Override + protected SlashImageView createSlashImageView(Context context) { + return new AlphaControlledSlashImageView(context); + } + + /** + * Creates AlphaControlledSlashDrawable instead of regular SlashDrawables + */ + public static class AlphaControlledSlashImageView extends SlashImageView { + public AlphaControlledSlashImageView(Context context) { + super(context); + } + + public void setFinalImageTintList(ColorStateList tint) { + super.setImageTintList(tint); + final SlashDrawable slash = getSlash(); + if (slash != null) { + ((AlphaControlledSlashDrawable)slash).setFinalTintList(tint); + } + } + + @Override + protected void ensureSlashDrawable() { + if (getSlash() == null) { + final SlashDrawable slash = new AlphaControlledSlashDrawable(getDrawable()); + setSlash(slash); + slash.setAnimationEnabled(getAnimationEnabled()); + setImageViewDrawable(slash); + } + } + } + + /** + * SlashDrawable that disobeys orders to change its drawable's tint except when you tell + * it not to disobey. The slash still will animate its alpha. + */ + public static class AlphaControlledSlashDrawable extends SlashDrawable { + AlphaControlledSlashDrawable(Drawable d) { + super(d); + } + + @Override + protected void setDrawableTintList(ColorStateList tint) { + } + + /** + * Set a target tint list instead of + */ + public void setFinalTintList(ColorStateList tint) { + super.setDrawableTintList(tint); + } + } +} + diff --git a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java index b300e4a35a5a..9ee40ccf8893 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java @@ -63,13 +63,17 @@ public class SignalTileView extends QSIconViewImpl { @Override protected View createIcon() { mIconFrame = new FrameLayout(mContext); - mSignal = new SlashImageView(mContext); + mSignal = createSlashImageView(mContext); mIconFrame.addView(mSignal); mOverlay = new ImageView(mContext); mIconFrame.addView(mOverlay, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); return mIconFrame; } + protected SlashImageView createSlashImageView(Context context) { + return new SlashImageView(context); + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); diff --git a/packages/SystemUI/src/com/android/systemui/qs/SlashDrawable.java b/packages/SystemUI/src/com/android/systemui/qs/SlashDrawable.java index c35614893098..a9b2376e46e5 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/SlashDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/qs/SlashDrawable.java @@ -197,11 +197,15 @@ public class SlashDrawable extends Drawable { public void setTintList(@Nullable ColorStateList tint) { mTintList = tint; super.setTintList(tint); - mDrawable.setTintList(tint); + setDrawableTintList(tint); mPaint.setColor(tint.getDefaultColor()); invalidateSelf(); } + protected void setDrawableTintList(@Nullable ColorStateList tint) { + mDrawable.setTintList(tint); + } + @Override public void setTintMode(@NonNull Mode tintMode) { mTintMode = tintMode; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java index 8074cb9b0443..e8c8b9075792 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java @@ -33,6 +33,7 @@ import com.android.systemui.plugins.qs.QSIconView; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.qs.QSTile.State; +import com.android.systemui.qs.AlphaControlledSignalTileView.AlphaControlledSlashImageView; import java.util.Objects; public class QSIconViewImpl extends QSIconView { @@ -138,7 +139,12 @@ public class QSIconViewImpl extends QSIconView { animateGrayScale(mTint, color, iv); mTint = color; } else { - setTint(iv, color); + if (iv instanceof AlphaControlledSlashImageView) { + ((AlphaControlledSlashImageView)iv) + .setFinalImageTintList(ColorStateList.valueOf(color)); + } else { + setTint(iv, color); + } mTint = color; } } @@ -149,6 +155,10 @@ public class QSIconViewImpl extends QSIconView { } public static void animateGrayScale(int fromColor, int toColor, ImageView iv) { + if (iv instanceof AlphaControlledSlashImageView) { + ((AlphaControlledSlashImageView)iv) + .setFinalImageTintList(ColorStateList.valueOf(toColor)); + } if (ValueAnimator.areAnimatorsEnabled()) { final float fromAlpha = Color.alpha(fromColor); final float toAlpha = Color.alpha(toColor); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java index 97e9c3dfd82c..63d6f82ce9e6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java @@ -34,7 +34,15 @@ public class SlashImageView extends ImageView { super(context); } - private void ensureSlashDrawable() { + protected SlashDrawable getSlash() { + return mSlash; + } + + protected void setSlash(SlashDrawable slash) { + mSlash = slash; + } + + protected void ensureSlashDrawable() { if (mSlash == null) { mSlash = new SlashDrawable(getDrawable()); mSlash.setAnimationEnabled(mAnimationEnabled); @@ -56,10 +64,18 @@ public class SlashImageView extends ImageView { } } + protected void setImageViewDrawable(SlashDrawable slash) { + super.setImageDrawable(slash); + } + public void setAnimationEnabled(boolean enabled) { mAnimationEnabled = enabled; } + public boolean getAnimationEnabled() { + return mAnimationEnabled; + } + private void setSlashState(@NonNull SlashState slashState) { ensureSlashDrawable(); mSlash.setRotation(slashState.rotation); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java index 33b15121b47e..23702736b0db 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java @@ -37,10 +37,10 @@ import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.plugins.qs.QSIconView; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.qs.QSTile.SignalState; +import com.android.systemui.qs.AlphaControlledSignalTileView; import com.android.systemui.qs.QSDetailItems; import com.android.systemui.qs.QSDetailItems.Item; import com.android.systemui.qs.QSHost; -import com.android.systemui.qs.SignalTileView; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.NetworkController.AccessPointController; @@ -104,7 +104,7 @@ public class WifiTile extends QSTileImpl<SignalState> { @Override public QSIconView createTileView(Context context) { - return new SignalTileView(context); + return new AlphaControlledSignalTileView(context); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java index aecf95fc677f..43227ab4f313 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java @@ -173,7 +173,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener } @Override - public void onActivityPinned(String packageName, int taskId) { + public void onActivityPinned(String packageName, int userId, int taskId) { // Check this is for the right user if (!checkCurrentUserId(mContext, false /* debug */)) { return; @@ -565,8 +565,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener // 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 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener // 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 3db106e7200f..862a1eee8c39 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 class LaunchTaskEvent extends EventBus.Event { 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 717778228989..5a5251e19337 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.HOME_STACK_ID; 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; @@ -172,7 +176,7 @@ public class SystemServicesProxy { public void onTaskStackChangedBackground() { } public void onTaskStackChanged() { } public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) { } - public void onActivityPinned(String packageName, int taskId) { } + public void onActivityPinned(String packageName, int userId, int taskId) { } public void onActivityUnpinned() { } public void onPinnedActivityRestartAttempt(boolean clearedTask) { } public void onPinnedStackAnimationStarted() { } @@ -227,9 +231,10 @@ public class SystemServicesProxy { } @Override - public void onActivityPinned(String packageName, int taskId) throws RemoteException { + public void onActivityPinned(String packageName, int userId, int taskId) + throws RemoteException { mHandler.removeMessages(H.ON_ACTIVITY_PINNED); - mHandler.obtainMessage(H.ON_ACTIVITY_PINNED, taskId, 0, packageName).sendToTarget(); + mHandler.obtainMessage(H.ON_ACTIVITY_PINNED, userId, taskId, packageName).sendToTarget(); } @Override @@ -576,7 +581,7 @@ public class SystemServicesProxy { 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 +1125,16 @@ public class SystemServicesProxy { 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 +1145,14 @@ public class SystemServicesProxy { 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; @@ -1343,7 +1357,8 @@ public class SystemServicesProxy { } case ON_ACTIVITY_PINNED: { for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { - mTaskStackListeners.get(i).onActivityPinned((String) msg.obj, msg.arg1); + mTaskStackListeners.get(i).onActivityPinned((String) msg.obj, msg.arg1, + msg.arg2); } break; } 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 b2675d7ac858..4d3321638e8e 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.DOCKED_STACK_ID; 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 class RecentsTransitionHelper { */ 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 @@ public class RecentsTransitionHelper { // 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 @@ public class RecentsTransitionHelper { 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 @@ public class RecentsTransitionHelper { @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 @@ public class RecentsTransitionHelper { * * @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 @@ public class RecentsTransitionHelper { * 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 @@ public class RecentsTransitionHelper { 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 @@ public class RecentsTransitionHelper { 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 c44cd7287625..fd1b806abf24 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 @@ public class RecentsView extends FrameLayout { 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 @@ public class RecentsView extends FrameLayout { 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 class RecentsView extends FrameLayout { 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 8899e307bb16..74e9ef2b3efb 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 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal 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 class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal 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 ceeebd96a3e1..c64f6dfcea4a 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 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks 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 ae922fcc218e..198ecae2d1a9 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.SystemServicesProxy; 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 @@ public class TaskViewHeader extends FrameLayout 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 @@ public class TaskViewHeader extends FrameLayout // 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 @@ public class TaskViewHeader extends FrameLayout 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 6bfef20c9f53..44e60eed8c7c 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 @@ public class DividerView extends FrameLayout implements OnTouchListener, 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 @@ public class DividerView extends FrameLayout implements OnTouchListener, 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 @@ public class DividerView extends FrameLayout implements OnTouchListener, 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 @@ public class DividerView extends FrameLayout implements OnTouchListener, @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 c24512649c2f..185f6e369f76 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 @@ public class WindowManagerProxy { } }; - 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 @@ public class WindowManagerProxy { 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/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java index 8fa904e10b4a..966e78997244 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -64,10 +64,10 @@ import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem; import com.android.systemui.statusbar.NotificationGuts.GutsContent; import com.android.systemui.statusbar.notification.AboveShelfChangedListener; +import com.android.systemui.statusbar.notification.AboveShelfObserver; import com.android.systemui.statusbar.notification.HybridNotificationView; import com.android.systemui.statusbar.notification.NotificationInflater; import com.android.systemui.statusbar.notification.NotificationUtils; -import com.android.systemui.statusbar.notification.NotificationViewWrapper; import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.StatusBar; @@ -436,9 +436,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } else { minHeight = mNotificationMinHeight; } - NotificationViewWrapper collapsedWrapper = layout.getVisibleWrapper( - NotificationContentView.VISIBLE_TYPE_CONTRACTED); - minHeight += collapsedWrapper.getMinHeightIncrease(mUseIncreasedCollapsedHeight); boolean headsUpCustom = layout.getHeadsUpChild() != null && layout.getHeadsUpChild().getId() != com.android.internal.R.id.status_bar_latest_event_content; @@ -450,11 +447,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } else { headsUpheight = mMaxHeadsUpHeight; } - NotificationViewWrapper headsUpWrapper = layout.getVisibleWrapper( - NotificationContentView.VISIBLE_TYPE_HEADSUP); - if (headsUpWrapper != null) { - headsUpheight += headsUpWrapper.getMinHeightIncrease(mUseIncreasedCollapsedHeight); - } layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight, mNotificationAmbientHeight); } 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 7e08d5605f40..9d2d71e28e5e 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 @@ class CarNavigationBarController { // 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 @@ class CarNavigationBarController { // 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 @@ class CarNavigationBarController { */ 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 680f693a83f8..10fc496fcfd2 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 @@ public class CarStatusBar extends StatusBar implements 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/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java index 9bfa7a9752a8..bb979ebd1288 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java @@ -25,7 +25,6 @@ import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; -import com.android.systemui.R; import com.android.systemui.statusbar.CrossFadeHelper; import com.android.systemui.statusbar.ExpandableNotificationRow; import com.android.systemui.statusbar.TransformableView; @@ -48,7 +47,6 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp private int mContentHeight; private int mMinHeightHint; - private boolean mColorized; protected NotificationTemplateViewWrapper(Context ctx, View view, ExpandableNotificationRow row) { @@ -164,9 +162,7 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp public void onContentUpdated(ExpandableNotificationRow row) { // Reinspect the notification. Before the super call, because the super call also updates // the transformation types and we need to have our values set by then. - StatusBarNotification sbn = row.getStatusBarNotification(); - resolveTemplateViews(sbn); - mColorized = sbn.getNotification().isColorized(); + resolveTemplateViews(row.getStatusBarNotification()); super.onContentUpdated(row); } @@ -269,17 +265,6 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp updateActionOffset(); } - @Override - public int getMinHeightIncrease(boolean useIncreasedCollapsedHeight) { - if (mColorized) { - int dimen = useIncreasedCollapsedHeight - ? R.dimen.notification_height_increase_colorized_increased - : R.dimen.notification_height_increase_colorized; - return mRow.getResources().getDimensionPixelSize(dimen); - } - return super.getMinHeightIncrease(useIncreasedCollapsedHeight); - } - private void updateActionOffset() { if (mActionsContainer != null) { // We should never push the actions higher than they are in the headsup view. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java index 085bce971ffc..5200d6962ed5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java @@ -190,14 +190,4 @@ public abstract class NotificationViewWrapper implements TransformableView { public boolean disallowSingleClick(float x, float y) { return false; } - - /** - * Get the amount that the minheight is allowed to be increased based on this layout. - * - * @param increasedHeight is the view allowed to show even bigger, i.e for messaging layouts - * @return - */ - public int getMinHeightIncrease(boolean increasedHeight) { - return 0; - } } 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 200cada972a7..4739a2eed6de 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_HIDDEN; 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.animation.AnimatorListenerAdapter; 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 @@ public class StatusBar extends SystemUI implements DemoMode, mNotificationData.setHeadsUpManager(mHeadsUpManager); mGroupManager.setHeadsUpManager(mHeadsUpManager); mHeadsUpManager.setVisualStabilityManager(mVisualStabilityManager); + putComponent(HeadsUpManager.class, mHeadsUpManager); if (MULTIUSER_DEBUG) { mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById( @@ -5931,7 +5932,7 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, } 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/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java index a3aca6e1b649..7bb987ca7cf0 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java +++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java @@ -524,18 +524,17 @@ public class ZenModePanel extends FrameLayout { bindGenericCountdown(); bindNextAlarm(getTimeUntilNextAlarmCondition()); } else if (isForever(c)) { + getConditionTagAt(FOREVER_CONDITION_INDEX).rb.setChecked(true); bindGenericCountdown(); bindNextAlarm(getTimeUntilNextAlarmCondition()); } else { if (isAlarm(c)) { bindGenericCountdown(); - bindNextAlarm(c); getConditionTagAt(COUNTDOWN_ALARM_CONDITION_INDEX).rb.setChecked(true); } else if (isCountdown(c)) { bindNextAlarm(getTimeUntilNextAlarmCondition()); - bind(c, mZenRadioGroupContent.getChildAt(COUNTDOWN_CONDITION_INDEX), COUNTDOWN_CONDITION_INDEX); getConditionTagAt(COUNTDOWN_CONDITION_INDEX).rb.setChecked(true); @@ -568,8 +567,8 @@ public class ZenModePanel extends FrameLayout { tag = (ConditionTag) alarmContent.getTag(); boolean showAlarm = tag != null && tag.condition != null; mZenRadioGroup.getChildAt(COUNTDOWN_ALARM_CONDITION_INDEX).setVisibility( - showAlarm ? View.VISIBLE : View.GONE); - alarmContent.setVisibility(showAlarm ? View.VISIBLE : View.GONE); + showAlarm ? View.VISIBLE : View.INVISIBLE); + alarmContent.setVisibility(showAlarm ? View.VISIBLE : View.INVISIBLE); } private Condition forever() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/AlphaControlledSignalTileViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/AlphaControlledSignalTileViewTest.java new file mode 100644 index 000000000000..3e677c01fd57 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/AlphaControlledSignalTileViewTest.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs; + + +import static org.junit.Assert.assertTrue; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.content.res.ColorStateList; +import android.graphics.drawable.Drawable; +import android.test.suitebuilder.annotation.SmallTest; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.qs.AlphaControlledSignalTileView.AlphaControlledSlashDrawable; +import com.android.systemui.qs.AlphaControlledSignalTileView.AlphaControlledSlashImageView; +import org.junit.Test; + +@SmallTest +public class AlphaControlledSignalTileViewTest extends SysuiTestCase { + + private AlphaControlledSignalTileView mTileView; + + @Test + public void testTileView_createsAlphaControlledSlashImageView() { + mTileView = new AlphaControlledSignalTileView(mContext); + + assertTrue(mTileView.createSlashImageView(mContext) + instanceof AlphaControlledSlashImageView); + } + + /// AlphaControlledSlashImageView tests + @Test + public void testSlashImageView_createsAlphaControlledSlashDrawable() { + TestableSlashImageView iv = new TestableSlashImageView(mContext); + + iv.ensureSlashDrawable(); + assertTrue(iv.getSlashDrawable() instanceof AlphaControlledSlashDrawable); + } + + /// AlphaControlledSlashDrawable tests + @Test + public void testSlashDrawable_doesNotSetTintList() { + Drawable mockDrawable = mock(Drawable.class); + AlphaControlledSlashDrawable drawable = new AlphaControlledSlashDrawable(mockDrawable); + ColorStateList list = ColorStateList.valueOf(0xffffff); + drawable.setTintList(list); + verify(mockDrawable, never()).setTintList(any()); + } + + @Test + public void testSlashDrawable_setsFinalTintList() { + Drawable mockDrawable = mock(Drawable.class); + AlphaControlledSlashDrawable drawable = new AlphaControlledSlashDrawable(mockDrawable); + ColorStateList list = ColorStateList.valueOf(0xffffff); + drawable.setFinalTintList(list); + verify(mockDrawable, atLeastOnce()).setTintList(list); + } + + // Expose getSlashDrawable + private static class TestableSlashImageView extends AlphaControlledSlashImageView { + TestableSlashImageView(Context c) { + super(c); + } + + private SlashDrawable getSlashDrawable() { + return mSlash; + } + + @Override + protected void setSlash(SlashDrawable slash) { + super.setSlash(slash); + } + } +} diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 07302706d134..523e6b2a7b63 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -4610,6 +4610,11 @@ message MetricsEvent { // 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/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index a1c75bfc16c0..b9bea163a8a5 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -120,6 +120,18 @@ public final class AutofillManagerService extends SystemService { @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) { + if (sDebug) Slog.d(TAG, "Close system dialogs"); + + // TODO(b/64940307): we need to destroy all sessions that are finished but showing + // Save UI because there is no way to show the Save UI back when the activity + // beneath it is brought back to top. Ideally, we should just hide the UI and + // bring it back when the activity resumes. + synchronized (mLock) { + for (int i = 0; i < mServicesCache.size(); i++) { + mServicesCache.valueAt(i).destroyFinishedSessionsLocked(); + } + } + mUi.hideAll(null); } } diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 77ce87171a4b..59022e3ff14e 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -452,7 +452,7 @@ final class AutofillManagerServiceImpl { final int sessionCount = mSessions.size(); for (int i = sessionCount - 1; i >= 0; i--) { final Session session = mSessions.valueAt(i); - if (session.isSaveUiPendingForToken(token)) { + if (session.isSaveUiPendingForTokenLocked(token)) { session.onPendingSaveUi(operation, token); return; } @@ -638,7 +638,7 @@ final class AutofillManagerServiceImpl { void destroySessionsLocked() { if (mSessions.size() == 0) { - mUi.destroyAll(null, null); + mUi.destroyAll(null, null, false); return; } while (mSessions.size() > 0) { @@ -646,6 +646,18 @@ final class AutofillManagerServiceImpl { } } + // TODO(b/64940307): remove this method if SaveUI is refactored to be attached on activities + void destroyFinishedSessionsLocked() { + final int sessionCount = mSessions.size(); + for (int i = sessionCount - 1; i >= 0; i--) { + final Session session = mSessions.valueAt(i); + if (session.isSavingLocked()) { + if (sDebug) Slog.d(TAG, "destroyFinishedSessionsLocked(): " + session.id); + session.forceRemoveSelfLocked(); + } + } + } + void listSessionsLocked(ArrayList<String> output) { final int numSessions = mSessions.size(); for (int i = 0; i < numSessions; i++) { diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java index f315148547e9..af55807ff1f0 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 @@ final class RemoteFillService implements DeathRecipient { 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 09ecdd534da9..f81ecf247ac7 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 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState 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 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // 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 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState return; } fillInIntent = createAuthFillInIntentLocked(requestId, extras); + if (fillInIntent == null) { + forceRemoveSelfLocked(); + return; + } } mService.setAuthenticationSelected(id, mClientState); @@ -1361,11 +1369,15 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } } - 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(AutofillManager.STATE_FINISHED); + } } catch (RemoteException e) { Slog.e(TAG, "Error notifying client no fill UI: id=" + mCurrentViewId, e); } @@ -1453,7 +1465,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } mService.resetLastResponse(); // Nothing to be done, but need to notify client. - notifyUnavailableToClient(); + notifyUnavailableToClient(true); removeSelf(); } @@ -1572,6 +1584,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } 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 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState 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 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } } + // 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 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState if (mDestroyed) { return null; } - mUi.destroyAll(mPendingSaveUi, this); + mUi.destroyAll(mPendingSaveUi, this, true); mUi.clearCallback(this); mDestroyed = true; writeLog(MetricsEvent.AUTOFILL_SESSION_FINISHED); @@ -1773,9 +1795,17 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState void forceRemoveSelfLocked() { if (sVerbose) Slog.v(TAG, "forceRemoveSelfLocked(): " + mPendingSaveUi); + final boolean isPendingSaveUi = isSaveUiPendingLocked(); mPendingSaveUi = null; removeSelfLocked(); - mUi.destroyAll(mPendingSaveUi, this); + mUi.destroyAll(mPendingSaveUi, this, false); + if (!isPendingSaveUi) { + try { + mClient.setSessionFinished(AutofillManager.STATE_UNKNOWN); + } catch (RemoteException e) { + Slog.e(TAG, "Error notifying client to finish session", e); + } + } } /** @@ -1798,7 +1828,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState + id + " destroyed"); return; } - if (isSaveUiPending()) { + if (isSaveUiPendingLocked()) { Slog.i(TAG, "removeSelfLocked() ignored, waiting for pending save ui"); return; } @@ -1819,14 +1849,14 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState * a specific {@code token} created by * {@link PendingUi#PendingUi(IBinder, int, IAutoFillManagerClient)}. */ - boolean isSaveUiPendingForToken(@NonNull IBinder token) { - return isSaveUiPending() && token.equals(mPendingSaveUi.getToken()); + boolean isSaveUiPendingForTokenLocked(@NonNull IBinder token) { + return isSaveUiPendingLocked() && token.equals(mPendingSaveUi.getToken()); } /** * Checks whether this session is hiding the Save UI to handle a custom description link. */ - private boolean isSaveUiPending() { + private boolean isSaveUiPendingLocked() { return mPendingSaveUi != null && mPendingSaveUi.getState() == PendingUi.STATE_PENDING; } 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 434b590d2d12..36b95fc02ed8 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 @@ public final class AutoFillUI { if (mCallback != null) { mCallback.save(); } - destroySaveUiUiThread(pendingSaveUi); + destroySaveUiUiThread(pendingSaveUi, true); } @Override @@ -293,7 +293,7 @@ public final class AutoFillUI { if (mCallback != null) { mCallback.cancelSave(); } - destroySaveUiUiThread(pendingSaveUi); + destroySaveUiUiThread(pendingSaveUi, true); } @Override @@ -335,8 +335,8 @@ public final class AutoFillUI { * 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 @@ public final class AutoFillUI { } @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 @@ public final class AutoFillUI { 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 @@ public final class AutoFillUI { @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 @@ public final class AutoFillUI { Slog.d(TAG, "hideAllUiThread(): " + "destroying Save UI because pending restoration is finished"); } - destroySaveUiUiThread(pendingSaveUi); + destroySaveUiUiThread(pendingSaveUi, true); } } } diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java index 32f4d69fc3e3..cd9bdb7205b1 100644 --- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java @@ -263,9 +263,7 @@ final class SaveUi { } else { noButton.setText(R.string.autofill_save_no); } - final View.OnClickListener cancelListener = - (v) -> mListener.onCancel(info.getNegativeActionListener()); - noButton.setOnClickListener(cancelListener); + noButton.setOnClickListener((v) -> mListener.onCancel(info.getNegativeActionListener())); final View yesButton = view.findViewById(R.id.autofill_save_yes); yesButton.setOnClickListener((v) -> mListener.onSave()); @@ -273,9 +271,6 @@ final class SaveUi { mDialog = new Dialog(context, R.style.Theme_DeviceDefault_Light_Panel); mDialog.setContentView(view); - // Dialog can be dismissed when touched outside. - mDialog.setOnDismissListener((d) -> mListener.onCancel(info.getNegativeActionListener())); - final Window window = mDialog.getWindow(); window.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE @@ -305,7 +300,7 @@ final class SaveUi { if (actualWidth <= maxWidth && actualHeight <= maxHeight) { if (sDebug) { - Slog.d(TAG, "Addingservice icon " + Slog.d(TAG, "Adding service icon " + "(" + actualWidth + "x" + actualHeight + ") as it's less than maximum " + "(" + maxWidth + "x" + maxHeight + ")."); } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index bfe50404a26a..3ac6f2e847f6 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -128,7 +128,6 @@ import com.android.server.connectivity.DataConnectionStats; import com.android.server.connectivity.KeepaliveTracker; import com.android.server.connectivity.LingerMonitor; import com.android.server.connectivity.MockableSystemProperties; -import com.android.server.connectivity.Nat464Xlat; import com.android.server.connectivity.NetworkAgentInfo; import com.android.server.connectivity.NetworkDiagnostics; import com.android.server.connectivity.NetworkMonitor; @@ -2205,7 +2204,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // A network factory has connected. Send it all current NetworkRequests. for (NetworkRequestInfo nri : mNetworkRequests.values()) { if (nri.request.isListen()) continue; - NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId); + NetworkAgentInfo nai = getNetworkForRequest(nri.request.requestId); ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, (nai != null ? nai.getCurrentScore() : 0), 0, nri.request); } @@ -2282,9 +2281,9 @@ public class ConnectivityService extends IConnectivityManager.Stub // Remove all previously satisfied requests. for (int i = 0; i < nai.numNetworkRequests(); i++) { NetworkRequest request = nai.requestAt(i); - NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(request.requestId); + NetworkAgentInfo currentNetwork = getNetworkForRequest(request.requestId); if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) { - mNetworkForRequestId.remove(request.requestId); + clearNetworkForRequest(request.requestId); sendUpdatedScoreToFactories(request, 0); } } @@ -2360,7 +2359,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } } rematchAllNetworksAndRequests(null, 0); - if (nri.request.isRequest() && mNetworkForRequestId.get(nri.request.requestId) == null) { + if (nri.request.isRequest() && getNetworkForRequest(nri.request.requestId) == null) { sendUpdatedScoreToFactories(nri.request, 0); } } @@ -2415,7 +2414,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // 2. Unvalidated WiFi will not be reaped when validated cellular // is currently satisfying the request. This is desirable when // WiFi ends up validating and out scoring cellular. - mNetworkForRequestId.get(nri.request.requestId).getCurrentScore() < + getNetworkForRequest(nri.request.requestId).getCurrentScore() < nai.getCurrentScoreAsValidated())) { return false; } @@ -2442,7 +2441,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (mNetworkRequests.get(nri.request) == null) { return; } - if (mNetworkForRequestId.get(nri.request.requestId) != null) { + if (getNetworkForRequest(nri.request.requestId) != null) { return; } if (VDBG || (DBG && nri.request.isRequest())) { @@ -2482,7 +2481,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mNetworkRequestInfoLogs.log("RELEASE " + nri); if (nri.request.isRequest()) { boolean wasKept = false; - NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId); + NetworkAgentInfo nai = getNetworkForRequest(nri.request.requestId); if (nai != null) { boolean wasBackgroundNetwork = nai.isBackgroundNetwork(); nai.removeRequest(nri.request.requestId); @@ -2499,7 +2498,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } else { wasKept = true; } - mNetworkForRequestId.remove(nri.request.requestId); + clearNetworkForRequest(nri.request.requestId); if (!wasBackgroundNetwork && nai.isBackgroundNetwork()) { // Went from foreground to background. updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities); @@ -4296,7 +4295,8 @@ public class ConnectivityService extends IConnectivityManager.Stub * and the are the highest scored network available. * the are keyed off the Requests requestId. */ - // TODO: Yikes, this is accessed on multiple threads: add synchronization. + // NOTE: Accessed on multiple threads, must be synchronized on itself. + @GuardedBy("mNetworkForRequestId") private final SparseArray<NetworkAgentInfo> mNetworkForRequestId = new SparseArray<NetworkAgentInfo>(); @@ -4326,8 +4326,26 @@ public class ConnectivityService extends IConnectivityManager.Stub // priority networks like Wi-Fi are active. private final NetworkRequest mDefaultMobileDataRequest; + private NetworkAgentInfo getNetworkForRequest(int requestId) { + synchronized (mNetworkForRequestId) { + return mNetworkForRequestId.get(requestId); + } + } + + private void clearNetworkForRequest(int requestId) { + synchronized (mNetworkForRequestId) { + mNetworkForRequestId.remove(requestId); + } + } + + private void setNetworkForRequest(int requestId, NetworkAgentInfo nai) { + synchronized (mNetworkForRequestId) { + mNetworkForRequestId.put(requestId, nai); + } + } + private NetworkAgentInfo getDefaultNetwork() { - return mNetworkForRequestId.get(mDefaultRequest.requestId); + return getNetworkForRequest(mDefaultRequest.requestId); } private boolean isDefaultNetwork(NetworkAgentInfo nai) { @@ -4881,7 +4899,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // requests or not, and doesn't affect the network's score. if (nri.request.isListen()) continue; - final NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId); + final NetworkAgentInfo currentNetwork = getNetworkForRequest(nri.request.requestId); final boolean satisfies = newNetwork.satisfies(nri.request); if (newNetwork == currentNetwork && satisfies) { if (VDBG) { @@ -4913,7 +4931,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (VDBG) log(" accepting network in place of null"); } newNetwork.unlingerRequest(nri.request); - mNetworkForRequestId.put(nri.request.requestId, newNetwork); + setNetworkForRequest(nri.request.requestId, newNetwork); if (!newNetwork.addRequest(nri.request)) { Slog.wtf(TAG, "BUG: " + newNetwork.name() + " already has " + nri.request); } @@ -4947,7 +4965,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } newNetwork.removeRequest(nri.request.requestId); if (currentNetwork == newNetwork) { - mNetworkForRequestId.remove(nri.request.requestId); + clearNetworkForRequest(nri.request.requestId); sendUpdatedScoreToFactories(nri.request, 0); } else { Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " + diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 8ae592f7978a..98e08e09049b 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -5285,7 +5285,7 @@ public class AccountManagerService == PackageManager.PERMISSION_GRANTED) { // Checks runtime permission revocation. final int opCode = AppOpsManager.permissionToOpCode(perm); - if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp( + if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOpNoThrow( opCode, uid, packageName) == AppOpsManager.MODE_ALLOWED) { return true; } @@ -5306,7 +5306,7 @@ public class AccountManagerService Log.v(TAG, " caller uid " + callingUid + " has " + perm); } final int opCode = AppOpsManager.permissionToOpCode(perm); - if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp( + if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOpNoThrow( opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) { return true; } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index d516d696ff84..12778d82d387 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -145,7 +145,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CLEANUP; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_FOCUS; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_IMMERSIVE; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKSCREEN; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LRU; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU; @@ -163,7 +162,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_UID_OBSERVERS; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_URI_PERMISSION; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBLE_BEHIND; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.am.ActivityStackSupervisor.CREATE_IF_NEEDED; @@ -177,6 +175,7 @@ import static com.android.server.am.TaskRecord.INVALID_TASK_ID; import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK; import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT; import static com.android.server.am.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE; +import static com.android.server.am.proto.ActivityManagerServiceProto.ACTIVITIES; import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_OPEN; import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_RELAUNCH; import static com.android.server.wm.AppTransition.TRANSIT_NONE; @@ -349,6 +348,7 @@ import android.util.SparseArray; import android.util.SparseIntArray; import android.util.TimeUtils; import android.util.Xml; +import android.util.proto.ProtoOutputStream; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; @@ -402,6 +402,7 @@ import com.android.server.firewall.IntentFirewall; import com.android.server.job.JobSchedulerInternal; import com.android.server.pm.Installer; import com.android.server.pm.Installer.InstallerException; +import com.android.server.utils.PriorityDump; import com.android.server.vr.VrManagerInternal; import com.android.server.wm.PinnedStackWindowController; import com.android.server.wm.WindowManagerService; @@ -707,6 +708,42 @@ public class ActivityManagerService extends IActivityManager.Stub @VisibleForTesting long mWaitForNetworkTimeoutMs; + /** + * Helper class which parses out priority arguments and dumps sections according to their + * priority. If priority arguments are omitted, function calls the legacy dump command. + */ + private final PriorityDump.PriorityDumper mPriorityDumper = new PriorityDump.PriorityDumper() { + @Override + public void dumpCritical(FileDescriptor fd, PrintWriter pw, String[] args) { + doDump(fd, pw, new String[] {"activities"}); + } + + @Override + public void dumpNormal(FileDescriptor fd, PrintWriter pw, String[] args) { + doDump(fd, pw, new String[] {"settings"}); + doDump(fd, pw, new String[] {"intents"}); + doDump(fd, pw, new String[] {"broadcasts"}); + doDump(fd, pw, new String[] {"providers"}); + doDump(fd, pw, new String[] {"permissions"}); + doDump(fd, pw, new String[] {"services"}); + doDump(fd, pw, new String[] {"recents"}); + doDump(fd, pw, new String[] {"lastanr"}); + doDump(fd, pw, new String[] {"starter"}); + if (mAssociations.size() > 0) { + doDump(fd, pw, new String[] {"associations"}); + } + doDump(fd, pw, new String[] {"processes"}); + doDump(fd, pw, new String[] {"-v", "all"}); + doDump(fd, pw, new String[] {"service", "all"}); + doDump(fd, pw, new String[] {"provider", "all"}); + } + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + doDump(fd, pw, args); + } + }; + public boolean canShowErrorDialogs() { return mShowDialogs && !mSleeping && !mShuttingDown && !mKeyguardController.isKeyguardShowing(DEFAULT_DISPLAY) @@ -2503,6 +2540,14 @@ public class ActivityManagerService extends IActivityManager.Stub static class MemBinder extends Binder { ActivityManagerService mActivityManagerService; + private final PriorityDump.PriorityDumper mPriorityDumper = + new PriorityDump.PriorityDumper() { + @Override + public void dumpNormal(FileDescriptor fd, PrintWriter pw, String[] args) { + mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, " ", args, false, null); + } + }; + MemBinder(ActivityManagerService activityManagerService) { mActivityManagerService = activityManagerService; } @@ -2511,7 +2556,7 @@ public class ActivityManagerService extends IActivityManager.Stub protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext, "meminfo", pw)) return; - mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, " ", args, false, null); + PriorityDump.dump(mPriorityDumper, fd, pw, args); } } @@ -2545,19 +2590,27 @@ public class ActivityManagerService extends IActivityManager.Stub static class CpuBinder extends Binder { ActivityManagerService mActivityManagerService; + private final PriorityDump.PriorityDumper mPriorityDumper = + new PriorityDump.PriorityDumper() { + @Override + public void dumpCritical(FileDescriptor fd, PrintWriter pw, String[] args) { + if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext, + "cpuinfo", pw)) return; + synchronized (mActivityManagerService.mProcessCpuTracker) { + pw.print(mActivityManagerService.mProcessCpuTracker.printCurrentLoad()); + pw.print(mActivityManagerService.mProcessCpuTracker.printCurrentState( + SystemClock.uptimeMillis())); + } + } + }; + CpuBinder(ActivityManagerService activityManagerService) { mActivityManagerService = activityManagerService; } @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext, - "cpuinfo", pw)) return; - synchronized (mActivityManagerService.mProcessCpuTracker) { - pw.print(mActivityManagerService.mProcessCpuTracker.printCurrentLoad()); - pw.print(mActivityManagerService.mProcessCpuTracker.printCurrentState( - SystemClock.uptimeMillis())); - } + PriorityDump.dump(mPriorityDumper, fd, pw, args); } } @@ -9957,7 +10010,7 @@ public class ActivityManagerService extends IActivityManager.Stub 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 +10123,7 @@ public class ActivityManagerService extends IActivityManager.Stub 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 +10186,7 @@ public class ActivityManagerService extends IActivityManager.Stub 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 +10218,7 @@ public class ActivityManagerService extends IActivityManager.Stub 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 +10237,7 @@ public class ActivityManagerService extends IActivityManager.Stub 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 +10257,7 @@ public class ActivityManagerService extends IActivityManager.Stub 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 +10571,6 @@ public class ActivityManagerService extends IActivityManager.Stub } } - @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. * @@ -14843,6 +14846,13 @@ public class ActivityManagerService extends IActivityManager.Stub @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + PriorityDump.dump(mPriorityDumper, fd, pw, args); + } + + /** + * Wrapper function to print out debug data filtered by specified arguments. + */ + private void doDump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return; boolean dumpAll = false; @@ -14851,6 +14861,7 @@ public class ActivityManagerService extends IActivityManager.Stub boolean dumpCheckinFormat = false; boolean dumpVisibleStacksOnly = false; boolean dumpFocusedStackOnly = false; + boolean useProto = false; String dumpPackage = null; int opti = 0; @@ -14884,12 +14895,26 @@ public class ActivityManagerService extends IActivityManager.Stub } else if ("-h".equals(opt)) { ActivityManagerShellCommand.dumpHelp(pw, true); return; + } else if ("--proto".equals(opt)) { + useProto = true; } else { pw.println("Unknown argument: " + opt + "; use -h for help"); } } long origId = Binder.clearCallingIdentity(); + + if (useProto) { + //TODO: Options when dumping proto + final ProtoOutputStream proto = new ProtoOutputStream(fd); + synchronized (this) { + writeActivitiesToProtoLocked(proto); + } + proto.flush(); + Binder.restoreCallingIdentity(origId); + return; + } + boolean more = false; // Is the caller requesting to dump a particular piece of data? if (opti < args.length) { @@ -15233,6 +15258,10 @@ public class ActivityManagerService extends IActivityManager.Stub Binder.restoreCallingIdentity(origId); } + private void writeActivitiesToProtoLocked(ProtoOutputStream proto) { + mStackSupervisor.writeToProto(proto, ACTIVITIES); + } + private void dumpLastANRLocked(PrintWriter pw) { pw.println("ACTIVITY MANAGER LAST ANR (dumpsys activity lastanr)"); if (mLastANRState == null) { diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 6901d2de6f00..5e0724e94b41 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_SYSTEM; 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 @@ final class ActivityManagerShellCommand extends ShellCommand { 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 @@ final class ActivityManagerShellCommand extends ShellCommand { 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 @@ final class ActivityManagerShellCommand extends ShellCommand { 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 @@ final class ActivityManagerShellCommand extends ShellCommand { 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(); @@ -2661,6 +2675,7 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" -p: limit output to given package."); pw.println(" --checkin: output checkin format, resetting data."); pw.println(" --C: output checkin format, not resetting data."); + pw.println(" --proto: output dump in protocol buffer format."); } else { pw.println("Activity manager (activity) commands:"); pw.println(" help"); @@ -2685,7 +2700,8 @@ final class ActivityManagerShellCommand extends ShellCommand { 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 0ccb45f74ec2..142c97ba0e7b 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.AppOpsManager.OP_PICTURE_IN_PICTURE; 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_SWITCH; 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; @@ -116,6 +112,16 @@ import static com.android.server.am.EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY; import static com.android.server.am.TaskPersister.DEBUG; import static com.android.server.am.TaskPersister.IMAGE_EXTENSION; import static com.android.server.am.TaskRecord.INVALID_TASK_ID; +import static com.android.server.am.proto.ActivityRecordProto.CONFIGURATION_CONTAINER; +import static com.android.server.am.proto.ActivityRecordProto.FRONT_OF_TASK; +import static com.android.server.am.proto.ActivityRecordProto.IDENTIFIER; +import static com.android.server.am.proto.ActivityRecordProto.PROC_ID; +import static com.android.server.am.proto.ActivityRecordProto.STATE; +import static com.android.server.am.proto.ActivityRecordProto.VISIBLE; +import static com.android.server.wm.proto.IdentifierProto.HASH_CODE; +import static com.android.server.wm.proto.IdentifierProto.TITLE; +import static com.android.server.wm.proto.IdentifierProto.USER_ID; + import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; import static org.xmlpull.v1.XmlPullParser.END_TAG; import static org.xmlpull.v1.XmlPullParser.START_TAG; @@ -153,6 +159,7 @@ import android.util.Log; import android.util.MergedConfiguration; import android.util.Slog; import android.util.TimeUtils; +import android.util.proto.ProtoOutputStream; import android.view.AppTransitionAnimationSpec; import android.view.IAppTransitionAnimationSpecsFuture; import android.view.IApplicationToken; @@ -1038,7 +1045,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo } } 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 +1164,15 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo * 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); } /** @@ -2770,4 +2784,25 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo stringName = sb.toString(); return toString(); } + + void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) { + final long token = proto.start(fieldId); + proto.write(HASH_CODE, System.identityHashCode(this)); + proto.write(USER_ID, userId); + proto.write(TITLE, intent.getComponent().flattenToShortString()); + proto.end(token); + } + + public void writeToProto(ProtoOutputStream proto, long fieldId) { + final long token = proto.start(fieldId); + super.writeToProto(proto, CONFIGURATION_CONTAINER); + writeIdentifierToProto(proto, IDENTIFIER); + proto.write(STATE, state.toString()); + proto.write(VISIBLE, visible); + proto.write(FRONT_OF_TASK, frontOfTask); + if (app != null) { + proto.write(PROC_ID, app.pid); + } + proto.end(token); + } } diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 6140c266f96b..8d21862142d7 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -78,6 +78,13 @@ import static com.android.server.am.ActivityStackSupervisor.ON_TOP; import static com.android.server.am.ActivityStackSupervisor.PAUSE_IMMEDIATELY; import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS; +import static com.android.server.am.proto.ActivityStackProto.BOUNDS; +import static com.android.server.am.proto.ActivityStackProto.CONFIGURATION_CONTAINER; +import static com.android.server.am.proto.ActivityStackProto.DISPLAY_ID; +import static com.android.server.am.proto.ActivityStackProto.FULLSCREEN; +import static com.android.server.am.proto.ActivityStackProto.ID; +import static com.android.server.am.proto.ActivityStackProto.RESUMED_ACTIVITY; +import static com.android.server.am.proto.ActivityStackProto.TASKS; import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_CLOSE; import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_OPEN; import static com.android.server.wm.AppTransition.TRANSIT_NONE; @@ -86,6 +93,7 @@ import static com.android.server.wm.AppTransition.TRANSIT_TASK_OPEN; import static com.android.server.wm.AppTransition.TRANSIT_TASK_OPEN_BEHIND; import static com.android.server.wm.AppTransition.TRANSIT_TASK_TO_BACK; import static com.android.server.wm.AppTransition.TRANSIT_TASK_TO_FRONT; + import static java.lang.Integer.MAX_VALUE; import android.app.Activity; @@ -122,6 +130,7 @@ import android.util.IntArray; import android.util.Log; import android.util.Slog; import android.util.SparseArray; +import android.util.proto.ProtoOutputStream; import android.view.Display; import com.android.internal.annotations.VisibleForTesting; @@ -5357,4 +5366,23 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai boolean shouldSleepOrShutDownActivities() { return shouldSleepActivities() || mService.isShuttingDownLocked(); } + + public void writeToProto(ProtoOutputStream proto, long fieldId) { + final long token = proto.start(fieldId); + super.writeToProto(proto, CONFIGURATION_CONTAINER); + proto.write(ID, mStackId); + for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { + final TaskRecord task = mTaskHistory.get(taskNdx); + task.writeToProto(proto, TASKS); + } + if (mResumedActivity != null) { + mResumedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY); + } + proto.write(DISPLAY_ID, mDisplayId); + if (mBounds != null) { + mBounds.writeToProto(proto, BOUNDS); + } + proto.write(FULLSCREEN, mFullscreen); + proto.end(token); + } } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index c8a2a230a7e1..45c4df993801 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.INTERNAL_SYSTEM_WINDOW; 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.INVALID_STACK_ID; 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,17 +91,26 @@ import static com.android.server.am.ActivityStack.ActivityState.STOPPING; 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; import static com.android.server.am.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE; import static com.android.server.am.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT; +import static com.android.server.am.proto.ActivityStackSupervisorProto.DISPLAYS; +import static com.android.server.am.proto.ActivityStackSupervisorProto.FOCUSED_STACK_ID; +import static com.android.server.am.proto.ActivityStackSupervisorProto.KEYGUARD_CONTROLLER; +import static com.android.server.am.proto.ActivityStackSupervisorProto.RESUMED_ACTIVITY; +import static com.android.server.am.proto.ActivityStackSupervisorProto.CONFIGURATION_CONTAINER; +import static com.android.server.am.proto.ActivityDisplayProto.STACKS; +import static com.android.server.am.proto.ActivityDisplayProto.ID; import static com.android.server.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS; import static java.lang.Integer.MAX_VALUE; 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; @@ -147,6 +164,7 @@ import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; import android.util.TimeUtils; +import android.util.proto.ProtoOutputStream; import android.view.Display; import com.android.internal.annotations.VisibleForTesting; @@ -156,6 +174,7 @@ import com.android.internal.os.TransferPipe; import com.android.internal.util.ArrayUtils; import com.android.server.LocalServices; import com.android.server.am.ActivityStack.ActivityState; +import com.android.server.am.proto.ActivityDisplayProto; import com.android.server.wm.ConfigurationContainer; import com.android.server.wm.PinnedStackWindowController; import com.android.server.wm.WindowManagerService; @@ -707,24 +726,26 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } 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 +783,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } // 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 +878,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // 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 +2105,35 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // 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 +2144,18 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D 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 +2180,179 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D 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 +2370,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // 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 +2378,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // 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 +2387,32 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D 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 +2563,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D 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 +2858,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D */ 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 +2957,11 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D /** * 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 +2974,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D 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() @@ -2984,7 +3180,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); resumeFocusedStackTopActivityLocked(); - mService.mTaskChangeNotificationController.notifyActivityPinned(r.packageName, + mService.mTaskChangeNotificationController.notifyActivityPinned(r.packageName, r.userId, r.getTask().taskId); } @@ -3045,6 +3241,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // tasks should always have lower priority than any affinity-matching tasks // in the fullscreen stacks affinityMatch = mTmpFindTaskResult.r; + } else if (DEBUG_TASKS && mTmpFindTaskResult.matchedByRootAffinity) { + Slog.d(TAG_TASKS, "Skipping match on different display " + + mTmpFindTaskResult.r.getDisplayId() + " " + displayId); } } } @@ -3568,6 +3767,26 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D mService.mLockTaskController.dump(pw, prefix); } + public void writeToProto(ProtoOutputStream proto, long fieldId) { + final long token = proto.start(fieldId); + super.writeToProto(proto, CONFIGURATION_CONTAINER); + for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) { + ActivityDisplay activityDisplay = mActivityDisplays.valueAt(displayNdx); + activityDisplay.writeToProto(proto, DISPLAYS); + } + mKeyguardController.writeToProto(proto, KEYGUARD_CONTROLLER); + if (mFocusedStack != null) { + proto.write(FOCUSED_STACK_ID, mFocusedStack.mStackId); + ActivityRecord focusedActivity = getResumedActivityLocked(); + if (focusedActivity != null) { + focusedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY); + } + } else { + proto.write(FOCUSED_STACK_ID, INVALID_STACK_ID); + } + proto.end(token); + } + /** * Dump all connected displays' configurations. * @param prefix Prefix to apply to each line of the dump. @@ -4015,21 +4234,20 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D 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; } @@ -4390,6 +4608,17 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void setIsSleeping(boolean asleep) { mSleeping = asleep; } + + public void writeToProto(ProtoOutputStream proto, long fieldId) { + final long token = proto.start(fieldId); + super.writeToProto(proto, ActivityDisplayProto.CONFIGURATION_CONTAINER); + proto.write(ID, mDisplayId); + for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = mStacks.get(stackNdx); + stack.writeToProto(proto, STACKS); + } + proto.end(token); + } } ActivityStack findStackBehind(ActivityStack stack) { @@ -4424,18 +4653,22 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D 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 +4680,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } 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 +4691,13 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // 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 +4716,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // 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 +4734,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D 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 16abcfb620d9..fab4d0d21b8e 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.ActivityManager.StackId.isDynamicStack; 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; @@ -167,7 +169,8 @@ class ActivityStarter { private boolean mDoResume; private int mStartFlags; private ActivityRecord mSourceRecord; - private int mSourceDisplayId; + // The display to launch the activity onto, barring any strong reason to do otherwise. + private int mPreferredDisplayId; private TaskRecord mInTask; private boolean mAddingToTask; @@ -222,7 +225,7 @@ class ActivityStarter { mDoResume = false; mStartFlags = 0; mSourceRecord = null; - mSourceDisplayId = INVALID_DISPLAY; + mPreferredDisplayId = INVALID_DISPLAY; mInTask = null; mAddingToTask = false; @@ -1024,10 +1027,12 @@ class ActivityStarter { 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 +1163,7 @@ class ActivityStarter { // 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 +1178,7 @@ class ActivityStarter { 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 +1245,7 @@ class ActivityStarter { } mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack); - mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(), preferredLaunchStackId, + mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(), preferredWindowingMode, preferredLaunchDisplayId, mTargetStack.mStackId); return START_SUCCESS; @@ -1260,7 +1264,7 @@ class ActivityStarter { mVoiceSession = voiceSession; mVoiceInteractor = voiceInteractor; - mSourceDisplayId = getSourceDisplayId(mSourceRecord, mStartActivity); + mPreferredDisplayId = getPreferedDisplayId(mSourceRecord, mStartActivity, options); mLaunchBounds = getOverrideBounds(r, options, inTask); @@ -1515,7 +1519,7 @@ class ActivityStarter { !mLaunchSingleTask); } else { // Otherwise find the best task to put the activity in. - intentActivity = mSupervisor.findTaskLocked(mStartActivity, mSourceDisplayId); + intentActivity = mSupervisor.findTaskLocked(mStartActivity, mPreferredDisplayId); } } return intentActivity; @@ -1523,10 +1527,12 @@ class ActivityStarter { /** * Returns the ID of the display to use for a new activity. If the device is in VR mode, - * then return the Vr mode's virtual display ID. If not, if the source activity has - * a explicit display ID set, use that to launch the activity. + * then return the Vr mode's virtual display ID. If not, if the activity was started with + * a launchDisplayId, use that. Otherwise, if the source activity has a explicit display ID + * set, use that to launch the activity. */ - private int getSourceDisplayId(ActivityRecord sourceRecord, ActivityRecord startingActivity) { + private int getPreferedDisplayId( + ActivityRecord sourceRecord, ActivityRecord startingActivity, ActivityOptions options) { // Check if the Activity is a VR activity. If so, the activity should be launched in // main display. if (startingActivity != null && startingActivity.requestedVrComponent != null) { @@ -1543,6 +1549,13 @@ class ActivityStarter { return displayId; } + // If the caller requested a display, prefer that display. + final int launchDisplayId = + (options != null) ? options.getLaunchDisplayId() : INVALID_DISPLAY; + if (launchDisplayId != INVALID_DISPLAY) { + return launchDisplayId; + } + displayId = sourceRecord != null ? sourceRecord.getDisplayId() : INVALID_DISPLAY; // If the activity has a displayId set explicitly, launch it on the same displayId. if (displayId != INVALID_DISPLAY) { @@ -1654,8 +1667,8 @@ class ActivityStarter { 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 +1688,7 @@ class ActivityStarter { // 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 +1791,7 @@ class ActivityStarter { } private int setTaskFromReuseOrCreateNewTask( - TaskRecord taskToAffiliate, int preferredLaunchStackId, ActivityStack topStack) { + TaskRecord taskToAffiliate, ActivityStack topStack) { mTargetStack = computeStackFocus( mStartActivity, true, mLaunchBounds, mLaunchFlags, mOptions); @@ -1821,8 +1833,10 @@ class ActivityStarter { // 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 +1978,8 @@ class ActivityStarter { 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"); @@ -2079,15 +2094,15 @@ class ActivityStarter { return mSupervisor.mFocusedStack; } - if (mSourceDisplayId != DEFAULT_DISPLAY) { + if (mPreferredDisplayId != DEFAULT_DISPLAY) { // Try to put the activity in a stack on a secondary display. - stack = mSupervisor.getValidLaunchStackOnDisplay(mSourceDisplayId, r); + stack = mSupervisor.getValidLaunchStackOnDisplay(mPreferredDisplayId, r); if (stack == null) { // If source display is not suitable - look for topmost valid stack in the system. if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, - "computeStackFocus: Can't launch on mSourceDisplayId=" + mSourceDisplayId - + ", looking on all displays."); - stack = mSupervisor.getNextValidLaunchStackLocked(r, mSourceDisplayId); + "computeStackFocus: Can't launch on mPreferredDisplayId=" + + mPreferredDisplayId + ", looking on all displays."); + stack = mSupervisor.getNextValidLaunchStackLocked(r, mPreferredDisplayId); } } if (stack == null) { @@ -2102,9 +2117,10 @@ class ActivityStarter { } } // 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=" @@ -2142,8 +2158,8 @@ class ActivityStarter { } return canUseFocusedStack && !newTask - // We strongly prefer to launch activities on the same display as their source. - && (mSourceDisplayId == focusedStack.mDisplayId); + // Using the focus stack isn't important enough to override the prefered display. + && (mPreferredDisplayId == focusedStack.mDisplayId); } private ActivityStack getLaunchStack(ActivityRecord r, int launchFlags, TaskRecord task, @@ -2165,18 +2181,16 @@ class ActivityStarter { 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 ? mPreferredDisplayId : 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,14 +2198,16 @@ class ActivityStarter { // 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); + ActivityStack as = mSupervisor.getValidLaunchStackOnDisplay(mPreferredDisplayId, r); if (DEBUG_STACK) { Slog.v(TAG, "Launch stack for app: " + r.toString() + ", on virtual display stack:" + as.toString()); @@ -2200,7 +2216,7 @@ class ActivityStarter { } if (((launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) == 0) - || mSourceDisplayId != DEFAULT_DISPLAY) { + || mPreferredDisplayId != DEFAULT_DISPLAY) { return null; } // Otherwise handle adjacent launch. @@ -2240,39 +2256,11 @@ class ActivityStarter { } } - 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/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index 3105e37f618f..e839003b957e 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -300,10 +300,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub // TODO: remove this once we figure out properly where and how // PROCESS_EVENT = 1112 - // EVENT SUBTYPE: START = 1 - // KEY_NAME: 1 + // KEY_STATE = 1 + // KEY_PACKAGE_NAME: 1002 // KEY_UID: 2 - StatsLog.writeArray(1112, 1, 1, name, 2, uid); + StatsLog.writeArray(1112, 1, 1, 1002, name, 2, uid); } } @@ -313,10 +313,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub // TODO: remove this once we figure out properly where and how // PROCESS_EVENT = 1112 - // EVENT SUBTYPE: CRASH = 2 - // KEY_NAME: 1 + // KEY_STATE = 1 + // KEY_PACKAGE_NAME: 1002 // KEY_UID: 2 - StatsLog.writeArray(1112, 2, 1, name, 2, uid); + StatsLog.writeArray(1112, 1, 2, 1002, name, 2, uid); } } @@ -550,10 +550,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub synchronized (mStats) { mStats.noteScreenStateLocked(state); // TODO: remove this once we figure out properly where and how - // SCREEN_EVENT = 1003 - // State key: 1 + // SCREEN_EVENT = 2 + // KEY_STATE: 1 // State value: state. We can change this to our own def later. - StatsLog.writeArray(1003, 1, state); + StatsLog.writeArray(2, 1, state); } if (DBG) Slog.d(TAG, "end noteScreenState"); } @@ -564,14 +564,14 @@ public final class BatteryStatsService extends IBatteryStats.Stub mStats.noteScreenBrightnessLocked(brightness); } } - + public void noteUserActivity(int uid, int event) { enforceCallingPermission(); synchronized (mStats) { mStats.noteUserActivityLocked(uid, event); } } - + public void noteWakeUp(String reason, int reasonUid) { enforceCallingPermission(); synchronized (mStats) { diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java index 85961135d84f..e03c530d0c92 100644 --- a/services/core/java/com/android/server/am/KeyguardController.java +++ b/services/core/java/com/android/server/am/KeyguardController.java @@ -26,6 +26,8 @@ import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_WITH_WAL import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; +import static com.android.server.am.proto.KeyguardControllerProto.KEYGUARD_OCCLUDED; +import static com.android.server.am.proto.KeyguardControllerProto.KEYGUARD_SHOWING; import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION; import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE; import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER; @@ -39,6 +41,7 @@ import android.os.IBinder; import android.os.RemoteException; import android.os.Trace; import android.util.Slog; +import android.util.proto.ProtoOutputStream; import com.android.internal.policy.IKeyguardDismissCallback; import com.android.server.wm.WindowManagerService; @@ -362,4 +365,11 @@ class KeyguardController { pw.println(prefix + " mDismissalRequested=" + mDismissalRequested); pw.println(prefix + " mVisibilityTransactionDepth=" + mVisibilityTransactionDepth); } + + void writeToProto(ProtoOutputStream proto, long fieldId) { + final long token = proto.start(fieldId); + proto.write(KEYGUARD_SHOWING, mKeyguardShowing); + proto.write(KEYGUARD_OCCLUDED, mOccluded); + proto.end(token); + } } diff --git a/services/core/java/com/android/server/am/LockTaskController.java b/services/core/java/com/android/server/am/LockTaskController.java index 241e58391144..72b5de88e50f 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_HOME; 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 @@ public class LockTaskController { 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/TaskChangeNotificationController.java b/services/core/java/com/android/server/am/TaskChangeNotificationController.java index 82971696d670..6a986bb8a684 100644 --- a/services/core/java/com/android/server/am/TaskChangeNotificationController.java +++ b/services/core/java/com/android/server/am/TaskChangeNotificationController.java @@ -95,7 +95,7 @@ class TaskChangeNotificationController { }; private final TaskStackConsumer mNotifyActivityPinned = (l, m) -> { - l.onActivityPinned((String) m.obj, m.arg1); + l.onActivityPinned((String) m.obj, m.arg1, m.arg2); }; private final TaskStackConsumer mNotifyActivityUnpinned = (l, m) -> { @@ -278,10 +278,10 @@ class TaskChangeNotificationController { } /** Notifies all listeners when an Activity is pinned. */ - void notifyActivityPinned(String packageName, int taskId) { + void notifyActivityPinned(String packageName, int userId, int taskId) { mHandler.removeMessages(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG); final Message msg = mHandler.obtainMessage(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG, - taskId, 0, packageName); + userId, taskId, packageName); forAllLocalListeners(mNotifyActivityPinned, msg); msg.sendToTarget(); } diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java index 74c4826f583b..f6e20cd2e1b4 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 @@ public class TaskPersister { 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 48da6555e75c..fb8b034ab064 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.HOME_STACK_ID; 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; @@ -65,6 +66,20 @@ import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING; import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING_TO_TOP; import static com.android.server.am.ActivityStackSupervisor.PAUSE_IMMEDIATELY; import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; +import static com.android.server.am.proto.TaskRecordProto.ACTIVITIES; +import static com.android.server.am.proto.TaskRecordProto.BOUNDS; +import static com.android.server.am.proto.TaskRecordProto.CONFIGURATION_CONTAINER; +import static com.android.server.am.proto.TaskRecordProto.FULLSCREEN; +import static com.android.server.am.proto.TaskRecordProto.ID; +import static com.android.server.am.proto.TaskRecordProto.LAST_NON_FULLSCREEN_BOUNDS; +import static com.android.server.am.proto.TaskRecordProto.MIN_HEIGHT; +import static com.android.server.am.proto.TaskRecordProto.MIN_WIDTH; +import static com.android.server.am.proto.TaskRecordProto.ORIG_ACTIVITY; +import static com.android.server.am.proto.TaskRecordProto.REAL_ACTIVITY; +import static com.android.server.am.proto.TaskRecordProto.RESIZE_MODE; +import static com.android.server.am.proto.TaskRecordProto.RETURN_TO_TYPE; +import static com.android.server.am.proto.TaskRecordProto.STACK_ID; +import static com.android.server.am.proto.TaskRecordProto.ACTIVITY_TYPE; import static java.lang.Integer.MAX_VALUE; @@ -94,6 +109,7 @@ import android.provider.Settings; import android.service.voice.IVoiceInteractionSession; import android.util.DisplayMetrics; import android.util.Slog; +import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IVoiceInteractor; @@ -507,8 +523,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi 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 +744,8 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi } // 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 +2095,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi } } - /** - * 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) { @@ -2257,4 +2252,34 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi stringName = sb.toString(); return toString(); } + + public void writeToProto(ProtoOutputStream proto, long fieldId) { + final long token = proto.start(fieldId); + super.writeToProto(proto, CONFIGURATION_CONTAINER); + proto.write(ID, taskId); + for (int i = mActivities.size() - 1; i >= 0; i--) { + ActivityRecord activity = mActivities.get(i); + activity.writeToProto(proto, ACTIVITIES); + } + proto.write(STACK_ID, mStack.mStackId); + if (mLastNonFullscreenBounds != null) { + mLastNonFullscreenBounds.writeToProto(proto, LAST_NON_FULLSCREEN_BOUNDS); + } + if (realActivity != null) { + proto.write(REAL_ACTIVITY, realActivity.flattenToShortString()); + } + if (origActivity != null) { + proto.write(ORIG_ACTIVITY, origActivity.flattenToShortString()); + } + proto.write(ACTIVITY_TYPE, getActivityType()); + proto.write(RETURN_TO_TYPE, mTaskToReturnTo); + proto.write(RESIZE_MODE, mResizeMode); + proto.write(FULLSCREEN, mFullscreen); + if (mBounds != null) { + mBounds.writeToProto(proto, BOUNDS); + } + proto.write(MIN_WIDTH, mMinWidth); + proto.write(MIN_HEIGHT, mMinHeight); + proto.end(token); + } } diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java index e6585ad194ec..fbbdf0051266 100644 --- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java +++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java @@ -20,6 +20,7 @@ import android.net.InterfaceConfiguration; import android.net.ConnectivityManager; import android.net.LinkAddress; import android.net.LinkProperties; +import android.net.NetworkInfo; import android.net.RouteInfo; import android.os.INetworkManagementService; import android.os.RemoteException; @@ -44,12 +45,18 @@ public class Nat464Xlat extends BaseNetworkObserver { // This must match the interface prefix in clatd.c. private static final String CLAT_PREFIX = "v4-"; - // The network types we will start clatd on, + // The network types on which we will start clatd, // allowing clat only on networks for which we can support IPv6-only. private static final int[] NETWORK_TYPES = { - ConnectivityManager.TYPE_MOBILE, - ConnectivityManager.TYPE_WIFI, - ConnectivityManager.TYPE_ETHERNET, + ConnectivityManager.TYPE_MOBILE, + ConnectivityManager.TYPE_WIFI, + ConnectivityManager.TYPE_ETHERNET, + }; + + // The network states in which running clatd is supported. + private static final NetworkInfo.State[] NETWORK_STATES = { + NetworkInfo.State.CONNECTED, + NetworkInfo.State.SUSPENDED, }; private final INetworkManagementService mNMService; @@ -81,11 +88,8 @@ public class Nat464Xlat extends BaseNetworkObserver { */ public static boolean requiresClat(NetworkAgentInfo nai) { // TODO: migrate to NetworkCapabilities.TRANSPORT_*. - final int netType = nai.networkInfo.getType(); final boolean supported = ArrayUtils.contains(NETWORK_TYPES, nai.networkInfo.getType()); - // TODO: this should also consider if the network is in SUSPENDED state to avoid stopping - // clatd in SUSPENDED state. - final boolean connected = nai.networkInfo.isConnected(); + final boolean connected = ArrayUtils.contains(NETWORK_STATES, nai.networkInfo.getState()); // We only run clat on networks that don't have a native IPv4 address. final boolean hasIPv4Address = (nai.linkProperties != null) && nai.linkProperties.hasIPv4Address(); diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java index 5eafe5f9f64f..057704a56c4c 100644 --- a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java +++ b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java @@ -52,6 +52,7 @@ import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -73,6 +74,8 @@ public class OffloadController { private static final String ANYIP = "0.0.0.0"; private static final ForwardedStats EMPTY_STATS = new ForwardedStats(); + private static enum UpdateType { IF_NEEDED, FORCE }; + private final Handler mHandler; private final OffloadHardwareInterface mHwInterface; private final ContentResolver mContentResolver; @@ -185,8 +188,8 @@ public class OffloadController { updateStatsForAllUpstreams(); forceTetherStatsPoll(); // [2] (Re)Push all state. - // TODO: computeAndPushLocalPrefixes() - // TODO: push all downstream state. + computeAndPushLocalPrefixes(UpdateType.FORCE); + pushAllDownstreamState(); pushUpstreamParameters(null); } @@ -319,7 +322,7 @@ public class OffloadController { } private boolean maybeUpdateDataLimit(String iface) { - // setDataLimit may only be called while offload is occuring on this upstream. + // setDataLimit may only be called while offload is occurring on this upstream. if (!started() || !TextUtils.equals(iface, currentUpstreamInterface())) { return true; } @@ -368,15 +371,15 @@ public class OffloadController { // upstream parameters fails (probably just wait for a subsequent // onOffloadEvent() callback to tell us offload is available again and // then reapply all state). - computeAndPushLocalPrefixes(); + computeAndPushLocalPrefixes(UpdateType.IF_NEEDED); pushUpstreamParameters(prevUpstream); } public void setLocalPrefixes(Set<IpPrefix> localPrefixes) { - if (!started()) return; - mExemptPrefixes = localPrefixes; - computeAndPushLocalPrefixes(); + + if (!started()) return; + computeAndPushLocalPrefixes(UpdateType.IF_NEEDED); } public void notifyDownstreamLinkProperties(LinkProperties lp) { @@ -385,27 +388,38 @@ public class OffloadController { if (Objects.equals(oldLp, lp)) return; if (!started()) return; + pushDownstreamState(oldLp, lp); + } - final List<RouteInfo> oldRoutes = (oldLp != null) ? oldLp.getRoutes() : new ArrayList<>(); - final List<RouteInfo> newRoutes = lp.getRoutes(); + private void pushDownstreamState(LinkProperties oldLp, LinkProperties newLp) { + final String ifname = newLp.getInterfaceName(); + final List<RouteInfo> oldRoutes = + (oldLp != null) ? oldLp.getRoutes() : Collections.EMPTY_LIST; + final List<RouteInfo> newRoutes = newLp.getRoutes(); // For each old route, if not in new routes: remove. - for (RouteInfo oldRoute : oldRoutes) { - if (shouldIgnoreDownstreamRoute(oldRoute)) continue; - if (!newRoutes.contains(oldRoute)) { - mHwInterface.removeDownstreamPrefix(ifname, oldRoute.getDestination().toString()); + for (RouteInfo ri : oldRoutes) { + if (shouldIgnoreDownstreamRoute(ri)) continue; + if (!newRoutes.contains(ri)) { + mHwInterface.removeDownstreamPrefix(ifname, ri.getDestination().toString()); } } // For each new route, if not in old routes: add. - for (RouteInfo newRoute : newRoutes) { - if (shouldIgnoreDownstreamRoute(newRoute)) continue; - if (!oldRoutes.contains(newRoute)) { - mHwInterface.addDownstreamPrefix(ifname, newRoute.getDestination().toString()); + for (RouteInfo ri : newRoutes) { + if (shouldIgnoreDownstreamRoute(ri)) continue; + if (!oldRoutes.contains(ri)) { + mHwInterface.addDownstreamPrefix(ifname, ri.getDestination().toString()); } } } + private void pushAllDownstreamState() { + for (LinkProperties lp : mDownstreams.values()) { + pushDownstreamState(null, lp); + } + } + public void removeDownstreamInterface(String ifname) { final LinkProperties lp = mDownstreams.remove(ifname); if (lp == null) return; @@ -484,10 +498,11 @@ public class OffloadController { return success; } - private boolean computeAndPushLocalPrefixes() { + private boolean computeAndPushLocalPrefixes(UpdateType how) { + final boolean force = (how == UpdateType.FORCE); final Set<String> localPrefixStrs = computeLocalPrefixStrings( mExemptPrefixes, mUpstreamLinkProperties); - if (mLastLocalPrefixStrs.equals(localPrefixStrs)) return true; + if (!force && mLastLocalPrefixStrs.equals(localPrefixStrs)) return true; mLastLocalPrefixStrs = localPrefixStrs; return mHwInterface.setLocalPrefixes(new ArrayList<>(localPrefixStrs)); diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index 2f3b55960c13..205e8283cc55 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -143,6 +143,7 @@ public class SyncManager { private static final boolean DEBUG_ACCOUNT_ACCESS = false; + // Only do the check on a debuggable build. private static final boolean ENABLE_SUSPICIOUS_CHECK = Build.IS_DEBUGGABLE; /** Delay a sync due to local changes this long. In milliseconds */ @@ -537,9 +538,11 @@ public class SyncManager { * @return whether the device most likely has some periodic syncs. */ private boolean likelyHasPeriodicSyncs() { - // STOPSHIP Remove the google specific string. try { - return AccountManager.get(mContext).getAccountsByType("com.google").length > 0; + // Each sync adapter has a daily periodic sync by default, but sync adapters can remove + // them by themselves. So here, we use an arbitrary threshold. If there are more than + // this many sync endpoints, surely one of them should have a periodic sync... + return mSyncStorageEngine.getAuthorityCount() >= 6; } catch (Throwable th) { // Just in case. } @@ -3775,48 +3778,10 @@ public class SyncManager { } if (op.isPeriodic) { mLogger.log("Removing periodic sync ", op, " for ", why); - - if (ENABLE_SUSPICIOUS_CHECK && isSuspiciousPeriodicSyncRemoval(op)) { - wtfWithLog("Suspicious removal of " + op + " for " + why); - } } getJobScheduler().cancel(op.jobId); } - private boolean isSuspiciousPeriodicSyncRemoval(SyncOperation op) { - // STOPSHIP Remove the google specific string. - if (!op.isPeriodic){ - return false; - } - boolean found = false; - for (UserInfo user : UserManager.get(mContext).getUsers(/*excludeDying=*/ true)) { - if (op.target.userId == user.id) { - found = true; - break; - } - } - if (!found) { - return false; // User is being removed, okay. - } - switch (op.target.provider) { - case "gmail-ls": - case "com.android.contacts.metadata": - break; - default: - return false; - } - final Account account = op.target.account; - final Account[] accounts = AccountManager.get(mContext) - .getAccountsByTypeAsUser(account.type, UserHandle.of(op.target.userId)); - for (Account a : accounts) { - if (a.equals(account)) { - return true; // Account still exists. Suspicious! - } - } - // Account no longer exists. Makes sense... - return false; - } - private void wtfWithLog(String message) { Slog.wtf(TAG, message); mLogger.log("WTF: ", message); diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java index 7b277c06328e..3591871f5386 100644 --- a/services/core/java/com/android/server/content/SyncStorageEngine.java +++ b/services/core/java/com/android/server/content/SyncStorageEngine.java @@ -911,6 +911,12 @@ public class SyncStorageEngine extends Handler { } } + public int getAuthorityCount() { + synchronized (mAuthorities) { + return mAuthorities.size(); + } + } + public AuthorityInfo getAuthority(int authorityId) { synchronized (mAuthorities) { return mAuthorities.get(authorityId); diff --git a/services/core/java/com/android/server/display/NightDisplayService.java b/services/core/java/com/android/server/display/NightDisplayService.java index aafc6317bfae..9cf136720881 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.TwilightListener; 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 @@ public final class NightDisplayService extends SystemService } @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 @@ public final class NightDisplayService extends SystemService } @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 @@ public final class NightDisplayService extends SystemService 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 @@ public final class NightDisplayService extends SystemService 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 @@ public final class NightDisplayService extends SystemService } 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 @@ public final class NightDisplayService extends SystemService 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 @@ public final class NightDisplayService extends SystemService @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 @@ public final class NightDisplayService extends SystemService } 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/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 11043bd16648..14d9afb14cf9 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -2366,6 +2366,13 @@ public class LockSettingsService extends ILockSettings.Stub { Slog.w(TAG, "Invalid escrow token supplied"); return false; } + if (result.gkResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) { + // Most likely, an untrusted credential reset happened in the past which + // changed the synthetic password + Slog.e(TAG, "Obsolete token: synthetic password derived but it fails GK " + + "verification."); + return false; + } // Update PASSWORD_TYPE_KEY since it's needed by notifyActivePasswordMetricsAvailable() // called by setLockCredentialWithAuthTokenLocked(). // TODO: refactor usage of PASSWORD_TYPE_KEY b/65239740 diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 89e10503fcf3..0b11479a162a 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -462,18 +462,25 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { mHandler.post(new Runnable() { @Override public void run() { - if (useSuggested) { - if (AudioSystem.isStreamActive(stream, 0)) { - mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(stream, direction, - flags, packageName, uid); + try { + if (useSuggested) { + if (AudioSystem.isStreamActive(stream, 0)) { + mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(stream, + direction, flags, packageName, uid); + } else { + mAudioManagerInternal.adjustSuggestedStreamVolumeForUid( + AudioManager.USE_DEFAULT_STREAM_TYPE, direction, + flags | previousFlagPlaySound, packageName, uid); + } } else { - mAudioManagerInternal.adjustSuggestedStreamVolumeForUid( - AudioManager.USE_DEFAULT_STREAM_TYPE, direction, - flags | previousFlagPlaySound, packageName, uid); + mAudioManagerInternal.adjustStreamVolumeForUid(stream, direction, flags, + packageName, uid); } - } else { - mAudioManagerInternal.adjustStreamVolumeForUid(stream, direction, flags, - packageName, uid); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Cannot adjust volume: direction=" + direction + ", stream=" + + stream + ", flags=" + flags + ", packageName=" + packageName + + ", uid=" + uid + ", useSuggested=" + useSuggested + + ", previousFlagPlaySound=" + previousFlagPlaySound, e); } } }); diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java index b77ed913cd12..b9a2d184aade 100644 --- a/services/core/java/com/android/server/media/MediaSessionService.java +++ b/services/core/java/com/android/server/media/MediaSessionService.java @@ -1363,6 +1363,10 @@ public class MediaSessionService extends SystemService implements Monitor { flags, packageName, TAG); } catch (RemoteException e) { Log.e(TAG, "Error adjusting default volume.", e); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Cannot adjust volume: direction=" + direction + + ", suggestedStream=" + suggestedStream + ", flags=" + flags, + e); } } }); diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java index 3444ef3ec2fa..c0fbfbb20b95 100644 --- a/services/core/java/com/android/server/notification/ConditionProviders.java +++ b/services/core/java/com/android/server/notification/ConditionProviders.java @@ -186,6 +186,11 @@ public class ConditionProviders extends ManagedServices { super.onPackagesChanged(removingPackage, pkgList, uid); } + @Override + protected boolean isValidEntry(String packageOrComponent, int userId) { + return true; + } + public ManagedServiceInfo checkServiceToken(IConditionProvider provider) { synchronized(mMutex) { return checkServiceTokenLocked(provider); diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index add4184fc129..b7b91a76ebf3 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -294,6 +294,7 @@ abstract public class ManagedServices { } if (type == XmlPullParser.START_TAG) { if (TAG_MANAGED_SERVICES.equals(tag)) { + Slog.i(TAG, "Read " + mConfig.caption + " permissions from xml"); final String approved = XmlUtils.readStringAttribute(parser, ATT_APPROVED_LIST); final int userId = XmlUtils.readIntAttribute(parser, ATT_USER_ID, 0); final boolean isPrimary = @@ -353,6 +354,8 @@ abstract public class ManagedServices { protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId, boolean isPrimary, boolean enabled) { + Slog.i(TAG, + (enabled ? " Allowing " : "Disallowing ") + mConfig.caption + " " + pkgOrComponent); ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.get(userId); if (allowedByType == null) { allowedByType = new ArrayMap<>(); @@ -460,6 +463,7 @@ abstract public class ManagedServices { } public void onUserRemoved(int user) { + Slog.i(TAG, "Removing approved services for removed user " + user); mApproved.remove(user); rebindServices(true); } @@ -543,10 +547,8 @@ abstract public class ManagedServices { } // State changed - if (DEBUG) { - Slog.d(TAG, ((enabled) ? "Enabling " : "Disabling ") + "component " + - component.flattenToShortString()); - } + Slog.d(TAG, ((enabled) ? "Enabling " : "Disabling ") + "component " + + component.flattenToShortString()); synchronized (mMutex) { final int[] userIds = mUserProfiles.getCurrentProfileIds(); @@ -628,12 +630,10 @@ abstract public class ManagedServices { int P = approved.size(); for (int k = P - 1; k >= 0; k--) { final String approvedPackageOrComponent = approved.valueAt(k); - if (!hasMatchingServices(approvedPackageOrComponent, userId)){ + if (!isValidEntry(approvedPackageOrComponent, userId)){ approved.removeAt(k); - if (DEBUG) { - Slog.v(TAG, "Removing " + approvedPackageOrComponent - + " from approved list; no matching services found"); - } + Slog.v(TAG, "Removing " + approvedPackageOrComponent + + " from approved list; no matching services found"); } else { if (DEBUG) { Slog.v(TAG, "Keeping " + approvedPackageOrComponent @@ -678,6 +678,10 @@ abstract public class ManagedServices { } } + protected boolean isValidEntry(String packageOrComponent, int userId) { + return hasMatchingServices(packageOrComponent, userId); + } + private boolean hasMatchingServices(String packageOrComponent, int userId) { if (!TextUtils.isEmpty(packageOrComponent)) { final String packageName = getPackageName(packageOrComponent); @@ -830,8 +834,7 @@ abstract public class ManagedServices { if (name.equals(info.component) && info.userid == userid) { // cut old connections - if (DEBUG) Slog.v(TAG, " disconnecting old " + getCaption() + ": " - + info.service); + Slog.v(TAG, " disconnecting old " + getCaption() + ": " + info.service); removeServiceLocked(i); if (info.connection != null) { mContext.unbindService(info.connection); @@ -859,7 +862,7 @@ abstract public class ManagedServices { appInfo != null ? appInfo.targetSdkVersion : Build.VERSION_CODES.BASE; try { - if (DEBUG) Slog.v(TAG, "binding: " + intent); + Slog.v(TAG, "binding: " + intent); ServiceConnection serviceConnection = new ServiceConnection() { IInterface mService; @@ -917,8 +920,7 @@ abstract public class ManagedServices { final int N = mServices.size(); for (int i = N - 1; i >= 0; i--) { final ManagedServiceInfo info = mServices.get(i); - if (name.equals(info.component) - && info.userid == userid) { + if (name.equals(info.component) && info.userid == userid) { removeServiceLocked(i); if (info.connection != null) { try { @@ -945,9 +947,8 @@ abstract public class ManagedServices { final int N = mServices.size(); for (int i = N - 1; i >= 0; i--) { final ManagedServiceInfo info = mServices.get(i); - if (info.service.asBinder() == service.asBinder() - && info.userid == userid) { - if (DEBUG) Slog.d(TAG, "Removing active service " + info.component); + if (info.service.asBinder() == service.asBinder() && info.userid == userid) { + Slog.d(TAG, "Removing active service " + info.component); serviceInfo = removeServiceLocked(i); } } diff --git a/services/core/java/com/android/server/notification/ScheduleCalendar.java b/services/core/java/com/android/server/notification/ScheduleCalendar.java index 9e8b2e34520b..40230bd2ba82 100644 --- a/services/core/java/com/android/server/notification/ScheduleCalendar.java +++ b/services/core/java/com/android/server/notification/ScheduleCalendar.java @@ -42,7 +42,8 @@ public class ScheduleCalendar { public void maybeSetNextAlarm(long now, long nextAlarm) { if (mSchedule != null) { - if (mSchedule.exitAtAlarm && now > mSchedule.nextAlarm) { + if (mSchedule.exitAtAlarm + && (now > mSchedule.nextAlarm || nextAlarm < mSchedule.nextAlarm)) { mSchedule.nextAlarm = nextAlarm; } } diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java index 415c9a9cba10..6d8cac0c661b 100644 --- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java +++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java @@ -342,8 +342,7 @@ public class BackgroundDexOptService extends JobService { DexoptOptions.DEXOPT_BOOT_COMPLETE | (downgrade ? DexoptOptions.DEXOPT_DOWNGRADE : 0); if (is_for_primary_dex) { - int result = pm.performDexOptWithStatus(new DexoptOptions(pkg, - PackageManagerService.REASON_BACKGROUND_DEXOPT, + int result = pm.performDexOptWithStatus(new DexoptOptions(pkg, reason, dexoptFlags)); success = result != PackageDexOptimizer.DEX_OPT_FAILED; if (result == PackageDexOptimizer.DEX_OPT_PERFORMED) { @@ -351,8 +350,7 @@ public class BackgroundDexOptService extends JobService { } } else { success = pm.performDexOpt(new DexoptOptions(pkg, - PackageManagerService.REASON_BACKGROUND_DEXOPT, - dexoptFlags | DexoptOptions.DEXOPT_ONLY_SECONDARY_DEX)); + reason, dexoptFlags | DexoptOptions.DEXOPT_ONLY_SECONDARY_DEX)); } if (success) { // Dexopt succeeded, remove package from the list of failing ones. diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index 0f580d818f91..4fafe34b3063 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 @@ public class PackageDexOptimizer { 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 @@ public class PackageDexOptimizer { } 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 ff52e0ebbbb9..050d9f00071a 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 class PackageManagerService extends IPackageManager.Stub 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 @@ public class PackageManagerService extends IPackageManager.Stub 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++; @@ -25245,6 +25233,37 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); } return results; } + + // NB: this differentiates between preloads and sideloads + @Override + public String getInstallerForPackage(String packageName) throws RemoteException { + final String installerName = getInstallerPackageName(packageName); + if (!TextUtils.isEmpty(installerName)) { + return installerName; + } + // differentiate between preload and sideload + int callingUser = UserHandle.getUserId(Binder.getCallingUid()); + ApplicationInfo appInfo = getApplicationInfo(packageName, + /*flags*/ 0, + /*userId*/ callingUser); + if (appInfo != null && (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { + return "preload"; + } + return ""; + } + + @Override + public int getVersionCodeForPackage(String packageName) throws RemoteException { + try { + int callingUser = UserHandle.getUserId(Binder.getCallingUid()); + PackageInfo pInfo = getPackageInfo(packageName, 0, callingUser); + if (pInfo != null) { + return pInfo.versionCode; + } + } catch (Exception e) { + } + return 0; + } } private class PackageManagerInternalImpl extends PackageManagerInternal { diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java index 1a97a72cf2b3..19b0d9bc4b90 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 @@ import dalvik.system.DexFile; 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 @@ public class PackageManagerServiceCompilerMapping { !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/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 12ca89a93d02..338ad2a951c9 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -120,7 +120,7 @@ public final class PowerManagerService extends SystemService implements Watchdog.Monitor { private static final String TAG = "PowerManagerService"; - private static final boolean DEBUG = true; + private static final boolean DEBUG = false; private static final boolean DEBUG_SPEW = DEBUG && true; // Message: Sent when a user activity timeout occurs to update the power state. 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 000000000000..11ae2129c339 --- /dev/null +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -0,0 +1,259 @@ +/* + * 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.IBinder; +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.internal.annotations.GuardedBy; +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; + @GuardedBy("sStatsdLock") + private static IStatsManager sStatsd; + private static final Object sStatsdLock = new Object(); + + private final PendingIntent mAnomalyAlarmIntent; + private final PendingIntent mPollingAlarmIntent; + + 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); + } + + public final static class AnomalyAlarmReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + Slog.i(TAG, "StatsCompanionService believes an anomaly has occurred."); + synchronized (sStatsdLock) { + if (sStatsd == null) { + Slog.w(TAG, "Could not access statsd to inform it of anomaly alarm firing"); + return; + } + try { + // Two-way call to statsd to retain AlarmManager wakelock + sStatsd.informAnomalyAlarmFired(); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to inform statsd 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."); + synchronized (sStatsdLock) { + if (sStatsd == null) { + Slog.w(TAG, "Could not access statsd to inform it of polling alarm firing"); + return; + } + try { + // Two-way call to statsd to retain AlarmManager wakelock + sStatsd.informPollAlarmFired(); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to inform statsd of polling alarm firing", e); + } + } + // AlarmManager releases its own wakelock here. + } + }; + + @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); + } + } + + @Override + public void statsdReady() { + enforceCallingPermission(); + if (DEBUG) Slog.d(TAG, "learned that statsdReady"); + sayHiToStatsd(); // tell statsd that we're ready too and link to it + } + + private void enforceCallingPermission() { + if (Binder.getCallingPid() == Process.myPid()) { + return; + } + mContext.enforceCallingPermission(android.Manifest.permission.STATSCOMPANION, null); + } + + // Lifecycle and related code + + /** Fetches the statsd IBinder service */ + private static IStatsManager fetchStatsdService() { + return IStatsManager.Stub.asInterface(ServiceManager.getService("stats")); + } + + 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 + public void onBootPhase(int phase) { + super.onBootPhase(phase); + if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { + mStatsCompanionService.systemReady(); + } + } + } + + /** Now that the android system is ready, StatsCompanion is ready too, so inform statsd. */ + private void systemReady() { + if (DEBUG) Slog.d(TAG, "Learned that systemReady"); + sayHiToStatsd(); + } + + /** Tells statsd that statscompanion is ready. If the binder call returns, link to statsd. */ + private void sayHiToStatsd() { + synchronized (sStatsdLock) { + if (sStatsd != null) { + Slog.e(TAG, "Trying to fetch statsd, but it was already fetched", + new IllegalStateException("sStatsd is not null when being fetched")); + return; + } + sStatsd = fetchStatsdService(); + if (sStatsd == null) { + Slog.w(TAG, "Could not access statsd"); + return; + } + if (DEBUG) Slog.d(TAG, "Saying hi to statsd"); + try { + sStatsd.statsCompanionReady(); + // If the statsCompanionReady two-way binder call returns, link to statsd. + try { + sStatsd.asBinder().linkToDeath(new StatsdDeathRecipient(), 0); + } catch (RemoteException e) { + Slog.e(TAG, "linkToDeath(StatsdDeathRecipient) failed", e); + forgetEverything(); + } + } catch (RemoteException e) { + Slog.e(TAG, "Failed to inform statsd that statscompanion is ready", e); + forgetEverything(); + } + } + } + + private class StatsdDeathRecipient implements IBinder.DeathRecipient { + @Override + public void binderDied() { + Slog.i(TAG, "Statsd is dead - erase all my knowledge."); + forgetEverything(); + } + } + + private void forgetEverything() { + synchronized (sStatsdLock) { + sStatsd = null; + cancelAnomalyAlarm(); + cancelPollingAlarms(); + } + } + +} diff --git a/services/core/java/com/android/server/twilight/TwilightState.java b/services/core/java/com/android/server/twilight/TwilightState.java index 30a8cccb6ad5..71304a7a4701 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 @@ package com.android.server.twilight; 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 @@ public final class TwilightState { } /** - * 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 @@ public final class TwilightState { } /** - * 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/utils/PriorityDump.java b/services/core/java/com/android/server/utils/PriorityDump.java index c05cc3ff8827..054f1564730e 100644 --- a/services/core/java/com/android/server/utils/PriorityDump.java +++ b/services/core/java/com/android/server/utils/PriorityDump.java @@ -59,10 +59,10 @@ public class SpringfieldNuclearPowerPlant extends Binder { Donuts in the box: 1 Nuclear reactor status: DANGER - MELTDOWN IMMINENT - $ adb shell dumpsys snpp --dump_priority CRITICAL + $ adb shell dumpsys snpp --dump-priority CRITICAL Donuts in the box: 1 - $ adb shell dumpsys snpp --dump_priority NORMAL + $ adb shell dumpsys snpp --dump-priority NORMAL Nuclear reactor status: DANGER - MELTDOWN IMMINENT * </code></pre> @@ -84,7 +84,7 @@ public class SpringfieldNuclearPowerPlant extends Binder { */ public final class PriorityDump { - public static final String PRIORITY_ARG = "--dump_priority"; + public static final String PRIORITY_ARG = "--dump-priority"; private PriorityDump() { throw new UnsupportedOperationException(); @@ -92,12 +92,12 @@ public final class PriorityDump { /** * Parses {@code} and call the proper {@link PriorityDumper} method when the first argument is - * {@code --dump_priority}, stripping the priority and its type. + * {@code --dump-priority}, stripping the priority and its type. * <p> - * For example, if called as {@code --dump_priority HIGH arg1 arg2 arg3}, it will call + * For example, if called as {@code --dump-priority HIGH arg1 arg2 arg3}, it will call * <code>dumper.dumpHigh(fd, pw, {"arg1", "arg2", "arg3"}) </code> * <p> - * If the {@code --dump_priority} is not set, it calls + * If the {@code --dump-priority} is not set, it calls * {@link PriorityDumper#dump(FileDescriptor, PrintWriter, String[])} passing the whole * {@code args} instead. */ @@ -124,7 +124,7 @@ public final class PriorityDump { } /** - * Gets an array without the {@code --dump_priority PRIORITY} prefix. + * Gets an array without the {@code --dump-priority PRIORITY} prefix. */ private static String[] getStrippedArgs(String[] args) { final String[] stripped = new String[args.length - 2]; diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java index bf769ed46bc1..1e334b83d8b0 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 @@ public class SystemImpl implements SystemInterface { // 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/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 6f796481cc08..6a5f6fafb275 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -247,6 +247,7 @@ import com.android.server.Watchdog; import com.android.server.input.InputManagerService; import com.android.server.power.BatterySaverPolicy.ServiceType; import com.android.server.power.ShutdownThread; +import com.android.server.utils.PriorityDump; import java.io.BufferedWriter; import java.io.DataInputStream; @@ -391,6 +392,18 @@ public class WindowManagerService extends IWindowManager.Stub }; final WindowSurfacePlacer mWindowPlacerLocked; + private final PriorityDump.PriorityDumper mPriorityDumper = new PriorityDump.PriorityDumper() { + @Override + public void dumpCritical(FileDescriptor fd, PrintWriter pw, String[] args) { + doDump(fd, pw, new String[] {"-a"}); + } + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + doDump(fd, pw, args); + } + }; + /** * Current user when multi-user is enabled. Don't show windows of * non-current user. Also see mCurrentProfileIds. @@ -6794,8 +6807,11 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; + PriorityDump.dump(mPriorityDumper, fd, pw, args); + } + private void doDump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; boolean dumpAll = false; boolean useProto = false; diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 2815da6e7a10..948c028d46ca 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.restrictions.RestrictionsManagerService; 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 @@ public final class SystemServer { 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 58a4456ff4d7..3a92d638fb02 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.support.test.runner.AndroidJUnit4; 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 org.mockito.Mockito; 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 @@ public class NightDisplayServiceTest { */ 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 @@ public class NightDisplayServiceTest { 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 @@ public class NightDisplayServiceTest { 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 47a3a7242a44..526f81572b07 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_BOTTOM; 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 @@ public class ActivityRecordTests extends ActivityTestsBase { 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 @@ public class ActivityRecordTests extends ActivityTestsBase { 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 661dd4fc828c..cd1843b37ae2 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 class ActivityStackSupervisorTests extends ActivityTestsBase { 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 b5345444f8cc..0cf1df84c073 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 @@ public class ActivityTestsBase { */ 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 @@ public class ActivityTestsBase { 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/utils/PriorityDumpTest.java b/services/tests/servicestests/src/com/android/server/utils/PriorityDumpTest.java index d378b7c56acb..8a312f64a846 100644 --- a/services/tests/servicestests/src/com/android/server/utils/PriorityDumpTest.java +++ b/services/tests/servicestests/src/com/android/server/utils/PriorityDumpTest.java @@ -80,7 +80,7 @@ public class PriorityDumpTest { @Test public void testMissingPriority() { final String[] args = { - "--dump_priority" + "--dump-priority" }; dump(mDumper, mFd, mPw, args); verify(mDumper).dump(same(mFd), same(mPw), same(args)); @@ -89,7 +89,7 @@ public class PriorityDumpTest { @Test public void testInvalidPriorityNoExtraArgs() { final String[] args = { - "--dump_priority", "SUPER_HIGH" + "--dump-priority", "SUPER_HIGH" }; dump(mDumper, mFd, mPw, args); verify(mDumper).dump(same(mFd), same(mPw), same(args)); @@ -98,7 +98,7 @@ public class PriorityDumpTest { @Test public void testInvalidPriorityExtraArgs() { final String[] args = { - "--dump_priority", "SUPER_HIGH", "--high", "--five" + "--dump-priority", "SUPER_HIGH", "--high", "--five" }; dump(mDumper, mFd, mPw, args); verify(mDumper).dump(same(mFd), same(mPw), same(args)); @@ -129,7 +129,7 @@ public class PriorityDumpTest { @Test public void testCriticalNoExtraArgs() { dump(mDumper, mFd, mPw, new String[] { - "--dump_priority", "CRITICAL" + "--dump-priority", "CRITICAL" }); verify(mDumper).dumpCritical(same(mFd), same(mPw), eq(EMPTY_ARGS)); } @@ -137,7 +137,7 @@ public class PriorityDumpTest { @Test public void testCriticalExtraArgs() { dump(mDumper, mFd, mPw, new String[] { - "--dump_priority", "CRITICAL", "--high", "--five" + "--dump-priority", "CRITICAL", "--high", "--five" }); verify(mDumper).dumpCritical(same(mFd), same(mPw), eq(new String[] { "--high", "--five" @@ -147,7 +147,7 @@ public class PriorityDumpTest { @Test public void testHighNoExtraArgs() { dump(mDumper, mFd, mPw, new String[] { - "--dump_priority", "HIGH" + "--dump-priority", "HIGH" }); verify(mDumper).dumpHigh(same(mFd), same(mPw), eq(EMPTY_ARGS)); } @@ -155,7 +155,7 @@ public class PriorityDumpTest { @Test public void testHighExtraArgs() { dump(mDumper, mFd, mPw, new String[] { - "--dump_priority", "HIGH", "--high", "--five" + "--dump-priority", "HIGH", "--high", "--five" }); verify(mDumper).dumpHigh(same(mFd), same(mPw), eq(new String[] { "--high", "--five" @@ -165,7 +165,7 @@ public class PriorityDumpTest { @Test public void testNormalNoExtraArgs() { dump(mDumper, mFd, mPw, new String[] { - "--dump_priority", "NORMAL" + "--dump-priority", "NORMAL" }); verify(mDumper).dumpNormal(same(mFd), same(mPw), eq(EMPTY_ARGS)); } @@ -173,7 +173,7 @@ public class PriorityDumpTest { @Test public void testNormalExtraArgs() { dump(mDumper, mFd, mPw, new String[] { - "--dump_priority", "NORMAL", "--high", "--five" + "--dump-priority", "NORMAL", "--high", "--five" }); verify(mDumper).dumpNormal(same(mFd), same(mPw), eq(new String[] { "--high", "--five" diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java index 3788cf331600..b040a6324dbb 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_HIDDEN_SESSION; 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 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } 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 629173dfa23b..7a53ef63e2a8 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 @@ public class SmsMessage extends SmsMessageBase { // 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. diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java index e3f46a40e2b1..de28de6b3185 100644 --- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java +++ b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java @@ -85,6 +85,32 @@ public class Nat464XlatTest { } @Test + public void testRequiresClat() throws Exception { + final int[] supportedTypes = { + ConnectivityManager.TYPE_MOBILE, + ConnectivityManager.TYPE_WIFI, + ConnectivityManager.TYPE_ETHERNET, + }; + + // NetworkInfo doesn't allow setting the State directly, but rather + // requires setting DetailedState in order set State as a side-effect. + final NetworkInfo.DetailedState[] supportedDetailedStates = { + NetworkInfo.DetailedState.CONNECTED, + NetworkInfo.DetailedState.SUSPENDED, + }; + + for (int type : supportedTypes) { + mNai.networkInfo.setType(type); + for (NetworkInfo.DetailedState state : supportedDetailedStates) { + mNai.networkInfo.setDetailedState(state, "reason", "extraInfo"); + assertTrue( + String.format("requiresClat expected for type=%d state=%s", type, state), + Nat464Xlat.requiresClat(mNai)); + } + } + } + + @Test public void testNormalStartAndStop() throws Exception { Nat464Xlat nat = makeNat464Xlat(); ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class); diff --git a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java index 7a2ff8995458..b98f63b6a5a5 100644 --- a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java +++ b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java @@ -671,6 +671,35 @@ public class OffloadControllerTest { offload.setUpstreamLinkProperties(upstreamLp); } + // Pretend that some local prefixes and downstreams have been added + // (and removed, for good measure). + final Set<IpPrefix> minimumLocalPrefixes = new HashSet<>(); + for (String s : new String[]{ + "127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64"}) { + minimumLocalPrefixes.add(new IpPrefix(s)); + } + offload.setLocalPrefixes(minimumLocalPrefixes); + + final LinkProperties usbLinkProperties = new LinkProperties(); + usbLinkProperties.setInterfaceName(RNDIS0); + usbLinkProperties.addLinkAddress(new LinkAddress("192.168.42.1/24")); + usbLinkProperties.addRoute(new RouteInfo(new IpPrefix(USB_PREFIX))); + offload.notifyDownstreamLinkProperties(usbLinkProperties); + + final LinkProperties wifiLinkProperties = new LinkProperties(); + wifiLinkProperties.setInterfaceName(WLAN0); + wifiLinkProperties.addLinkAddress(new LinkAddress("192.168.43.1/24")); + wifiLinkProperties.addRoute(new RouteInfo(new IpPrefix(WIFI_PREFIX))); + wifiLinkProperties.addRoute(new RouteInfo(new IpPrefix(IPV6_LINKLOCAL))); + // Use a benchmark prefix (RFC 5180 + erratum), since the documentation + // prefix is included in the excluded prefix list. + wifiLinkProperties.addLinkAddress(new LinkAddress("2001:2::1/64")); + wifiLinkProperties.addLinkAddress(new LinkAddress("2001:2::2/64")); + wifiLinkProperties.addRoute(new RouteInfo(new IpPrefix("2001:2::/64"))); + offload.notifyDownstreamLinkProperties(wifiLinkProperties); + + offload.removeDownstreamInterface(RNDIS0); + // Clear invocation history, especially the getForwardedStats() calls // that happen with setUpstreamParameters(). clearInvocations(mHardware); @@ -685,6 +714,17 @@ public class OffloadControllerTest { verifyNoMoreInteractions(mNMService); // TODO: verify local prefixes and downstreams are also pushed to the HAL. + verify(mHardware, times(1)).setLocalPrefixes(mStringArrayCaptor.capture()); + ArrayList<String> localPrefixes = mStringArrayCaptor.getValue(); + assertEquals(4, localPrefixes.size()); + assertArrayListContains(localPrefixes, + // TODO: The logic to find and exclude downstream IP prefixes + // is currently in Tethering's OffloadWrapper but must be moved + // into OffloadController proper. After this, also check for: + // "192.168.43.1/32", "2001:2::1/128", "2001:2::2/128" + "127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64"); + verify(mHardware, times(1)).addDownstreamPrefix(WLAN0, "192.168.43.0/24"); + verify(mHardware, times(1)).addDownstreamPrefix(WLAN0, "2001:2::/64"); verify(mHardware, times(1)).setUpstreamParameters(eq(RMNET0), any(), any(), any()); verify(mHardware, times(1)).setDataLimit(eq(RMNET0), anyLong()); verifyNoMoreInteractions(mHardware); @@ -692,7 +732,7 @@ public class OffloadControllerTest { private static void assertArrayListContains(ArrayList<String> list, String... elems) { for (String element : elems) { - assertTrue(list.contains(element)); + assertTrue(element + " not in list", list.contains(element)); } } } |