diff options
41 files changed, 2433 insertions, 1250 deletions
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk index b9ee7ff201d5..3f120166d974 100644 --- a/cmds/statsd/Android.mk +++ b/cmds/statsd/Android.mk @@ -54,6 +54,7 @@ LOCAL_SRC_FILES := \ src/statsd_config.proto \ src/stats_constants.proto \ src/DropboxReader.cpp \ + src/matchers/LogEntryMatcherManager.cpp \ LOCAL_CFLAGS += \ @@ -107,6 +108,9 @@ LOCAL_MODULE := statsd_test LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_MODULE_TAGS := tests +LOCAL_C_INCLUDES += $(LOCAL_PATH)/src \ + STATSD_PROTO_INCLUDES + LOCAL_CFLAGS += \ -Wall \ -Werror \ @@ -115,21 +119,24 @@ LOCAL_CFLAGS += \ -Wno-unused-function \ -Wno-unused-parameter -LOCAL_C_INCLUDES += $(LOCAL_PATH)/src \ - STATSD_PROTO_INCLUDES - LOCAL_SRC_FILES := \ + src/stats_log.proto \ + src/statsd_config.proto \ + src/stats_constants.proto \ ../../core/java/android/os/IStatsCompanionService.aidl \ ../../core/java/android/os/IStatsManager.aidl \ src/StatsService.cpp \ tests/indexed_priority_queue_test.cpp \ + src/parse_util.cpp \ src/LogEntryPrinter.cpp \ src/LogReader.cpp \ + src/matchers/LogEntryMatcherManager.cpp \ tests/LogReader_test.cpp \ + tests/LogEntryMatcher_test.cpp \ LOCAL_STATIC_LIBRARIES := \ libgmock \ - statsd_proto + statsd_proto \ LOCAL_SHARED_LIBRARIES := \ libbase \ diff --git a/cmds/statsd/src/matchers/LogEntryMatcherManager.cpp b/cmds/statsd/src/matchers/LogEntryMatcherManager.cpp new file mode 100644 index 000000000000..bb0951ce4fab --- /dev/null +++ b/cmds/statsd/src/matchers/LogEntryMatcherManager.cpp @@ -0,0 +1,182 @@ +/* + * 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 "LogEntryMatcherManager.h" +#include <log/event_tag_map.h> +#include <log/logprint.h> +#include <utils/Errors.h> +#include <cutils/log.h> +#include <unordered_map> +#include <frameworks/base/cmds/statsd/src/statsd_config.pb.h> + +using std::unordered_map; +using std::string; + +namespace android { +namespace os { +namespace statsd { + +bool LogEntryMatcherManager::matches(const LogEntryMatcher &matcher, const int tagId, + const unordered_map<int, long> &intMap, + const unordered_map<int, string> &strMap, + const unordered_map<int, float> &floatMap, + const unordered_map<int, bool> &boolMap) { + if (matcher.has_combination()) { // Need to evaluate composite matching + switch (matcher.combination().operation()) { + case LogicalOperation::AND: + for (auto nestedMatcher : matcher.combination().matcher()) { + if (!matches(nestedMatcher, tagId, intMap, strMap, floatMap, boolMap)) { + return false; // return false if any nested matcher is false; + } + } + return true; // Otherwise, return true. + case LogicalOperation::OR: + for (auto nestedMatcher : matcher.combination().matcher()) { + if (matches(nestedMatcher, tagId, intMap, strMap, floatMap, boolMap)) { + return true; // return true if any nested matcher is true; + } + } + return false; + case LogicalOperation::NOT: + return !matches(matcher.combination().matcher(0), tagId, intMap, strMap, floatMap, + boolMap); + + // Case NAND is just inverting the return statement of AND + case LogicalOperation::NAND: + for (auto nestedMatcher : matcher.combination().matcher()) { + auto simple = nestedMatcher.simple_log_entry_matcher(); + if (!matches(nestedMatcher, tagId, intMap, strMap, floatMap, boolMap)) { + return true; // return false if any nested matcher is false; + } + } + return false; // Otherwise, return true. + case LogicalOperation::NOR: + for (auto nestedMatcher : matcher.combination().matcher()) { + if (matches(nestedMatcher, tagId, intMap, strMap, floatMap, boolMap)) { + return false; // return true if any nested matcher is true; + } + } + return true; + } + return false; + } else { + return matchesSimple(matcher.simple_log_entry_matcher(), tagId, intMap, strMap, floatMap, + boolMap); + } +} + +bool LogEntryMatcherManager::matchesSimple(const SimpleLogEntryMatcher &simpleMatcher, + const int tagId, + const unordered_map<int, long> &intMap, + const unordered_map<int, string> &strMap, + const unordered_map<int, float> &floatMap, + const unordered_map<int, bool> &boolMap) { + for (int i = 0; i < simpleMatcher.tag_size(); i++) { + if (simpleMatcher.tag(i) != tagId) { + continue; + } + + // now see if this event is interesting to us -- matches ALL the matchers + // defined in the metrics. + bool allMatched = true; + for (int j = 0; j < simpleMatcher.key_value_matcher_size(); j++) { + auto cur = simpleMatcher.key_value_matcher(j); + + // TODO: Check if this key is a magic key (eg package name). + int key = cur.key_matcher().key(); + + switch (cur.value_matcher_case()) { + case KeyValueMatcher::ValueMatcherCase::kEqString: { + auto it = strMap.find(key); + if (it == strMap.end() || cur.eq_string().compare(it->second) != 0) { + allMatched = false; + } + break; + } + case KeyValueMatcher::ValueMatcherCase::kEqInt: { + auto it = intMap.find(key); + if (it == intMap.end() || cur.eq_int() != it->second) { + allMatched = false; + } + break; + } + case KeyValueMatcher::ValueMatcherCase::kEqBool: { + auto it = boolMap.find(key); + if (it == boolMap.end() || cur.eq_bool() != it->second) { + allMatched = false; + } + break; + } + // Begin numeric comparisons + case KeyValueMatcher::ValueMatcherCase::kLtInt: { + auto it = intMap.find(key); + if (it == intMap.end() || cur.lt_int() <= it->second) { + allMatched = false; + } + break; + } + case KeyValueMatcher::ValueMatcherCase::kGtInt: { + auto it = intMap.find(key); + if (it == intMap.end() || cur.gt_int() >= it->second) { + allMatched = false; + } + break; + } + case KeyValueMatcher::ValueMatcherCase::kLtFloat: { + auto it = floatMap.find(key); + if (it == floatMap.end() || cur.lt_float() <= it->second) { + allMatched = false; + } + break; + } + case KeyValueMatcher::ValueMatcherCase::kGtFloat: { + auto it = floatMap.find(key); + if (it == floatMap.end() || cur.gt_float() >= it->second) { + allMatched = false; + } + break; + } + // Begin comparisons with equality + case KeyValueMatcher::ValueMatcherCase::kLteInt: { + auto it = intMap.find(key); + if (it == intMap.end() || cur.lte_int() < it->second) { + allMatched = false; + } + break; + } + case KeyValueMatcher::ValueMatcherCase::kGteInt: { + auto it = intMap.find(key); + if (it == intMap.end() || cur.gte_int() > it->second) { + allMatched = false; + } + break; + } + case KeyValueMatcher::ValueMatcherCase::VALUE_MATCHER_NOT_SET: + // If value matcher is not present, assume that we match. + break; + } + } + + if (allMatched) { + return true; + } + } + return false; +} + +} // namespace statsd +} // namespace os +} // namespace android diff --git a/cmds/statsd/src/matchers/LogEntryMatcherManager.h b/cmds/statsd/src/matchers/LogEntryMatcherManager.h new file mode 100644 index 000000000000..10ac0e2e9145 --- /dev/null +++ b/cmds/statsd/src/matchers/LogEntryMatcherManager.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LOG_ENTRY_MATCHER_MANAGER_H +#define LOG_ENTRY_MATCHER_MANAGER_H + +#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" +#include <log/logprint.h> +#include <log/log_read.h> +#include <set> +#include <vector> +#include <unordered_map> + +using std::unordered_map; +using std::string; + +namespace android { +namespace os { +namespace statsd { + +/** + * Keeps track per log entry which simple log entry matchers match. + */ +class LogEntryMatcherManager { +public: + LogEntryMatcherManager(); + + ~LogEntryMatcherManager() {}; + + static bool matches(const LogEntryMatcher &matcher, const int tagId, + const unordered_map<int, long> &intMap, + const unordered_map<int, string> &strMap, + const unordered_map<int, float> &floatMap, + const unordered_map<int, bool> &boolMap); + + static bool matchesSimple(const SimpleLogEntryMatcher &simpleMatcher, + const int tagId, + const unordered_map<int, long> &intMap, + const unordered_map<int, string> &strMap, + const unordered_map<int, float> &floatMap, + const unordered_map<int, bool> &boolMap); +}; + +} // namespace statsd +} // namespace os +} // namespace android +#endif //LOG_ENTRY_MATCHER_MANAGER_H diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto index c6119df691a3..c7f030559cd3 100644 --- a/cmds/statsd/src/statsd_config.proto +++ b/cmds/statsd/src/statsd_config.proto @@ -19,14 +19,17 @@ message KeyValueMatcher { oneof value_matcher { bool eq_bool = 2; string eq_string = 3; - int32 eq_int32 = 4; - int64 eq_int64 = 5; - int32 lt_int32 = 6; - int32 gt_int32 = 7; - int64 lt_int64 = 8; - int64 gt_int64 = 9; - float lt_float = 10; - float gt_float = 11; + int32 eq_int = 4; + + // Numeric comparisons. Lt means strictly less than. + int64 lt_int = 5; + int64 gt_int = 6; + float lt_float = 7; + float gt_float = 8; + + // Numeric comparisons with equality. Lte means less than or equal. + int64 lte_int = 9; + int64 gte_int = 10; } } diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp new file mode 100644 index 000000000000..eb807cad9085 --- /dev/null +++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp @@ -0,0 +1,366 @@ +// 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 "statsd_test" + +#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" +#include "../src/matchers/LogEntryMatcherManager.h" +#include "../src/parse_util.h" +#include <log/logprint.h> +#include <log/log_read.h> +#include <log/log_event_list.h> +#include <gtest/gtest.h> + +#include <stdio.h> + +using namespace android::os::statsd; +using std::unordered_map; + +#ifdef __ANDROID__ +TEST(LogEntryMatcherTest, TestSimpleMatcher) { + // Set up the matcher + LogEntryMatcher matcher; + auto simpleMatcher = matcher.mutable_simple_log_entry_matcher(); + simpleMatcher->add_tag(TagId::WAKELOCK); + + unordered_map<int, long> intMap; + unordered_map<int, string> strMap; + unordered_map<int, float> floatMap; + unordered_map<int, bool> boolMap; + + EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, floatMap, boolMap)); +} + +TEST(LogEntryMatcherTest, TestBoolMatcher) { + // Set up the matcher + LogEntryMatcher matcher; + auto simpleMatcher = matcher.mutable_simple_log_entry_matcher(); + simpleMatcher->add_tag(TagId::WAKELOCK); + auto keyValue = simpleMatcher->add_key_value_matcher(); + keyValue->mutable_key_matcher()->set_key(KeyId::STATE); + + + unordered_map<int, long> intMap; + unordered_map<int, string> strMap; + unordered_map<int, float> floatMap; + unordered_map<int, bool> boolMap; + + keyValue->set_eq_bool(true); + boolMap[KeyId::STATE] = true; + EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, floatMap, + boolMap)); + + keyValue->set_eq_bool(false); + EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, + floatMap, boolMap)); + + boolMap[TagId::WAKELOCK] = false; + EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, floatMap, + boolMap)); +} + +TEST(LogEntryMatcherTest, TestStringMatcher) { + // Set up the matcher + LogEntryMatcher matcher; + auto simpleMatcher = matcher.mutable_simple_log_entry_matcher(); + simpleMatcher->add_tag(TagId::WAKELOCK); + auto keyValue = simpleMatcher->add_key_value_matcher(); + keyValue->mutable_key_matcher()->set_key(KeyId::STATE); + keyValue->set_eq_string("wakelock_name"); + + unordered_map<int, long> intMap; + unordered_map<int, string> strMap; + unordered_map<int, float> floatMap; + unordered_map<int, bool> boolMap; + + strMap[KeyId::STATE] = "wakelock_name"; + + EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, floatMap, boolMap)); +} + +TEST(LogEntryMatcherTest, TestIntComparisonMatcher) { + // Set up the matcher + LogEntryMatcher matcher; + auto simpleMatcher = matcher.mutable_simple_log_entry_matcher(); + simpleMatcher->add_tag(TagId::WAKELOCK); + auto keyValue = simpleMatcher->add_key_value_matcher(); + keyValue->mutable_key_matcher()->set_key(KeyId::STATE); + + unordered_map<int, long> intMap; + unordered_map<int, string> strMap; + unordered_map<int, float> floatMap; + unordered_map<int, bool> boolMap; + + keyValue->set_lt_int(10); + intMap[KeyId::STATE] = 11; + EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, + floatMap, boolMap)); + intMap[KeyId::STATE] = 10; + EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, + floatMap, boolMap)); + intMap[KeyId::STATE] = 9; + EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, + floatMap, boolMap)); + + keyValue->set_gt_int(10); + intMap[KeyId::STATE] = 11; + EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, + floatMap, boolMap)); + intMap[KeyId::STATE] = 10; + EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, + floatMap, boolMap)); + intMap[KeyId::STATE] = 9; + EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, + floatMap, boolMap)); +} + +TEST(LogEntryMatcherTest, TestIntWithEqualityComparisonMatcher) { + // Set up the matcher + LogEntryMatcher matcher; + auto simpleMatcher = matcher.mutable_simple_log_entry_matcher(); + simpleMatcher->add_tag(TagId::WAKELOCK); + auto keyValue = simpleMatcher->add_key_value_matcher(); + keyValue->mutable_key_matcher()->set_key(KeyId::STATE); + + unordered_map<int, long> intMap; + unordered_map<int, string> strMap; + unordered_map<int, float> floatMap; + unordered_map<int, bool> boolMap; + + keyValue->set_lte_int(10); + intMap[KeyId::STATE] = 11; + EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, + floatMap, boolMap)); + intMap[KeyId::STATE] = 10; + EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, + floatMap, boolMap)); + intMap[KeyId::STATE] = 9; + EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, + floatMap, boolMap)); + + keyValue->set_gte_int(10); + intMap[KeyId::STATE] = 11; + EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, + floatMap, boolMap)); + intMap[KeyId::STATE] = 10; + EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, + floatMap, boolMap)); + intMap[KeyId::STATE] = 9; + EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, + floatMap, boolMap)); +} + +TEST(LogEntryMatcherTest, TestFloatComparisonMatcher) { + // Set up the matcher + LogEntryMatcher matcher; + auto simpleMatcher = matcher.mutable_simple_log_entry_matcher(); + simpleMatcher->add_tag(TagId::WAKELOCK); + auto keyValue = simpleMatcher->add_key_value_matcher(); + keyValue->mutable_key_matcher()->set_key(KeyId::STATE); + + unordered_map<int, long> intMap; + unordered_map<int, string> strMap; + unordered_map<int, float> floatMap; + unordered_map<int, bool> boolMap; + + keyValue->set_lt_float(10.0); + floatMap[KeyId::STATE] = 10.1; + EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, + floatMap, boolMap)); + floatMap[KeyId::STATE] = 9.9; + EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, + floatMap, boolMap)); + + keyValue->set_gt_float(10.0); + floatMap[KeyId::STATE] = 10.1; + EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, + floatMap, boolMap)); + floatMap[KeyId::STATE] = 9.9; + EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, + floatMap, boolMap)); +} + +// Helper for the composite matchers. +void addSimpleMatcher(SimpleLogEntryMatcher* simpleMatcher, TagId tag, KeyId key, int val) { + simpleMatcher->add_tag(tag); + auto keyValue = simpleMatcher->add_key_value_matcher(); + keyValue->mutable_key_matcher()->set_key(key); + keyValue->set_eq_int(val); +} + +TEST(LogEntryMatcherTest, TestAndMatcher) { + // Set up the matcher + LogEntryMatcher matcher; + auto combination = matcher.mutable_combination(); + combination->set_operation(LogicalOperation::AND); + + addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(), TagId::WAKELOCK, KeyId::STATE, 3); + addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(), TagId::WAKELOCK, KeyId::PACKAGE_VERSION, 4); + + unordered_map<int, long> intMap; + unordered_map<int, string> strMap; + unordered_map<int, float> floatMap; + unordered_map<int, bool> boolMap; + + intMap[1003] = 4; + EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, floatMap, boolMap)); + intMap.clear(); + intMap[1] = 3; + EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, floatMap, boolMap)); + intMap.clear(); + intMap[1] = 3; + intMap[1003] = 4; + EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, floatMap, boolMap)); +} + +TEST(LogEntryMatcherTest, TestOrMatcher) { + // Set up the matcher + LogEntryMatcher matcher; + auto combination = matcher.mutable_combination(); + combination->set_operation(LogicalOperation::OR); + + addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(), + TagId::WAKELOCK, KeyId::STATE, 3); + addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(), + TagId::WAKELOCK, KeyId::PACKAGE_VERSION, 4); + + unordered_map<int, long> intMap; + unordered_map<int, string> strMap; + unordered_map<int, float> floatMap; + unordered_map<int, bool> boolMap; + + // Don't set any key-value pairs. + EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, floatMap, + boolMap)); + intMap[1003] = 4; + EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, floatMap, + boolMap)); + intMap.clear(); + intMap[1] = 3; + EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, floatMap, + boolMap)); + intMap.clear(); + intMap[1] = 3; + intMap[1003] = 4; + EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, floatMap, + boolMap)); +} + +TEST(LogEntryMatcherTest, TestNotMatcher) { + // Set up the matcher + LogEntryMatcher matcher; + auto combination = matcher.mutable_combination(); + combination->set_operation(LogicalOperation::NOT); + + // Define first simpleMatcher + addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(), + TagId::WAKELOCK, KeyId::STATE, 3); + + unordered_map<int, long> intMap; + unordered_map<int, string> strMap; + unordered_map<int, float> floatMap; + unordered_map<int, bool> boolMap; + + // Don't set any key-value pairs. + intMap[KeyId::STATE] = 3; + EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, floatMap, + boolMap)); +} + +TEST(LogEntryMatcherTest, TestNANDMatcher) { + // Set up the matcher + LogEntryMatcher matcher; + auto combination = matcher.mutable_combination(); + combination->set_operation(LogicalOperation::NAND); + + addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(), + TagId::WAKELOCK, KeyId::STATE, 3); + addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(), + TagId::WAKELOCK, KeyId::PACKAGE_VERSION, 4); + + unordered_map<int, long> intMap; + unordered_map<int, string> strMap; + unordered_map<int, float> floatMap; + unordered_map<int, bool> boolMap; + + // Don't set any key-value pairs. + EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, floatMap, + boolMap)); + intMap[KeyId::STATE] = 3; + EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, floatMap, + boolMap)); + intMap[KeyId::PACKAGE_VERSION] = 4; + EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, floatMap, + boolMap)); +} + +TEST(LogEntryMatcherTest, TestNORMatcher) { + // Set up the matcher + LogEntryMatcher matcher; + auto combination = matcher.mutable_combination(); + combination->set_operation(LogicalOperation::NOR); + + addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(), + TagId::WAKELOCK, KeyId::STATE, 3); + addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(), + TagId::WAKELOCK, KeyId::PACKAGE_VERSION, 4); + + unordered_map<int, long> intMap; + unordered_map<int, string> strMap; + unordered_map<int, float> floatMap; + unordered_map<int, bool> boolMap; + + // Don't set any key-value pairs. + EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, floatMap, + boolMap)); + intMap[KeyId::STATE] = 3; + EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, floatMap, + boolMap)); + intMap[KeyId::PACKAGE_VERSION] = 4; + EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, floatMap, + boolMap)); +} + +// Tests that a NOT on top of AND is the same as NAND +TEST(LogEntryMatcherTest, TestMultipleLayerMatcher) { + LogEntryMatcher matcher; + auto not_combination = matcher.mutable_combination(); + not_combination->set_operation(LogicalOperation::NOT); + + // Now add the AND + auto combination = not_combination->add_matcher()->mutable_combination(); + combination->set_operation(LogicalOperation::AND); + addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(), + TagId::WAKELOCK, KeyId::STATE, 3); + addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(), + TagId::WAKELOCK, KeyId::PACKAGE_VERSION, 4); + + unordered_map<int, long> intMap; + unordered_map<int, string> strMap; + unordered_map<int, float> floatMap; + unordered_map<int, bool> boolMap; + + // Don't set any key-value pairs. + EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, floatMap, + boolMap)); + intMap[KeyId::STATE] = 3; + EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, floatMap, + boolMap)); + intMap[KeyId::PACKAGE_VERSION] = 4; + EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, TagId::WAKELOCK, intMap, strMap, floatMap, + boolMap)); +} +#else + GTEST_LOG_(INFO) << "This test does nothing.\n"; +#endif diff --git a/config/compiled-classes-phone b/config/compiled-classes-phone index df68f14efec9..42e6ecf79229 100644 --- a/config/compiled-classes-phone +++ b/config/compiled-classes-phone @@ -5022,8 +5022,6 @@ android.widget.RemoteViews$AsyncApplyTask android.widget.RemoteViews$BitmapCache android.widget.RemoteViews$BitmapReflectionAction android.widget.RemoteViews$LayoutParamAction -android.widget.RemoteViews$MemoryUsageCounter -android.widget.RemoteViews$MutablePair android.widget.RemoteViews$OnClickHandler android.widget.RemoteViews$OnViewAppliedListener android.widget.RemoteViews$ReflectionAction @@ -5031,7 +5029,7 @@ android.widget.RemoteViews$RemoteView android.widget.RemoteViews$RemoteViewsContextWrapper android.widget.RemoteViews$RunnableAction android.widget.RemoteViews$RuntimeAction -android.widget.RemoteViews$SetDrawableParameters +android.widget.RemoteViews$SetDrawableTint android.widget.RemoteViews$SetOnClickPendingIntent android.widget.RemoteViews$SetOnClickPendingIntent$1 android.widget.RemoteViews$ViewGroupAction diff --git a/config/preloaded-classes b/config/preloaded-classes index 337d7a0ad8bb..c0819a98a64c 100644 --- a/config/preloaded-classes +++ b/config/preloaded-classes @@ -2723,13 +2723,11 @@ android.widget.RemoteViews$3 android.widget.RemoteViews$Action android.widget.RemoteViews$BitmapCache android.widget.RemoteViews$LayoutParamAction -android.widget.RemoteViews$MemoryUsageCounter -android.widget.RemoteViews$MutablePair android.widget.RemoteViews$OnClickHandler android.widget.RemoteViews$ReflectionAction android.widget.RemoteViews$RemoteView android.widget.RemoteViews$RuntimeAction -android.widget.RemoteViews$SetDrawableParameters +android.widget.RemoteViews$SetDrawableTint android.widget.RemoteViewsAdapter$RemoteAdapterConnectionCallback android.widget.RtlSpacingHelper android.widget.ScrollBarDrawable diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java index 00d6657efd0d..1a2dc5cde4e5 100644 --- a/core/java/android/animation/AnimatorSet.java +++ b/core/java/android/animation/AnimatorSet.java @@ -843,7 +843,7 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim // Assumes forward playing from here on. for (int i = 0; i < mEvents.size(); i++) { AnimationEvent event = mEvents.get(i); - if (event.getTime() > currentPlayTime) { + if (event.getTime() > currentPlayTime || event.getTime() == DURATION_INFINITE) { break; } @@ -1264,7 +1264,8 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim } else { for (int i = mLastEventId + 1; i < size; i++) { AnimationEvent event = mEvents.get(i); - if (event.getTime() <= currentPlayTime) { + // TODO: need a function that accounts for infinite duration to compare time + if (event.getTime() != DURATION_INFINITE && event.getTime() <= currentPlayTime) { latestId = i; } } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 60f4ed01805c..fee7d6c8ba2b 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -3839,8 +3839,8 @@ public class Notification implements Parcelable contentView.setImageViewBitmap(R.id.profile_badge, profileBadge); contentView.setViewVisibility(R.id.profile_badge, View.VISIBLE); if (isColorized()) { - contentView.setDrawableParameters(R.id.profile_badge, false, -1, - getPrimaryTextColor(), PorterDuff.Mode.SRC_ATOP, -1); + contentView.setDrawableTint(R.id.profile_badge, false, + getPrimaryTextColor(), PorterDuff.Mode.SRC_ATOP); } } } @@ -4130,18 +4130,14 @@ public class Notification implements Parcelable if (action != null) { int contrastColor = resolveContrastColor(); - contentView.setDrawableParameters(R.id.reply_icon_action, + contentView.setDrawableTint(R.id.reply_icon_action, true /* targetBackground */, - -1, - contrastColor, - PorterDuff.Mode.SRC_ATOP, -1); + contrastColor, PorterDuff.Mode.SRC_ATOP); int iconColor = NotificationColorUtil.isColorLight(contrastColor) ? Color.BLACK : Color.WHITE; - contentView.setDrawableParameters(R.id.reply_icon_action, + contentView.setDrawableTint(R.id.reply_icon_action, false /* targetBackground */, - -1, - iconColor, - PorterDuff.Mode.SRC_ATOP, -1); + iconColor, PorterDuff.Mode.SRC_ATOP); contentView.setOnClickPendingIntent(R.id.right_icon, action.actionIntent); contentView.setOnClickPendingIntent(R.id.reply_icon_action, @@ -4185,8 +4181,8 @@ public class Notification implements Parcelable private void bindExpandButton(RemoteViews contentView) { int color = getPrimaryHighlightColor(); - contentView.setDrawableParameters(R.id.expand_button, false, -1, color, - PorterDuff.Mode.SRC_ATOP, -1); + contentView.setDrawableTint(R.id.expand_button, false, color, + PorterDuff.Mode.SRC_ATOP); contentView.setInt(R.id.notification_header, "setOriginalNotificationColor", color); } @@ -4293,8 +4289,7 @@ public class Notification implements Parcelable mN.mSmallIcon = Icon.createWithResource(mContext, mN.icon); } contentView.setImageViewIcon(R.id.icon, mN.mSmallIcon); - contentView.setDrawableParameters(R.id.icon, false /* targetBackground */, - -1 /* alpha */, -1 /* colorFilter */, null /* mode */, mN.iconLevel); + contentView.setInt(R.id.icon, "setImageLevel", mN.iconLevel); processSmallIconColor(mN.mSmallIcon, contentView, ambient); } @@ -4684,8 +4679,8 @@ public class Notification implements Parcelable bgColor = mContext.getColor(oddAction ? R.color.notification_action_list : R.color.notification_action_list_dark); } - button.setDrawableParameters(R.id.button_holder, true, -1, bgColor, - PorterDuff.Mode.SRC_ATOP, -1); + button.setDrawableTint(R.id.button_holder, true, + bgColor, PorterDuff.Mode.SRC_ATOP); CharSequence title = action.title; ColorStateList[] outResultColor = null; if (isLegacy()) { @@ -4818,8 +4813,8 @@ public class Notification implements Parcelable boolean colorable = !isLegacy() || getColorUtil().isGrayscaleIcon(mContext, smallIcon); int color = ambient ? resolveAmbientColor() : getPrimaryHighlightColor(); if (colorable) { - contentView.setDrawableParameters(R.id.icon, false, -1, color, - PorterDuff.Mode.SRC_ATOP, -1); + contentView.setDrawableTint(R.id.icon, false, color, + PorterDuff.Mode.SRC_ATOP); } contentView.setInt(R.id.notification_header, "setOriginalIconColor", @@ -4835,8 +4830,8 @@ public class Notification implements Parcelable if (largeIcon != null && isLegacy() && getColorUtil().isGrayscaleIcon(mContext, largeIcon)) { // resolve color will fall back to the default when legacy - contentView.setDrawableParameters(R.id.icon, false, -1, resolveContrastColor(), - PorterDuff.Mode.SRC_ATOP, -1); + contentView.setDrawableTint(R.id.icon, false, resolveContrastColor(), + PorterDuff.Mode.SRC_ATOP); } } @@ -6750,8 +6745,8 @@ public class Notification implements Parcelable : NotificationColorUtil.resolveColor(mBuilder.mContext, Notification.COLOR_DEFAULT); - button.setDrawableParameters(R.id.action0, false, -1, tintColor, - PorterDuff.Mode.SRC_ATOP, -1); + button.setDrawableTint(R.id.action0, false, tintColor, + PorterDuff.Mode.SRC_ATOP); if (!tombstone) { button.setOnClickPendingIntent(R.id.action0, action.actionIntent); } diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 70591d4d0587..84765f6d7280 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -1134,6 +1134,29 @@ public final class BluetoothAdapter { } /** + * Sets the {@link BluetoothClass} Bluetooth Class of Device (CoD) of + * the local Bluetooth adapter. + * + * @param bluetoothClass {@link BluetoothClass} to set the local Bluetooth adapter to. + * @return true if successful, false if unsuccessful. + * + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public boolean setBluetoothClass(BluetoothClass bluetoothClass) { + if (getState() != STATE_ON) return false; + try { + mServiceLock.readLock().lock(); + if (mService != null) return mService.setBluetoothClass(bluetoothClass); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } + return false; + } + + /** * Get the current Bluetooth scan mode of the local Bluetooth adapter. * <p>The Bluetooth scan mode determines if the local adapter is * connectable and/or discoverable from remote Bluetooth devices. diff --git a/core/java/android/bluetooth/BluetoothClass.java b/core/java/android/bluetooth/BluetoothClass.java index 57e4abb12987..f22ea6e88e04 100755 --- a/core/java/android/bluetooth/BluetoothClass.java +++ b/core/java/android/bluetooth/BluetoothClass.java @@ -19,6 +19,10 @@ package android.bluetooth; import android.os.Parcel; import android.os.Parcelable; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Arrays; + /** * Represents a Bluetooth class, which describes general characteristics * and capabilities of a device. For example, a Bluetooth class will @@ -275,6 +279,48 @@ public final class BluetoothClass implements Parcelable { return (mClass & Device.BITMASK); } + /** + * Return the Bluetooth Class of Device (CoD) value including the + * {@link BluetoothClass.Service}, {@link BluetoothClass.Device.Major} and + * minor device fields. + * + * <p>This value is an integer representation of Bluetooth CoD as in + * Bluetooth specification. + * + * @see <a href="Bluetooth CoD">https://www.bluetooth.com/specifications/assigned-numbers/baseband</a> + * + * @hide + */ + public int getClassOfDevice() { + return mClass; + } + + /** + * Return the Bluetooth Class of Device (CoD) value including the + * {@link BluetoothClass.Service}, {@link BluetoothClass.Device.Major} and + * minor device fields. + * + * <p>This value is a byte array representation of Bluetooth CoD as in + * Bluetooth specification. + * + * <p>Bluetooth COD information is 3 bytes, but stored as an int. Hence the + * MSB is useless and needs to be thrown away. The lower 3 bytes are + * converted into a byte array MSB to LSB. Hence, using BIG_ENDIAN. + * + * @see <a href="Bluetooth CoD">https://www.bluetooth.com/specifications/assigned-numbers/baseband</a> + * + * @hide + */ + public byte[] getClassOfDeviceBytes() { + byte[] bytes = ByteBuffer.allocate(4) + .order(ByteOrder.BIG_ENDIAN) + .putInt(mClass) + .array(); + + // Discard the top byte + return Arrays.copyOfRange(bytes, 1, bytes.length); + } + /** @hide */ public static final int PROFILE_HEADSET = 0; /** @hide */ diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java index 25f791bc8cc6..c3b2a16cc986 100644 --- a/core/java/android/text/Layout.java +++ b/core/java/android/text/Layout.java @@ -1915,8 +1915,7 @@ public abstract class Layout { return margin; } - /* package */ - static float measurePara(TextPaint paint, CharSequence text, int start, int end, + private static float measurePara(TextPaint paint, CharSequence text, int start, int end, TextDirectionHeuristic textDir) { MeasuredText mt = MeasuredText.obtain(); TextLine tl = TextLine.obtain(); diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index 3303b54e462b..8e0ad6352081 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -101,6 +101,7 @@ public class StaticLayout extends Layout { b.mBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE; b.mHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE; b.mJustificationMode = Layout.JUSTIFICATION_MODE_NONE; + b.mLocales = null; b.mMeasuredText = MeasuredText.obtain(); return b; @@ -117,6 +118,9 @@ public class StaticLayout extends Layout { b.mMeasuredText = null; b.mLeftIndents = null; b.mRightIndents = null; + b.mLocales = null; + b.mLeftPaddings = null; + b.mRightPaddings = null; nFinishBuilder(b.mNativePtr); sPool.release(b); } @@ -128,6 +132,8 @@ public class StaticLayout extends Layout { mPaint = null; mLeftIndents = null; mRightIndents = null; + mLeftPaddings = null; + mRightPaddings = null; mMeasuredText.finish(); } @@ -356,6 +362,28 @@ public class StaticLayout extends Layout { } /** + * Set available paddings to draw overhanging text on. Arguments are arrays holding the + * amount of padding available, one per line, measured in pixels. For lines past the last + * element in the array, the last element repeats. + * + * The individual padding amounts should be non-negative. The result of passing negative + * paddings is undefined. + * + * @param leftPaddings array of amounts of available padding for left margin, in pixels + * @param rightPaddings array of amounts of available padding for right margin, in pixels + * @return this builder, useful for chaining + * + * @hide + */ + @NonNull + public Builder setAvailablePaddings(@Nullable int[] leftPaddings, + @Nullable int[] rightPaddings) { + mLeftPaddings = leftPaddings; + mRightPaddings = rightPaddings; + return this; + } + + /** * Set paragraph justification mode. The default value is * {@link Layout#JUSTIFICATION_MODE_NONE}. If the last line is too short for justification, * the last line will be displayed with the alignment set by {@link #setAlignment}. @@ -401,7 +429,6 @@ public class StaticLayout extends Layout { * future). * * Then, for each run within the paragraph: - * - setLocales (this must be done at least for the first run, optional afterwards) * - one of the following, depending on the type of run: * + addStyleRun (a text run, to be measured in native code) * + addMeasuredRun (a run already measured in Java, passed into native code) @@ -413,16 +440,21 @@ public class StaticLayout extends Layout { * After all paragraphs, call finish() to release expensive buffers. */ - private void setLocales(LocaleList locales) { + /* package */ float addStyleRun(TextPaint paint, int start, int end, boolean isRtl) { + final LocaleList locales = paint.getTextLocales(); + final String languageTags; + long[] hyphenators; if (!locales.equals(mLocales)) { - nSetLocales(mNativePtr, locales.toLanguageTags(), getHyphenators(locales)); - mLocales = locales; + languageTags = locales.toLanguageTags(); + hyphenators = getHyphenators(locales); + } else { + // passing null means keep current locale. + // TODO: move locale change detection to native. + languageTags = null; + hyphenators = null; } - } - - /* package */ float addStyleRun(TextPaint paint, int start, int end, boolean isRtl) { - setLocales(paint.getTextLocales()); - return nAddStyleRun(mNativePtr, paint.getNativeInstance(), start, end, isRtl); + return nAddStyleRun(mNativePtr, paint.getNativeInstance(), start, end, isRtl, + languageTags, hyphenators); } /* package */ void addMeasuredRun(int start, int end, float[] widths) { @@ -478,6 +510,8 @@ public class StaticLayout extends Layout { private int mHyphenationFrequency; @Nullable private int[] mLeftIndents; @Nullable private int[] mRightIndents; + @Nullable private int[] mLeftPaddings; + @Nullable private int[] mRightPaddings; private int mJustificationMode; private boolean mAddLastLineLineSpacing; @@ -638,6 +672,8 @@ public class StaticLayout extends Layout { mLeftIndents = b.mLeftIndents; mRightIndents = b.mRightIndents; + mLeftPaddings = b.mLeftPaddings; + mRightPaddings = b.mRightPaddings; setJustificationMode(b.mJustificationMode); generate(b, b.mIncludePad, b.mIncludePad); @@ -662,7 +698,6 @@ public class StaticLayout extends Layout { // store fontMetrics per span range // must be a multiple of 4 (and > 0) (store top, bottom, ascent, and descent per range) int[] fmCache = new int[4 * 4]; - b.setLocales(paint.getTextLocales()); mLineCount = 0; mEllipsized = false; @@ -780,7 +815,10 @@ public class StaticLayout extends Layout { firstWidth, firstWidthLineCount, restWidth, variableTabStops, TAB_INCREMENT, b.mBreakStrategy, b.mHyphenationFrequency, // TODO: Support more justification mode, e.g. letter spacing, stretching. - b.mJustificationMode != Layout.JUSTIFICATION_MODE_NONE, indents, mLineCount); + b.mJustificationMode != Layout.JUSTIFICATION_MODE_NONE, + // TODO: indents and paddings don't need to get passed to native code for every + // paragraph. Pass them to native code just once. + indents, mLeftPaddings, mRightPaddings, mLineCount); // measurement has to be done before performing line breaking // but we don't want to recompute fontmetrics or span ranges the @@ -1494,20 +1532,20 @@ public class StaticLayout extends Layout { /* package */ static native long nLoadHyphenator(ByteBuffer buf, int offset, int minPrefix, int minSuffix); - private static native void nSetLocales(long nativePtr, String locales, - long[] nativeHyphenators); - // Set up paragraph text and settings; done as one big method to minimize jni crossings private static native void nSetupParagraph( - @NonNull long nativePtr, @NonNull char[] text, @IntRange(from = 0) int length, + /* non zero */ long nativePtr, @NonNull char[] text, @IntRange(from = 0) int length, @FloatRange(from = 0.0f) float firstWidth, @IntRange(from = 0) int firstWidthLineCount, @FloatRange(from = 0.0f) float restWidth, @Nullable int[] variableTabStops, int defaultTabStop, @BreakStrategy int breakStrategy, @HyphenationFrequency int hyphenationFrequency, boolean isJustified, - @Nullable int[] indents, @IntRange(from = 0) int indentsOffset); + @Nullable int[] indents, @Nullable int[] leftPaddings, @Nullable int[] rightPaddings, + @IntRange(from = 0) int indentsOffset); - private static native float nAddStyleRun(long nativePtr, long nativePaint, int start, int end, - boolean isRtl); + private static native float nAddStyleRun( + /* non zero */ long nativePtr, /* non zero */ long nativePaint, + @IntRange(from = 0) int start, @IntRange(from = 0) int end, boolean isRtl, + @Nullable String languageTags, @Nullable long[] hyphenators); private static native void nAddMeasuredRun(long nativePtr, int start, int end, float[] widths); @@ -1590,4 +1628,6 @@ public class StaticLayout extends Layout { @Nullable private int[] mLeftIndents; @Nullable private int[] mRightIndents; + @Nullable private int[] mLeftPaddings; + @Nullable private int[] mRightPaddings; } diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index a5d964951af1..1b26f8e2fd9f 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -20,6 +20,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import android.annotation.ColorInt; import android.annotation.DimenRes; +import android.annotation.NonNull; import android.app.ActivityOptions; import android.app.ActivityThread; import android.app.Application; @@ -108,9 +109,9 @@ public class RemoteViews implements Parcelable, Filter { // The unique identifiers for each custom {@link Action}. private static final int SET_ON_CLICK_PENDING_INTENT_TAG = 1; private static final int REFLECTION_ACTION_TAG = 2; - private static final int SET_DRAWABLE_PARAMETERS_TAG = 3; + private static final int SET_DRAWABLE_TINT_TAG = 3; private static final int VIEW_GROUP_ACTION_ADD_TAG = 4; - private static final int SET_REFLECTION_ACTION_WITHOUT_PARAMS_TAG = 5; + private static final int VIEW_CONTENT_NAVIGATION_TAG = 5; private static final int SET_EMPTY_VIEW_ACTION_TAG = 6; private static final int VIEW_GROUP_ACTION_REMOVE_TAG = 7; private static final int SET_PENDING_INTENT_TEMPLATE_TAG = 8; @@ -121,7 +122,6 @@ public class RemoteViews implements Parcelable, Filter { private static final int TEXT_VIEW_SIZE_ACTION_TAG = 13; private static final int VIEW_PADDING_ACTION_TAG = 14; private static final int SET_REMOTE_VIEW_ADAPTER_LIST_TAG = 15; - private static final int TEXT_VIEW_DRAWABLE_COLOR_FILTER_ACTION_TAG = 17; private static final int SET_REMOTE_INPUTS_ACTION_TAG = 18; private static final int LAYOUT_PARAM_ACTION_TAG = 19; private static final int OVERRIDE_TEXT_COLORS_TAG = 20; @@ -389,10 +389,10 @@ public class RemoteViews implements Parcelable, Filter { return MERGE_REPLACE; } - public abstract String getActionName(); + public abstract int getActionTag(); public String getUniqueKey() { - return (getActionName() + viewId); + return (getActionTag() + "_" + viewId); } /** @@ -424,8 +424,8 @@ public class RemoteViews implements Parcelable, Filter { */ private static abstract class RuntimeAction extends Action { @Override - public final String getActionName() { - return "RuntimeAction"; + public final int getActionTag() { + return 0; } @Override @@ -514,7 +514,6 @@ public class RemoteViews implements Parcelable, Filter { } private class SetEmptyView extends Action { - int viewId; int emptyViewId; SetEmptyView(int viewId, int emptyViewId) { @@ -528,7 +527,6 @@ public class RemoteViews implements Parcelable, Filter { } public void writeToParcel(Parcel out, int flags) { - out.writeInt(SET_EMPTY_VIEW_ACTION_TAG); out.writeInt(this.viewId); out.writeInt(this.emptyViewId); } @@ -546,8 +544,9 @@ public class RemoteViews implements Parcelable, Filter { adapterView.setEmptyView(emptyView); } - public String getActionName() { - return "SetEmptyView"; + @Override + public int getActionTag() { + return SET_EMPTY_VIEW_ACTION_TAG; } } @@ -559,13 +558,12 @@ public class RemoteViews implements Parcelable, Filter { public SetOnClickFillInIntent(Parcel parcel) { viewId = parcel.readInt(); - fillInIntent = Intent.CREATOR.createFromParcel(parcel); + fillInIntent = parcel.readTypedObject(Intent.CREATOR); } public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(SET_ON_CLICK_FILL_IN_INTENT_TAG); dest.writeInt(viewId); - fillInIntent.writeToParcel(dest, 0 /* no flags */); + dest.writeTypedObject(fillInIntent, 0 /* no flags */); } @Override @@ -624,8 +622,9 @@ public class RemoteViews implements Parcelable, Filter { } } - public String getActionName() { - return "SetOnClickFillInIntent"; + @Override + public int getActionTag() { + return SET_ON_CLICK_FILL_IN_INTENT_TAG; } Intent fillInIntent; @@ -643,9 +642,8 @@ public class RemoteViews implements Parcelable, Filter { } public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(SET_PENDING_INTENT_TEMPLATE_TAG); dest.writeInt(viewId); - pendingIntentTemplate.writeToParcel(dest, 0 /* no flags */); + PendingIntent.writePendingIntentOrNullToParcel(pendingIntentTemplate, dest); } @Override @@ -699,8 +697,9 @@ public class RemoteViews implements Parcelable, Filter { } } - public String getActionName() { - return "SetPendingIntentTemplate"; + @Override + public int getActionTag() { + return SET_PENDING_INTENT_TEMPLATE_TAG; } PendingIntent pendingIntentTemplate; @@ -716,30 +715,13 @@ public class RemoteViews implements Parcelable, Filter { public SetRemoteViewsAdapterList(Parcel parcel) { viewId = parcel.readInt(); viewTypeCount = parcel.readInt(); - int count = parcel.readInt(); - list = new ArrayList<RemoteViews>(); - - for (int i = 0; i < count; i++) { - RemoteViews rv = RemoteViews.CREATOR.createFromParcel(parcel); - list.add(rv); - } + list = parcel.createTypedArrayList(RemoteViews.CREATOR); } public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(SET_REMOTE_VIEW_ADAPTER_LIST_TAG); dest.writeInt(viewId); dest.writeInt(viewTypeCount); - - if (list == null || list.size() == 0) { - dest.writeInt(0); - } else { - int count = list.size(); - dest.writeInt(count); - for (int i = 0; i < count; i++) { - RemoteViews rv = list.get(i); - rv.writeToParcel(dest, flags); - } - } + dest.writeTypedList(list, flags); } @Override @@ -779,8 +761,9 @@ public class RemoteViews implements Parcelable, Filter { } } - public String getActionName() { - return "SetRemoteViewsAdapterList"; + @Override + public int getActionTag() { + return SET_REMOTE_VIEW_ADAPTER_LIST_TAG; } int viewTypeCount; @@ -795,13 +778,12 @@ public class RemoteViews implements Parcelable, Filter { public SetRemoteViewsAdapterIntent(Parcel parcel) { viewId = parcel.readInt(); - intent = Intent.CREATOR.createFromParcel(parcel); + intent = parcel.readTypedObject(Intent.CREATOR); } public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(SET_REMOTE_VIEW_ADAPTER_INTENT_TAG); dest.writeInt(viewId); - intent.writeToParcel(dest, flags); + dest.writeTypedObject(intent, flags); } @Override @@ -845,8 +827,9 @@ public class RemoteViews implements Parcelable, Filter { return copy; } - public String getActionName() { - return "SetRemoteViewsAdapterIntent"; + @Override + public int getActionTag() { + return SET_REMOTE_VIEW_ADAPTER_INTENT_TAG; } Intent intent; @@ -866,22 +849,12 @@ public class RemoteViews implements Parcelable, Filter { public SetOnClickPendingIntent(Parcel parcel) { viewId = parcel.readInt(); - - // We check a flag to determine if the parcel contains a PendingIntent. - if (parcel.readInt() != 0) { - pendingIntent = PendingIntent.readPendingIntentOrNullFromParcel(parcel); - } + pendingIntent = PendingIntent.readPendingIntentOrNullFromParcel(parcel); } public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(SET_ON_CLICK_PENDING_INTENT_TAG); dest.writeInt(viewId); - - // We use a flag to indicate whether the parcel contains a valid object. - dest.writeInt(pendingIntent != null ? 1 : 0); - if (pendingIntent != null) { - pendingIntent.writeToParcel(dest, 0 /* no flags */); - } + PendingIntent.writePendingIntentOrNullToParcel(pendingIntent, dest); } @Override @@ -922,8 +895,9 @@ public class RemoteViews implements Parcelable, Filter { target.setOnClickListener(listener); } - public String getActionName() { - return "SetOnClickPendingIntent"; + @Override + public int getActionTag() { + return SET_ON_CLICK_PENDING_INTENT_TAG; } PendingIntent pendingIntent; @@ -1012,55 +986,37 @@ public class RemoteViews implements Parcelable, Filter { } /** - * Equivalent to calling a combination of {@link Drawable#setAlpha(int)}, + * Equivalent to calling * {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)}, - * and/or {@link Drawable#setLevel(int)} on the {@link Drawable} of a given view. + * on the {@link Drawable} of a given view. * <p> - * These operations will be performed on the {@link Drawable} returned by the + * The operation will be performed on the {@link Drawable} returned by the * target {@link View#getBackground()} by default. If targetBackground is false, * we assume the target is an {@link ImageView} and try applying the operations * to {@link ImageView#getDrawable()}. * <p> - * You can omit specific calls by marking their values with null or -1. */ - private class SetDrawableParameters extends Action { - public SetDrawableParameters(int id, boolean targetBackground, int alpha, - int colorFilter, PorterDuff.Mode mode, int level) { + private class SetDrawableTint extends Action { + SetDrawableTint(int id, boolean targetBackground, + int colorFilter, @NonNull PorterDuff.Mode mode) { this.viewId = id; this.targetBackground = targetBackground; - this.alpha = alpha; this.colorFilter = colorFilter; this.filterMode = mode; - this.level = level; } - public SetDrawableParameters(Parcel parcel) { + SetDrawableTint(Parcel parcel) { viewId = parcel.readInt(); targetBackground = parcel.readInt() != 0; - alpha = parcel.readInt(); colorFilter = parcel.readInt(); - boolean hasMode = parcel.readInt() != 0; - if (hasMode) { - filterMode = PorterDuff.Mode.valueOf(parcel.readString()); - } else { - filterMode = null; - } - level = parcel.readInt(); + filterMode = PorterDuff.intToMode(parcel.readInt()); } public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(SET_DRAWABLE_PARAMETERS_TAG); dest.writeInt(viewId); dest.writeInt(targetBackground ? 1 : 0); - dest.writeInt(alpha); dest.writeInt(colorFilter); - if (filterMode != null) { - dest.writeInt(1); - dest.writeString(filterMode.toString()); - } else { - dest.writeInt(0); - } - dest.writeInt(level); + dest.writeInt(PorterDuff.modeToInt(filterMode)); } @Override @@ -1078,47 +1034,36 @@ public class RemoteViews implements Parcelable, Filter { } if (targetDrawable != null) { - // Perform modifications only if values are set correctly - if (alpha != -1) { - targetDrawable.mutate().setAlpha(alpha); - } - if (filterMode != null) { - targetDrawable.mutate().setColorFilter(colorFilter, filterMode); - } - if (level != -1) { - targetDrawable.mutate().setLevel(level); - } + targetDrawable.mutate().setColorFilter(colorFilter, filterMode); } } - public String getActionName() { - return "SetDrawableParameters"; + @Override + public int getActionTag() { + return SET_DRAWABLE_TINT_TAG; } boolean targetBackground; - int alpha; int colorFilter; PorterDuff.Mode filterMode; - int level; } - private final class ReflectionActionWithoutParams extends Action { - final String methodName; + private final class ViewContentNavigation extends Action { + final boolean mNext; - ReflectionActionWithoutParams(int viewId, String methodName) { + ViewContentNavigation(int viewId, boolean next) { this.viewId = viewId; - this.methodName = methodName; + this.mNext = next; } - ReflectionActionWithoutParams(Parcel in) { + ViewContentNavigation(Parcel in) { this.viewId = in.readInt(); - this.methodName = in.readString(); + this.mNext = in.readBoolean(); } public void writeToParcel(Parcel out, int flags) { - out.writeInt(SET_REFLECTION_ACTION_WITHOUT_PARAMS_TAG); out.writeInt(this.viewId); - out.writeString(this.methodName); + out.writeBoolean(this.mNext); } @Override @@ -1127,23 +1072,20 @@ public class RemoteViews implements Parcelable, Filter { if (view == null) return; try { - getMethod(view, this.methodName, null, false /* async */).invoke(view); + getMethod(view, + mNext ? "showNext" : "showPrevious", null, false /* async */).invoke(view); } catch (Throwable ex) { throw new ActionException(ex); } } public int mergeBehavior() { - // we don't need to build up showNext or showPrevious calls - if (methodName.equals("showNext") || methodName.equals("showPrevious")) { - return MERGE_IGNORE; - } else { - return MERGE_REPLACE; - } + return MERGE_IGNORE; } - public String getActionName() { - return "ReflectionActionWithoutParams"; + @Override + public int getActionTag() { + return VIEW_CONTENT_NAVIGATION_TAG; } } @@ -1157,12 +1099,7 @@ public class RemoteViews implements Parcelable, Filter { } public BitmapCache(Parcel source) { - int count = source.readInt(); - mBitmaps = new ArrayList<>(count); - for (int i = 0; i < count; i++) { - Bitmap b = Bitmap.CREATOR.createFromParcel(source); - mBitmaps.add(b); - } + mBitmaps = source.createTypedArrayList(Bitmap.CREATOR); } public int getBitmapId(Bitmap b) { @@ -1188,11 +1125,7 @@ public class RemoteViews implements Parcelable, Filter { } public void writeBitmapsToParcel(Parcel dest, int flags) { - int count = mBitmaps.size(); - dest.writeInt(count); - for (int i = 0; i < count; i++) { - mBitmaps.get(i).writeToParcel(dest, flags); - } + dest.writeTypedList(mBitmaps, flags); } public int getBitmapMemory() { @@ -1228,7 +1161,6 @@ public class RemoteViews implements Parcelable, Filter { @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(BITMAP_REFLECTION_ACTION_TAG); dest.writeInt(viewId); dest.writeString(methodName); dest.writeInt(bitmapId); @@ -1247,8 +1179,9 @@ public class RemoteViews implements Parcelable, Filter { bitmapId = bitmapCache.getBitmapId(bitmap); } - public String getActionName() { - return "BitmapReflectionAction"; + @Override + public int getActionTag() { + return BITMAP_REFLECTION_ACTION_TAG; } } @@ -1300,7 +1233,7 @@ public class RemoteViews implements Parcelable, Filter { // written to the parcel. switch (this.type) { case BOOLEAN: - this.value = in.readInt() != 0; + this.value = in.readBoolean(); break; case BYTE: this.value = in.readByte(); @@ -1330,39 +1263,28 @@ public class RemoteViews implements Parcelable, Filter { this.value = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); break; case URI: - if (in.readInt() != 0) { - this.value = Uri.CREATOR.createFromParcel(in); - } + this.value = in.readTypedObject(Uri.CREATOR); break; case BITMAP: - if (in.readInt() != 0) { - this.value = Bitmap.CREATOR.createFromParcel(in); - } + this.value = in.readTypedObject(Bitmap.CREATOR); break; case BUNDLE: this.value = in.readBundle(); break; case INTENT: - if (in.readInt() != 0) { - this.value = Intent.CREATOR.createFromParcel(in); - } + this.value = in.readTypedObject(Intent.CREATOR); break; case COLOR_STATE_LIST: - if (in.readInt() != 0) { - this.value = ColorStateList.CREATOR.createFromParcel(in); - } + this.value = in.readTypedObject(ColorStateList.CREATOR); break; case ICON: - if (in.readInt() != 0) { - this.value = Icon.CREATOR.createFromParcel(in); - } + this.value = in.readTypedObject(Icon.CREATOR); default: break; } } public void writeToParcel(Parcel out, int flags) { - out.writeInt(REFLECTION_ACTION_TAG); out.writeInt(this.viewId); out.writeString(this.methodName); out.writeInt(this.type); @@ -1376,7 +1298,7 @@ public class RemoteViews implements Parcelable, Filter { // we have written a valid value to the parcel. switch (this.type) { case BOOLEAN: - out.writeInt((Boolean) this.value ? 1 : 0); + out.writeBoolean((Boolean) this.value); break; case BYTE: out.writeByte((Byte) this.value); @@ -1413,10 +1335,7 @@ public class RemoteViews implements Parcelable, Filter { case INTENT: case COLOR_STATE_LIST: case ICON: - out.writeInt(this.value != null ? 1 : 0); - if (this.value != null) { - ((Parcelable) this.value).writeToParcel(out, flags); - } + out.writeTypedObject((Parcelable) this.value, flags); break; default: break; @@ -1522,10 +1441,16 @@ public class RemoteViews implements Parcelable, Filter { } } - public String getActionName() { + @Override + public int getActionTag() { + return REFLECTION_ACTION_TAG; + } + + @Override + public String getUniqueKey() { // Each type of reflection action corresponds to a setter, so each should be seen as // unique from the standpoint of merging. - return "ReflectionAction" + this.methodName + this.type; + return super.getUniqueKey() + this.methodName + this.type; } @Override @@ -1587,7 +1512,6 @@ public class RemoteViews implements Parcelable, Filter { } public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(VIEW_GROUP_ACTION_ADD_TAG); dest.writeInt(viewId); dest.writeInt(mIndex); mNestedViews.writeToParcel(dest, flags); @@ -1662,10 +1586,9 @@ public class RemoteViews implements Parcelable, Filter { return mNestedViews.prefersAsyncApply(); } - @Override - public String getActionName() { - return "ViewGroupActionAdd"; + public int getActionTag() { + return VIEW_GROUP_ACTION_ADD_TAG; } } @@ -1697,7 +1620,6 @@ public class RemoteViews implements Parcelable, Filter { } public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(VIEW_GROUP_ACTION_REMOVE_TAG); dest.writeInt(viewId); dest.writeInt(mViewIdToKeep); } @@ -1763,8 +1685,8 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public String getActionName() { - return "ViewGroupActionRemove"; + public int getActionTag() { + return VIEW_GROUP_ACTION_REMOVE_TAG; } @Override @@ -1804,18 +1726,10 @@ public class RemoteViews implements Parcelable, Filter { isRelative = (parcel.readInt() != 0); useIcons = (parcel.readInt() != 0); if (useIcons) { - if (parcel.readInt() != 0) { - i1 = Icon.CREATOR.createFromParcel(parcel); - } - if (parcel.readInt() != 0) { - i2 = Icon.CREATOR.createFromParcel(parcel); - } - if (parcel.readInt() != 0) { - i3 = Icon.CREATOR.createFromParcel(parcel); - } - if (parcel.readInt() != 0) { - i4 = Icon.CREATOR.createFromParcel(parcel); - } + i1 = parcel.readTypedObject(Icon.CREATOR); + i2 = parcel.readTypedObject(Icon.CREATOR); + i3 = parcel.readTypedObject(Icon.CREATOR); + i4 = parcel.readTypedObject(Icon.CREATOR); } else { d1 = parcel.readInt(); d2 = parcel.readInt(); @@ -1825,35 +1739,14 @@ public class RemoteViews implements Parcelable, Filter { } public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(TEXT_VIEW_DRAWABLE_ACTION_TAG); dest.writeInt(viewId); dest.writeInt(isRelative ? 1 : 0); dest.writeInt(useIcons ? 1 : 0); if (useIcons) { - if (i1 != null) { - dest.writeInt(1); - i1.writeToParcel(dest, 0); - } else { - dest.writeInt(0); - } - if (i2 != null) { - dest.writeInt(1); - i2.writeToParcel(dest, 0); - } else { - dest.writeInt(0); - } - if (i3 != null) { - dest.writeInt(1); - i3.writeToParcel(dest, 0); - } else { - dest.writeInt(0); - } - if (i4 != null) { - dest.writeInt(1); - i4.writeToParcel(dest, 0); - } else { - dest.writeInt(0); - } + dest.writeTypedObject(i1, 0); + dest.writeTypedObject(i2, 0); + dest.writeTypedObject(i3, 0); + dest.writeTypedObject(i4, 0); } else { dest.writeInt(d1); dest.writeInt(d2); @@ -1924,8 +1817,9 @@ public class RemoteViews implements Parcelable, Filter { return useIcons; } - public String getActionName() { - return "TextViewDrawableAction"; + @Override + public int getActionTag() { + return TEXT_VIEW_DRAWABLE_ACTION_TAG; } boolean isRelative = false; @@ -1954,7 +1848,6 @@ public class RemoteViews implements Parcelable, Filter { } public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(TEXT_VIEW_SIZE_ACTION_TAG); dest.writeInt(viewId); dest.writeInt(units); dest.writeFloat(size); @@ -1967,8 +1860,9 @@ public class RemoteViews implements Parcelable, Filter { target.setTextSize(units, size); } - public String getActionName() { - return "TextViewSizeAction"; + @Override + public int getActionTag() { + return TEXT_VIEW_SIZE_ACTION_TAG; } int units; @@ -1996,7 +1890,6 @@ public class RemoteViews implements Parcelable, Filter { } public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(VIEW_PADDING_ACTION_TAG); dest.writeInt(viewId); dest.writeInt(left); dest.writeInt(top); @@ -2011,8 +1904,9 @@ public class RemoteViews implements Parcelable, Filter { target.setPadding(left, top, right, bottom); } - public String getActionName() { - return "ViewPaddingAction"; + @Override + public int getActionTag() { + return VIEW_PADDING_ACTION_TAG; } int left, top, right, bottom; @@ -2029,6 +1923,9 @@ public class RemoteViews implements Parcelable, Filter { public static final int LAYOUT_WIDTH = 2; public static final int LAYOUT_MARGIN_BOTTOM_DIMEN = 3; + final int mProperty; + final int mValue; + /** * @param viewId ID of the view alter * @param property which layout parameter to alter @@ -2036,21 +1933,20 @@ public class RemoteViews implements Parcelable, Filter { */ public LayoutParamAction(int viewId, int property, int value) { this.viewId = viewId; - this.property = property; - this.value = value; + this.mProperty = property; + this.mValue = value; } public LayoutParamAction(Parcel parcel) { viewId = parcel.readInt(); - property = parcel.readInt(); - value = parcel.readInt(); + mProperty = parcel.readInt(); + mValue = parcel.readInt(); } public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(LAYOUT_PARAM_ACTION_TAG); dest.writeInt(viewId); - dest.writeInt(property); - dest.writeInt(value); + dest.writeInt(mProperty); + dest.writeInt(mValue); } @Override @@ -2063,27 +1959,27 @@ public class RemoteViews implements Parcelable, Filter { if (layoutParams == null) { return; } - switch (property) { + switch (mProperty) { case LAYOUT_MARGIN_END_DIMEN: if (layoutParams instanceof ViewGroup.MarginLayoutParams) { - int resolved = resolveDimenPixelOffset(target, value); + int resolved = resolveDimenPixelOffset(target, mValue); ((ViewGroup.MarginLayoutParams) layoutParams).setMarginEnd(resolved); target.setLayoutParams(layoutParams); } break; case LAYOUT_MARGIN_BOTTOM_DIMEN: if (layoutParams instanceof ViewGroup.MarginLayoutParams) { - int resolved = resolveDimenPixelOffset(target, value); + int resolved = resolveDimenPixelOffset(target, mValue); ((ViewGroup.MarginLayoutParams) layoutParams).bottomMargin = resolved; target.setLayoutParams(layoutParams); } break; case LAYOUT_WIDTH: - layoutParams.width = value; + layoutParams.width = mValue; target.setLayoutParams(layoutParams); break; default: - throw new IllegalArgumentException("Unknown property " + property); + throw new IllegalArgumentException("Unknown property " + mProperty); } } @@ -2094,79 +1990,15 @@ public class RemoteViews implements Parcelable, Filter { return target.getContext().getResources().getDimensionPixelOffset(value); } - public String getActionName() { - return "LayoutParamAction" + property + "."; - } - - int property; - int value; - } - - /** - * Helper action to set a color filter on a compound drawable on a TextView. Supports relative - * (s/t/e/b) or cardinal (l/t/r/b) arrangement. - */ - private class TextViewDrawableColorFilterAction extends Action { - public TextViewDrawableColorFilterAction(int viewId, boolean isRelative, int index, - int color, PorterDuff.Mode mode) { - this.viewId = viewId; - this.isRelative = isRelative; - this.index = index; - this.color = color; - this.mode = mode; - } - - public TextViewDrawableColorFilterAction(Parcel parcel) { - viewId = parcel.readInt(); - isRelative = (parcel.readInt() != 0); - index = parcel.readInt(); - color = parcel.readInt(); - mode = readPorterDuffMode(parcel); - } - - private PorterDuff.Mode readPorterDuffMode(Parcel parcel) { - int mode = parcel.readInt(); - if (mode >= 0 && mode < PorterDuff.Mode.values().length) { - return PorterDuff.Mode.values()[mode]; - } else { - return PorterDuff.Mode.CLEAR; - } - } - - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(TEXT_VIEW_DRAWABLE_COLOR_FILTER_ACTION_TAG); - dest.writeInt(viewId); - dest.writeInt(isRelative ? 1 : 0); - dest.writeInt(index); - dest.writeInt(color); - dest.writeInt(mode.ordinal()); - } - @Override - public void apply(View root, ViewGroup rootParent, OnClickHandler handler) { - final TextView target = root.findViewById(viewId); - if (target == null) return; - Drawable[] drawables = isRelative - ? target.getCompoundDrawablesRelative() - : target.getCompoundDrawables(); - if (index < 0 || index >= 4) { - throw new IllegalStateException("index must be in range [0, 3]."); - } - Drawable d = drawables[index]; - if (d != null) { - d.mutate(); - d.setColorFilter(color, mode); - } + public int getActionTag() { + return LAYOUT_PARAM_ACTION_TAG; } - public String getActionName() { - return "TextViewDrawableColorFilterAction"; + @Override + public String getUniqueKey() { + return super.getUniqueKey() + mProperty; } - - final boolean isRelative; - final int index; - final int color; - final PorterDuff.Mode mode; } /** @@ -2185,7 +2017,6 @@ public class RemoteViews implements Parcelable, Filter { } public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(SET_REMOTE_INPUTS_ACTION_TAG); dest.writeInt(viewId); dest.writeTypedArray(remoteInputs, flags); } @@ -2198,8 +2029,9 @@ public class RemoteViews implements Parcelable, Filter { target.setTagInternal(R.id.remote_input_tag, remoteInputs); } - public String getActionName() { - return "SetRemoteInputsAction"; + @Override + public int getActionTag() { + return SET_REMOTE_INPUTS_ACTION_TAG; } final Parcelable[] remoteInputs; @@ -2221,7 +2053,6 @@ public class RemoteViews implements Parcelable, Filter { } public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(OVERRIDE_TEXT_COLORS_TAG); dest.writeInt(textColor); } @@ -2246,8 +2077,9 @@ public class RemoteViews implements Parcelable, Filter { } } - public String getActionName() { - return "OverrideTextColorsAction"; + @Override + public int getActionTag() { + return OVERRIDE_TEXT_COLORS_TAG; } } @@ -2411,16 +2243,16 @@ public class RemoteViews implements Parcelable, Filter { switch (tag) { case SET_ON_CLICK_PENDING_INTENT_TAG: return new SetOnClickPendingIntent(parcel); - case SET_DRAWABLE_PARAMETERS_TAG: - return new SetDrawableParameters(parcel); + case SET_DRAWABLE_TINT_TAG: + return new SetDrawableTint(parcel); case REFLECTION_ACTION_TAG: return new ReflectionAction(parcel); case VIEW_GROUP_ACTION_ADD_TAG: return new ViewGroupActionAdd(parcel, mBitmapCache, mApplication, depth); case VIEW_GROUP_ACTION_REMOVE_TAG: return new ViewGroupActionRemove(parcel); - case SET_REFLECTION_ACTION_WITHOUT_PARAMS_TAG: - return new ReflectionActionWithoutParams(parcel); + case VIEW_CONTENT_NAVIGATION_TAG: + return new ViewContentNavigation(parcel); case SET_EMPTY_VIEW_ACTION_TAG: return new SetEmptyView(parcel); case SET_PENDING_INTENT_TEMPLATE_TAG: @@ -2439,8 +2271,6 @@ public class RemoteViews implements Parcelable, Filter { return new BitmapReflectionAction(parcel); case SET_REMOTE_VIEW_ADAPTER_LIST_TAG: return new SetRemoteViewsAdapterList(parcel); - case TEXT_VIEW_DRAWABLE_COLOR_FILTER_ACTION_TAG: - return new TextViewDrawableColorFilterAction(parcel); case SET_REMOTE_INPUTS_ACTION_TAG: return new SetRemoteInputsAction(parcel); case LAYOUT_PARAM_ACTION_TAG: @@ -2597,7 +2427,7 @@ public class RemoteViews implements Parcelable, Filter { * @param viewId The id of the view on which to call {@link AdapterViewAnimator#showNext()} */ public void showNext(int viewId) { - addAction(new ReflectionActionWithoutParams(viewId, "showNext")); + addAction(new ViewContentNavigation(viewId, true /* next */)); } /** @@ -2606,7 +2436,7 @@ public class RemoteViews implements Parcelable, Filter { * @param viewId The id of the view on which to call {@link AdapterViewAnimator#showPrevious()} */ public void showPrevious(int viewId) { - addAction(new ReflectionActionWithoutParams(viewId, "showPrevious")); + addAction(new ViewContentNavigation(viewId, false /* next */)); } /** @@ -2680,28 +2510,6 @@ public class RemoteViews implements Parcelable, Filter { } /** - * Equivalent to applying a color filter on one of the drawables in - * {@link android.widget.TextView#getCompoundDrawablesRelative()}. - * - * @param viewId The id of the view whose text should change. - * @param index The index of the drawable in the array of - * {@link android.widget.TextView#getCompoundDrawablesRelative()} to set the color - * filter on. Must be in [0, 3]. - * @param color The color of the color filter. See - * {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)}. - * @param mode The mode of the color filter. See - * {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)}. - * @hide - */ - public void setTextViewCompoundDrawablesRelativeColorFilter(int viewId, - int index, int color, PorterDuff.Mode mode) { - if (index < 0 || index >= 4) { - throw new IllegalArgumentException("index must be in range [0, 3]."); - } - addAction(new TextViewDrawableColorFilterAction(viewId, true, index, color, mode)); - } - - /** * Equivalent to calling {@link * TextView#setCompoundDrawablesWithIntrinsicBounds(Drawable, Drawable, Drawable, Drawable)} * using the drawables yielded by {@link Icon#loadDrawable(Context)}. @@ -2898,12 +2706,10 @@ public class RemoteViews implements Parcelable, Filter { /** * @hide - * Equivalent to calling a combination of {@link Drawable#setAlpha(int)}, + * Equivalent to calling * {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)}, - * and/or {@link Drawable#setLevel(int)} on the {@link Drawable} of a given - * view. + * on the {@link Drawable} of a given view. * <p> - * You can omit specific calls by marking their values with null or -1. * * @param viewId The id of the view that contains the target * {@link Drawable} @@ -2912,20 +2718,15 @@ public class RemoteViews implements Parcelable, Filter { * {@link android.view.View#getBackground()}. Otherwise, assume * the target view is an {@link ImageView} and apply them to * {@link ImageView#getDrawable()}. - * @param alpha Specify an alpha value for the drawable, or -1 to leave - * unchanged. * @param colorFilter Specify a color for a * {@link android.graphics.ColorFilter} for this drawable. This will be ignored if * {@code mode} is {@code null}. * @param mode Specify a PorterDuff mode for this drawable, or null to leave * unchanged. - * @param level Specify the level for the drawable, or -1 to leave - * unchanged. */ - public void setDrawableParameters(int viewId, boolean targetBackground, int alpha, - int colorFilter, PorterDuff.Mode mode, int level) { - addAction(new SetDrawableParameters(viewId, targetBackground, alpha, - colorFilter, mode, level)); + public void setDrawableTint(int viewId, boolean targetBackground, + int colorFilter, @NonNull PorterDuff.Mode mode) { + addAction(new SetDrawableTint(viewId, targetBackground, colorFilter, mode)); } /** @@ -3717,6 +3518,7 @@ public class RemoteViews implements Parcelable, Filter { parcel.writeInt(count); for (int i = 0; i < count; i++) { Action a = mActions.get(i); + parcel.writeInt(a.getActionTag()); a.writeToParcel(parcel, a.hasSameAppInfo(mApplication) ? PARCELABLE_ELIDE_DUPLICATES : 0); } diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp index 7442fa2d62dc..9afb7f3ed444 100644 --- a/core/jni/android_text_StaticLayout.cpp +++ b/core/jni/android_text_StaticLayout.cpp @@ -87,7 +87,8 @@ class JNILineBreakerLineWidth : public minikin::LineBreaker::LineWidthDelegate { static void nSetupParagraph(JNIEnv* env, jclass, jlong nativePtr, jcharArray text, jint length, jfloat firstWidth, jint firstWidthLineLimit, jfloat restWidth, jintArray variableTabStops, jint defaultTabStop, jint strategy, jint hyphenFrequency, - jboolean isJustified, jintArray indents, jint indentsOffset) { + jboolean isJustified, jintArray indents, jintArray leftPaddings, jintArray rightPaddings, + jint indentsOffset) { minikin::LineBreaker* b = reinterpret_cast<minikin::LineBreaker*>(nativePtr); b->resize(length); env->GetCharArrayRegion(text, 0, length, b->buffer()); @@ -187,24 +188,9 @@ static jlong nLoadHyphenator(JNIEnv* env, jclass, jobject buffer, jint offset, return reinterpret_cast<jlong>(hyphenator); } -static void nSetLocales(JNIEnv* env, jclass, jlong nativePtr, jstring javaLocaleNames, - jlongArray nativeHyphenators) { - minikin::LineBreaker* b = reinterpret_cast<minikin::LineBreaker*>(nativePtr); - - ScopedUtfChars localeNames(env, javaLocaleNames); - ScopedLongArrayRO hyphArr(env, nativeHyphenators); - const size_t numLocales = hyphArr.size(); - std::vector<minikin::Hyphenator*> hyphVec; - hyphVec.reserve(numLocales); - for (size_t i = 0; i < numLocales; i++) { - hyphVec.push_back(reinterpret_cast<minikin::Hyphenator*>(hyphArr[i])); - } - b->setLocales(localeNames.c_str(), hyphVec); -} - // Basically similar to Paint.getTextRunAdvances but with C++ interface static jfloat nAddStyleRun(JNIEnv* env, jclass, jlong nativePtr, jlong nativePaint, jint start, - jint end, jboolean isRtl) { + jint end, jboolean isRtl, jstring langTags, jlongArray hyphenators) { minikin::LineBreaker* b = reinterpret_cast<minikin::LineBreaker*>(nativePtr); Paint* paint = reinterpret_cast<Paint*>(nativePaint); const Typeface* typeface = paint->getAndroidTypeface(); @@ -212,8 +198,26 @@ static jfloat nAddStyleRun(JNIEnv* env, jclass, jlong nativePtr, jlong nativePai const Typeface* resolvedTypeface = Typeface::resolveDefault(typeface); minikin::FontStyle style = MinikinUtils::prepareMinikinPaint(&minikinPaint, paint, typeface); - return b->addStyleRun(&minikinPaint, resolvedTypeface->fFontCollection, style, start, end, - isRtl); + + std::vector<minikin::Hyphenator*> hyphVec; + const char* langTagStr; + if (langTags == nullptr) { + langTagStr = nullptr; // nullptr languageTag means keeping current locale + } else { + ScopedLongArrayRO hyphArr(env, hyphenators); + const size_t numLocales = hyphArr.size(); + hyphVec.reserve(numLocales); + for (size_t i = 0; i < numLocales; i++) { + hyphVec.push_back(reinterpret_cast<minikin::Hyphenator*>(hyphArr[i])); + } + langTagStr = env->GetStringUTFChars(langTags, nullptr); + } + float result = b->addStyleRun(&minikinPaint, resolvedTypeface->fFontCollection, style, start, + end, isRtl, langTagStr, hyphVec); + if (langTagStr != nullptr) { + env->ReleaseStringUTFChars(langTags, langTagStr); + } + return result; } // Accept width measurements for the run, passed in from Java @@ -221,7 +225,8 @@ static void nAddMeasuredRun(JNIEnv* env, jclass, jlong nativePtr, jint start, jint end, jfloatArray widths) { minikin::LineBreaker* b = reinterpret_cast<minikin::LineBreaker*>(nativePtr); env->GetFloatArrayRegion(widths, start, end - start, b->charWidths() + start); - b->addStyleRun(nullptr, nullptr, minikin::FontStyle{}, start, end, false); + b->addStyleRun(nullptr, nullptr, minikin::FontStyle{}, start, end, false, + nullptr /* keep current locale */, std::vector<minikin::Hyphenator*>()); } static void nAddReplacementRun(JNIEnv* env, jclass, jlong nativePtr, @@ -241,9 +246,8 @@ static const JNINativeMethod gMethods[] = { {"nFreeBuilder", "(J)V", (void*) nFreeBuilder}, {"nFinishBuilder", "(J)V", (void*) nFinishBuilder}, {"nLoadHyphenator", "(Ljava/nio/ByteBuffer;III)J", (void*) nLoadHyphenator}, - {"nSetLocales", "(JLjava/lang/String;[J)V", (void*) nSetLocales}, - {"nSetupParagraph", "(J[CIFIF[IIIIZ[II)V", (void*) nSetupParagraph}, - {"nAddStyleRun", "(JJIIZ)F", (void*) nAddStyleRun}, + {"nSetupParagraph", "(J[CIFIF[IIIIZ[I[I[II)V", (void*) nSetupParagraph}, + {"nAddStyleRun", "(JJIIZLjava/lang/String;[J)F", (void*) nAddStyleRun}, {"nAddMeasuredRun", "(JII[F)V", (void*) nAddMeasuredRun}, {"nAddReplacementRun", "(JIIF)V", (void*) nAddReplacementRun}, {"nGetWidths", "(J[F)V", (void*) nGetWidths}, diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto index bce10dc2e2fb..15c547f0196c 100644 --- a/core/proto/android/os/incident.proto +++ b/core/proto/android/os/incident.proto @@ -78,7 +78,10 @@ message IncidentProto { (section).type = SECTION_DUMPSYS, (section).args = "notification --proto" ]; - android.service.battery.BatteryServiceDumpProto battery = 3006; + android.service.battery.BatteryServiceDumpProto battery = 3006 [ + (section).type = SECTION_DUMPSYS, + (section).args = "battery --proto" + ]; android.service.diskstats.DiskStatsServiceDumpProto diskstats = 3007; android.service.pm.PackageServiceDumpProto package = 3008; android.service.power.PowerServiceDumpProto power = 3009; diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 7416113b4e90..afcb35feaedd 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -2709,6 +2709,8 @@ <string name="yes">OK</string> <!-- Preference framework strings. --> <string name="no">Cancel</string> + <!-- Preference framework strings. --> + <string name="close">CLOSE</string> <!-- This is the generic "attention" string to be used in attention dialogs. Typically combined with setIconAttribute(android.R.attr.alertDialogIcon) (or setIcon(android.R.drawable.ic_dialog_alert) on legacy versions of the platform) --> @@ -2841,6 +2843,11 @@ <!-- [CHAR LIMIT=200] Compat mode dialog: hint to re-enable compat mode dialog. --> <string name="screen_compat_mode_hint">Re-enable this in System settings > Apps > Downloaded.</string> + <!-- Text of the alert that is displayed when a top application is killed by lmk. --> + <string name="top_app_killed_title">App isn\'t responding</string> + <!-- Top app killed by lmk dialog message. --> + <string name="top_app_killed_message"><xliff:g id="app_name">%1$s</xliff:g> may be using too much memory.</string> + <!-- [CHAR LIMIT=200] Unsupported display size dialog: message. Refers to "Display size" setting. --> <string name="unsupported_display_size_message"><xliff:g id="app_name">%1$s</xliff:g> does not support the current Display size setting and may behave unexpectedly.</string> <!-- [CHAR LIMIT=50] Unsupported display size dialog: check box label. --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 4f03e7b06d97..96695538b7ce 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1893,6 +1893,9 @@ <java-symbol type="string" name="anr_application_process" /> <java-symbol type="string" name="anr_process" /> <java-symbol type="string" name="anr_title" /> + <java-symbol type="string" name="top_app_killed_title" /> + <java-symbol type="string" name="top_app_killed_message" /> + <java-symbol type="string" name="close" /> <java-symbol type="string" name="car_mode_disable_notification_message" /> <java-symbol type="string" name="car_mode_disable_notification_title" /> <java-symbol type="string" name="chooser_wallpaper" /> diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java index 0209cea4e2e5..40288f5ec8af 100644 --- a/graphics/java/android/graphics/Shader.java +++ b/graphics/java/android/graphics/Shader.java @@ -159,8 +159,10 @@ public class Shader { if (mNativeInstance == 0) { mNativeInstance = createNativeInstance(mLocalMatrix == null ? 0 : mLocalMatrix.native_instance); - mCleaner = NoImagePreloadHolder.sRegistry.registerNativeAllocation( - this, mNativeInstance); + if (mNativeInstance != 0) { + mCleaner = NoImagePreloadHolder.sRegistry.registerNativeAllocation( + this, mNativeInstance); + } } return mNativeInstance; } diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp index 17438e5e1cdc..5c6078d566b4 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.cpp +++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp @@ -36,22 +36,18 @@ void LayerDrawable::onDraw(SkCanvas* canvas) { bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer) { // transform the matrix based on the layer - int saveCount = -1; - if (!layer->getTransform().isIdentity()) { - saveCount = canvas->save(); - SkMatrix transform; - layer->getTransform().copyTo(transform); - canvas->concat(transform); - } - + SkMatrix layerTransform; + layer->getTransform().copyTo(layerTransform); sk_sp<SkImage> layerImage; + int layerWidth = layer->getWidth(); + int layerHeight = layer->getHeight(); if (layer->getApi() == Layer::Api::OpenGL) { GlLayer* glLayer = static_cast<GlLayer*>(layer); GrGLTextureInfo externalTexture; externalTexture.fTarget = glLayer->getRenderTarget(); externalTexture.fID = glLayer->getTextureId(); - GrBackendTexture backendTexture(glLayer->getWidth(), glLayer->getHeight(), - kRGBA_8888_GrPixelConfig, externalTexture); + GrBackendTexture backendTexture(layerWidth, layerHeight, kRGBA_8888_GrPixelConfig, + externalTexture); layerImage = SkImage::MakeFromTexture(context, backendTexture, kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, nullptr); } else { @@ -62,15 +58,29 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer } if (layerImage) { + SkMatrix textureMatrix; + layer->getTexTransform().copyTo(textureMatrix); + //TODO: after skia bug https://bugs.chromium.org/p/skia/issues/detail?id=7075 is fixed + // use bottom left origin and remove flipV and invert transformations. + SkMatrix flipV; + flipV.setAll(1, 0, 0, 0, -1, 1, 0, 0, 1); + textureMatrix.preConcat(flipV); + textureMatrix.preScale(1.0f/layerWidth, 1.0f/layerHeight); + textureMatrix.postScale(layerWidth, layerHeight); + SkMatrix textureMatrixInv; + if (!textureMatrix.invert(&textureMatrixInv)) { + textureMatrixInv = textureMatrix; + } + + SkMatrix matrix = SkMatrix::Concat(textureMatrixInv, layerTransform); + SkPaint paint; paint.setAlpha(layer->getAlpha()); paint.setBlendMode(layer->getMode()); paint.setColorFilter(sk_ref_sp(layer->getColorFilter())); - canvas->drawImage(layerImage, 0, 0, &paint); - } - // restore the original matrix - if (saveCount >= 0) { - canvas->restoreToCount(saveCount); + // draw image with a shader to avoid save/restore of the matrix + paint.setShader(layerImage->makeShader(&matrix)); + canvas->drawRect(SkRect::MakeWH(layerWidth, layerHeight), paint); } return layerImage; diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java index 40c2b1f3b771..fa2499f6c144 100644 --- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java +++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java @@ -52,6 +52,11 @@ import android.util.SparseArray; import com.android.internal.R; import com.android.internal.util.ArrayUtils; +import com.android.settingslib.core.lifecycle.Lifecycle; +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnDestroy; +import com.android.settingslib.core.lifecycle.events.OnPause; +import com.android.settingslib.core.lifecycle.events.OnResume; import java.io.File; import java.io.IOException; @@ -180,7 +185,11 @@ public class ApplicationsState { } public Session newSession(Callbacks callbacks) { - Session s = new Session(callbacks); + return newSession(callbacks, null); + } + + public Session newSession(Callbacks callbacks, Lifecycle lifecycle) { + Session s = new Session(callbacks, lifecycle); synchronized (mEntriesMap) { mSessions.add(s); } @@ -586,7 +595,7 @@ public class ApplicationsState { .replaceAll("").toLowerCase(); } - public class Session { + public class Session implements LifecycleObserver, OnPause, OnResume, OnDestroy { final Callbacks mCallbacks; boolean mResumed; @@ -600,11 +609,19 @@ public class ApplicationsState { ArrayList<AppEntry> mLastAppList; boolean mRebuildForeground; - Session(Callbacks callbacks) { + private final boolean mHasLifecycle; + + Session(Callbacks callbacks, Lifecycle lifecycle) { mCallbacks = callbacks; + if (lifecycle != null) { + lifecycle.addObserver(this); + mHasLifecycle = true; + } else { + mHasLifecycle = false; + } } - public void resume() { + public void onResume() { if (DEBUG_LOCKING) Log.v(TAG, "resume about to acquire lock..."); synchronized (mEntriesMap) { if (!mResumed) { @@ -616,7 +633,7 @@ public class ApplicationsState { if (DEBUG_LOCKING) Log.v(TAG, "...resume releasing lock"); } - public void pause() { + public void onPause() { if (DEBUG_LOCKING) Log.v(TAG, "pause about to acquire lock..."); synchronized (mEntriesMap) { if (mResumed) { @@ -735,8 +752,11 @@ public class ApplicationsState { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); } - public void release() { - pause(); + public void onDestroy() { + if (!mHasLifecycle) { + // TODO: Legacy, remove this later once all usages are switched to Lifecycle + onPause(); + } synchronized (mEntriesMap) { mSessions.remove(this); } diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java index 44e60eed8c7c..a41fd22d4c0b 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java @@ -64,6 +64,7 @@ import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.recents.Recents; import com.android.systemui.recents.events.EventBus; +import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent; import com.android.systemui.recents.events.activity.DockedTopTaskEvent; import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent; import com.android.systemui.recents.events.activity.UndockingTaskEvent; @@ -1192,6 +1193,10 @@ public class DividerView extends FrameLayout implements OnTouchListener, } } + public final void onBusEvent(DockedFirstAnimationFrameEvent event) { + saveSnapTargetBeforeMinimized(mSnapAlgorithm.getMiddleTarget()); + } + public final void onBusEvent(DockedTopTaskEvent event) { if (event.dragMode == NavigationBarGestureHelper.DRAG_MODE_NONE) { mState.growAfterRecentsDrawn = false; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index cfe0a4a6005b..6d3bc1df00a2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -437,7 +437,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks { } private boolean onNavigationTouch(View v, MotionEvent event) { - mStatusBar.checkUserAutohide(v, event); + mStatusBar.checkUserAutohide(event); return false; } 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 67500bf4217d..274c024407bb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -69,9 +69,6 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.ColorFilter; -import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.PointF; import android.graphics.PorterDuff; @@ -108,7 +105,6 @@ import android.service.notification.NotificationListenerService.RankingMap; import android.service.notification.StatusBarNotification; import android.service.vr.IVrManager; import android.service.vr.IVrStateCallbacks; -import android.text.TextUtils; import android.util.ArraySet; import android.util.DisplayMetrics; import android.util.EventLog; @@ -127,13 +123,11 @@ import android.view.View; import android.view.ViewAnimationUtils; import android.view.ViewGroup; import android.view.ViewParent; -import android.view.ViewStub; import android.view.ViewTreeObserver; import android.view.WindowManager; import android.view.WindowManagerGlobal; import android.view.accessibility.AccessibilityManager; import android.view.animation.AccelerateInterpolator; -import android.view.animation.Interpolator; import android.widget.DateTimeView; import android.widget.ImageView; import android.widget.RemoteViews; @@ -259,7 +253,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.Stack; @@ -279,11 +272,9 @@ public class StatusBar extends SystemUI implements DemoMode, = SystemProperties.getBoolean("debug.child_notifs", true); public static final boolean FORCE_REMOTE_INPUT_HISTORY = SystemProperties.getBoolean("debug.force_remoteinput_history", false); - private static boolean ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT = false; + private static final boolean ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT = false; - protected static final int MSG_SHOW_RECENT_APPS = 1019; protected static final int MSG_HIDE_RECENT_APPS = 1020; - protected static final int MSG_TOGGLE_RECENTS_APPS = 1021; protected static final int MSG_PRELOAD_RECENT_APPS = 1022; protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023; protected static final int MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU = 1026; @@ -365,10 +356,6 @@ public class StatusBar extends SystemUI implements DemoMode, /** If true, the lockscreen will show a distinct wallpaper */ private static final boolean ENABLE_LOCKSCREEN_WALLPAPER = true; - /* If true, the device supports freeform window management. - * This affects the status bar UI. */ - private static final boolean FREEFORM_WINDOW_MANAGEMENT; - /** * How long to wait before auto-dismissing a notification that was kept for remote input, and * has now sent a remote input. We auto-dismiss, because the app may not see a reason to cancel @@ -387,19 +374,14 @@ public class StatusBar extends SystemUI implements DemoMode, static { boolean onlyCoreApps; - boolean freeformWindowManagement; try { IPackageManager packageManager = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); onlyCoreApps = packageManager.isOnlyCoreApps(); - freeformWindowManagement = packageManager.hasSystemFeature( - PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT, 0); } catch (RemoteException e) { onlyCoreApps = false; - freeformWindowManagement = false; } ONLY_CORE_APPS = onlyCoreApps; - FREEFORM_WINDOW_MANAGEMENT = freeformWindowManagement; } /** @@ -410,17 +392,17 @@ public class StatusBar extends SystemUI implements DemoMode, protected boolean mShowLockscreenNotifications; protected boolean mAllowLockscreenRemoteInput; - PhoneStatusBarPolicy mIconPolicy; + private PhoneStatusBarPolicy mIconPolicy; - VolumeComponent mVolumeComponent; - BrightnessMirrorController mBrightnessMirrorController; + private VolumeComponent mVolumeComponent; + private BrightnessMirrorController mBrightnessMirrorController; protected FingerprintUnlockController mFingerprintUnlockController; - LightBarController mLightBarController; + private LightBarController mLightBarController; protected LockscreenWallpaper mLockscreenWallpaper; - int mNaturalBarHeight = -1; + private int mNaturalBarHeight = -1; - Point mCurrentDisplaySize = new Point(); + private final Point mCurrentDisplaySize = new Point(); protected StatusBarWindowView mStatusBarWindow; protected PhoneStatusBarView mStatusBarView; @@ -431,15 +413,13 @@ public class StatusBar extends SystemUI implements DemoMode, private boolean mWakeUpComingFromTouch; private PointF mWakeUpTouchLocation; - int mPixelFormat; - Object mQueueLock = new Object(); + private final Object mQueueLock = new Object(); protected StatusBarIconController mIconController; // expanded notifications protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window - View mExpandedContents; - TextView mNotificationPanelDebugText; + private TextView mNotificationPanelDebugText; /** * {@code true} if notifications not part of a group should by default be rendered in their @@ -452,12 +432,10 @@ public class StatusBar extends SystemUI implements DemoMode, private QSPanel mQSPanel; // top bar - protected KeyguardStatusBarView mKeyguardStatusBar; - boolean mLeaveOpenOnKeyguardHide; + private KeyguardStatusBarView mKeyguardStatusBar; + private boolean mLeaveOpenOnKeyguardHide; KeyguardIndicationController mKeyguardIndicationController; - // Keyguard is going away soon. - private boolean mKeyguardGoingAway; // Keyguard is actually fading away now. protected boolean mKeyguardFadingAway; protected long mKeyguardFadingAwayDelay; @@ -469,25 +447,19 @@ public class StatusBar extends SystemUI implements DemoMode, private View mReportRejectedTouch; - int mMaxAllowedKeyguardNotifications; - - boolean mExpandedVisible; - - // the tracker view - int mTrackingPosition; // the position of the top of the tracking view. + private int mMaxAllowedKeyguardNotifications; - // Tracking finger for opening/closing. - boolean mTracking; + private boolean mExpandedVisible; - int[] mAbsPos = new int[2]; - ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>(); + private final int[] mAbsPos = new int[2]; + private final ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>(); // for disabling the status bar - int mDisabled1 = 0; - int mDisabled2 = 0; + private int mDisabled1 = 0; + private int mDisabled2 = 0; // tracking calls to View.setSystemUiVisibility() - int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE; + private int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE; private final Rect mLastFullscreenStackBounds = new Rect(); private final Rect mLastDockedStackBounds = new Rect(); private final Rect mTmpRect = new Rect(); @@ -495,7 +467,7 @@ public class StatusBar extends SystemUI implements DemoMode, // last value sent to window manager private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE; - DisplayMetrics mDisplayMetrics = new DisplayMetrics(); + private final DisplayMetrics mDisplayMetrics = new DisplayMetrics(); // XXX: gesture research private final GestureRecorder mGestureRec = DEBUG_GESTURES @@ -508,13 +480,15 @@ public class StatusBar extends SystemUI implements DemoMode, // ensure quick settings is disabled until the current user makes it through the setup wizard private boolean mUserSetup = false; - private DeviceProvisionedListener mUserSetupObserver = new DeviceProvisionedListener() { + private final DeviceProvisionedListener mUserSetupObserver = new DeviceProvisionedListener() { @Override public void onUserSetupChanged() { final boolean userSetup = mDeviceProvisionedController.isUserSetup( mDeviceProvisionedController.getCurrentUser()); - if (MULTIUSER_DEBUG) Log.d(TAG, String.format("User setup changed: " + - "userSetup=%s mUserSetup=%s", userSetup, mUserSetup)); + if (MULTIUSER_DEBUG) { + Log.d(TAG, String.format("User setup changed: userSetup=%s mUserSetup=%s", + userSetup, mUserSetup)); + } if (userSetup != mUserSetup) { mUserSetup = userSetup; @@ -528,7 +502,7 @@ public class StatusBar extends SystemUI implements DemoMode, } }; - protected H mHandler = createHandler(); + protected final H mHandler = createHandler(); final private ContentObserver mHeadsUpObserver = new ContentObserver(mHandler) { @Override public void onChange(boolean selfChange) { @@ -537,8 +511,6 @@ public class StatusBar extends SystemUI implements DemoMode, && Settings.Global.HEADS_UP_OFF != Settings.Global.getInt( mContext.getContentResolver(), Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED, Settings.Global.HEADS_UP_OFF); - mHeadsUpTicker = mUseHeadsUp && 0 != Settings.Global.getInt( - mContext.getContentResolver(), SETTING_HEADS_UP_TICKER, 0); Log.d(TAG, "heads up is " + (mUseHeadsUp ? "enabled" : "disabled")); if (wasUsing != mUseHeadsUp) { if (!mUseHeadsUp) { @@ -566,26 +538,21 @@ public class StatusBar extends SystemUI implements DemoMode, } }; - private boolean mWaitingForKeyguardExit; protected boolean mDozing; private boolean mDozingRequested; protected boolean mScrimSrcModeEnabled; - public static final Interpolator ALPHA_IN = Interpolators.ALPHA_IN; - public static final Interpolator ALPHA_OUT = Interpolators.ALPHA_OUT; - protected BackDropView mBackdrop; protected ImageView mBackdropFront, mBackdropBack; - protected PorterDuffXfermode mSrcXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC); - protected PorterDuffXfermode mSrcOverXferMode = + protected final PorterDuffXfermode mSrcXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC); + protected final PorterDuffXfermode mSrcOverXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER); private MediaSessionManager mMediaSessionManager; private MediaController mMediaController; private String mMediaNotificationKey; private MediaMetadata mMediaMetadata; - private MediaController.Callback mMediaListener - = new MediaController.Callback() { + private final MediaController.Callback mMediaListener = new MediaController.Callback() { @Override public void onPlaybackStateChanged(PlaybackState state) { super.onPlaybackStateChanged(state); @@ -607,17 +574,6 @@ public class StatusBar extends SystemUI implements DemoMode, } }; - private final OnChildLocationsChangedListener mOnChildLocationsChangedListener = - new OnChildLocationsChangedListener() { - @Override - public void onChildLocationsChanged(NotificationStackScrollLayout stackScrollLayout) { - userActivity(); - } - }; - - private int mDisabledUnmodified1; - private int mDisabledUnmodified2; - /** Keys of notifications currently visible to the user. */ private final ArraySet<NotificationVisibility> mCurrentlyVisibleNotifications = new ArraySet<>(); @@ -644,15 +600,6 @@ public class StatusBar extends SystemUI implements DemoMode, private boolean mWereIconsJustHidden; private boolean mBouncerWasShowingWhenHidden; - public boolean isStartedGoingToSleep() { - return mStartedGoingToSleep; - } - - /** - * If set, the device has started going to sleep but isn't fully non-interactive yet. - */ - protected boolean mStartedGoingToSleep; - private final OnChildLocationsChangedListener mNotificationLocationsChangedListener = new OnChildLocationsChangedListener() { @Override @@ -686,7 +633,6 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void run() { mLastVisibilityReportUptimeMs = SystemClock.uptimeMillis(); - final String mediaKey = getCurrentMediaNotificationKey(); // 1. Loop over mNotificationData entries: // A. Keep list of visible notifications. @@ -743,10 +689,10 @@ public class StatusBar extends SystemUI implements DemoMode, private boolean mKeyguardRequested; private boolean mIsKeyguard; private LogMaker mStatusBarStateLog; - private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger(); + private final LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger(); protected NotificationIconAreaController mNotificationIconAreaController; private boolean mReinflateNotificationsOnUserSwitched; - private HashMap<String, Entry> mPendingNotifications = new HashMap<>(); + private final HashMap<String, Entry> mPendingNotifications = new HashMap<>(); private boolean mClearAllEnabled; @Nullable private View mAmbientIndicationContainer; private String mKeyToRemoveOnGutsClosed; @@ -769,20 +715,21 @@ public class StatusBar extends SystemUI implements DemoMode, goToLockedShade(null); } }; - private HashMap<ExpandableNotificationRow, List<ExpandableNotificationRow>> mTmpChildOrderMap - = new HashMap<>(); + private final HashMap<ExpandableNotificationRow, List<ExpandableNotificationRow>> + mTmpChildOrderMap = new HashMap<>(); private RankingMap mLatestRankingMap; private boolean mNoAnimationOnNextBarModeChange; private FalsingManager mFalsingManager; - private KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() { - @Override - public void onDreamingStateChanged(boolean dreaming) { - if (dreaming) { - maybeEscalateHeadsUp(); - } - } - }; + private final KeyguardUpdateMonitorCallback mUpdateCallback = + new KeyguardUpdateMonitorCallback() { + @Override + public void onDreamingStateChanged(boolean dreaming) { + if (dreaming) { + maybeEscalateHeadsUp(); + } + } + }; private NavigationBarFragment mNavigationBar; private View mNavigationBarView; @@ -861,10 +808,6 @@ public class StatusBar extends SystemUI implements DemoMode, mRecents = getComponent(Recents.class); - final Configuration currentConfig = res.getConfiguration(); - mLocale = currentConfig.locale; - mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale); - mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); mLockPatternUtils = new LockPatternUtils(mContext); @@ -994,9 +937,6 @@ public class StatusBar extends SystemUI implements DemoMode, Dependency.get(ConfigurationController.class).addCallback(this); } - protected void createIconController() { - } - // ================================================================================ // Constructing the view // ================================================================================ @@ -1012,16 +952,14 @@ public class StatusBar extends SystemUI implements DemoMode, // TODO: Deal with the ugliness that comes from having some of the statusbar broken out // into fragments, but the rest here, it leaves some awkward lifecycle and whatnot. - mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById( - R.id.notification_panel); - mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById( - R.id.notification_stack_scroller); + mNotificationPanel = mStatusBarWindow.findViewById(R.id.notification_panel); + mStackScroller = mStatusBarWindow.findViewById(R.id.notification_stack_scroller); mNotificationPanel.setStatusBar(this); mNotificationPanel.setGroupManager(mGroupManager); mAboveShelfObserver = new AboveShelfObserver(mStackScroller); mAboveShelfObserver.setListener(mStatusBarWindow.findViewById( R.id.notification_container_parent)); - mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header); + mKeyguardStatusBar = mStatusBarWindow.findViewById(R.id.keyguard_header); mNotificationIconAreaController = SystemUIFactory.getInstance() .createNotificationIconAreaController(context, this); @@ -1060,8 +998,7 @@ public class StatusBar extends SystemUI implements DemoMode, putComponent(HeadsUpManager.class, mHeadsUpManager); if (MULTIUSER_DEBUG) { - mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById( - R.id.header_debug_info); + mNotificationPanelDebugText = mNotificationPanel.findViewById(R.id.header_debug_info); mNotificationPanelDebugText.setVisibility(View.VISIBLE); } @@ -1075,9 +1012,6 @@ public class StatusBar extends SystemUI implements DemoMode, // no window manager? good luck with that } - // figure out which pixel-format to use for the status bar. - mPixelFormat = PixelFormat.OPAQUE; - mStackScroller.setLongPressListener(getNotificationLongClicker()); mStackScroller.setStatusBar(this); mStackScroller.setGroupManager(mGroupManager); @@ -1087,11 +1021,10 @@ public class StatusBar extends SystemUI implements DemoMode, inflateEmptyShadeView(); inflateDismissView(); - mExpandedContents = mStackScroller; - mBackdrop = (BackDropView) mStatusBarWindow.findViewById(R.id.backdrop); - mBackdropFront = (ImageView) mBackdrop.findViewById(R.id.backdrop_front); - mBackdropBack = (ImageView) mBackdrop.findViewById(R.id.backdrop_back); + mBackdrop = mStatusBarWindow.findViewById(R.id.backdrop); + mBackdropFront = mBackdrop.findViewById(R.id.backdrop_front); + mBackdropBack = mBackdrop.findViewById(R.id.backdrop_back); if (ENABLE_LOCKSCREEN_WALLPAPER) { mLockscreenWallpaper = new LockscreenWallpaper(mContext, this, mHandler); @@ -1099,8 +1032,8 @@ public class StatusBar extends SystemUI implements DemoMode, mKeyguardIndicationController = SystemUIFactory.getInstance().createKeyguardIndicationController(mContext, - (ViewGroup) mStatusBarWindow.findViewById(R.id.keyguard_indication_area), - mNotificationPanel.getLockIcon()); + mStatusBarWindow.findViewById(R.id.keyguard_indication_area), + mNotificationPanel.getLockIcon()); mNotificationPanel.setKeyguardIndicationController(mKeyguardIndicationController); @@ -1131,8 +1064,8 @@ public class StatusBar extends SystemUI implements DemoMode, mNavigationBar.setLightBarController(mLightBarController); } - ScrimView scrimBehind = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_behind); - ScrimView scrimInFront = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_in_front); + ScrimView scrimBehind = mStatusBarWindow.findViewById(R.id.scrim_behind); + ScrimView scrimInFront = mStatusBarWindow.findViewById(R.id.scrim_in_front); View headsUpScrim = mStatusBarWindow.findViewById(R.id.heads_up_scrim); mScrimController = SystemUIFactory.getInstance().createScrimController(mLightBarController, scrimBehind, scrimInFront, headsUpScrim, mLockscreenWallpaper, @@ -1142,13 +1075,10 @@ public class StatusBar extends SystemUI implements DemoMode, } }); if (mScrimSrcModeEnabled) { - Runnable runnable = new Runnable() { - @Override - public void run() { - boolean asSrc = mBackdrop.getVisibility() != View.VISIBLE; - mScrimController.setDrawBehindAsSrc(asSrc); - mStackScroller.setDrawBackgroundAsSrc(asSrc); - } + Runnable runnable = () -> { + boolean asSrc = mBackdrop.getVisibility() != View.VISIBLE; + mScrimController.setDrawBehindAsSrc(asSrc); + mStackScroller.setDrawBackgroundAsSrc(asSrc); }; mBackdrop.setOnVisibilityChangedRunnable(runnable); runnable.run(); @@ -1170,11 +1100,11 @@ public class StatusBar extends SystemUI implements DemoMode, if (container != null) { FragmentHostManager fragmentHostManager = FragmentHostManager.get(container); ExtensionFragmentListener.attachExtensonToFragment(container, QS.TAG, R.id.qs_frame, - Dependency.get(ExtensionController.class).newExtension(QS.class) + Dependency.get(ExtensionController.class) + .newExtension(QS.class) .withPlugin(QS.class) - .withFeature( - PackageManager.FEATURE_AUTOMOTIVE, () -> new CarQSFragment()) - .withDefault(() -> new QSFragment()) + .withFeature(PackageManager.FEATURE_AUTOMOTIVE, CarQSFragment::new) + .withDefault(QSFragment::new) .build()); final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this, mIconController); @@ -1276,7 +1206,7 @@ public class StatusBar extends SystemUI implements DemoMode, */ protected View.OnTouchListener getStatusBarWindowTouchListener() { return (v, event) -> { - checkUserAutohide(v, event); + checkUserAutohide(event); checkRemoteInputOutside(event); if (event.getAction() == MotionEvent.ACTION_DOWN) { if (mExpandedVisible) { @@ -1380,8 +1310,7 @@ public class StatusBar extends SystemUI implements DemoMode, public static SignalClusterView reinflateSignalCluster(View view) { Context context = view.getContext(); - SignalClusterView signalCluster = - (SignalClusterView) view.findViewById(R.id.signal_cluster); + SignalClusterView signalCluster = view.findViewById(R.id.signal_cluster); if (signalCluster != null) { ViewParent parent = signalCluster.getParent(); if (parent instanceof ViewGroup) { @@ -1421,20 +1350,17 @@ public class StatusBar extends SystemUI implements DemoMode, mDismissView = (DismissView) LayoutInflater.from(mContext).inflate( R.layout.status_bar_notification_dismiss_all, mStackScroller, false); - mDismissView.setOnButtonClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - mMetricsLogger.action(MetricsEvent.ACTION_DISMISS_ALL_NOTES); - clearAllNotifications(); - } + mDismissView.setOnButtonClickListener(v -> { + mMetricsLogger.action(MetricsEvent.ACTION_DISMISS_ALL_NOTES); + clearAllNotifications(); }); mStackScroller.setDismissView(mDismissView); } protected void createUserSwitcher() { mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext, - (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher), - mKeyguardStatusBar, mNotificationPanel); + mStatusBarWindow.findViewById(R.id.keyguard_user_switcher), mKeyguardStatusBar, + mNotificationPanel); } protected void inflateStatusBarWindow(Context context) { @@ -1447,7 +1373,7 @@ public class StatusBar extends SystemUI implements DemoMode, // animate-swipe all dismissable notifications, then animate the shade closed int numChildren = mStackScroller.getChildCount(); - final ArrayList<View> viewsToHide = new ArrayList<View>(numChildren); + final ArrayList<View> viewsToHide = new ArrayList<>(numChildren); final ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>(numChildren); for (int i = 0; i < numChildren; i++) { final View child = mStackScroller.getChildAt(i); @@ -1487,20 +1413,18 @@ public class StatusBar extends SystemUI implements DemoMode, return; } - addPostCollapseAction(new Runnable() { - @Override - public void run() { - mStackScroller.setDismissAllInProgress(false); - for (ExpandableNotificationRow rowToRemove : viewsToRemove) { - if (mStackScroller.canChildBeDismissed(rowToRemove)) { - removeNotification(rowToRemove.getEntry().key, null); - } else { - rowToRemove.resetTranslation(); - } + addPostCollapseAction(() -> { + mStackScroller.setDismissAllInProgress(false); + for (ExpandableNotificationRow rowToRemove : viewsToRemove) { + if (mStackScroller.canChildBeDismissed(rowToRemove)) { + removeNotification(rowToRemove.getEntry().key, null); + } else { + rowToRemove.resetTranslation(); } - try { - mBarService.onClearAllNotifications(mCurrentUserId); - } catch (Exception ex) { } + } + try { + mBarService.onClearAllNotifications(mCurrentUserId); + } catch (Exception ex) { } }); @@ -1509,11 +1433,8 @@ public class StatusBar extends SystemUI implements DemoMode, } private void performDismissAllAnimations(ArrayList<View> hideAnimatedList) { - Runnable animationFinishAction = new Runnable() { - @Override - public void run() { - animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); - } + Runnable animationFinishAction = () -> { + animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); }; // let's disable our normal animations @@ -1632,10 +1553,6 @@ public class StatusBar extends SystemUI implements DemoMode, SystemServicesProxy.getInstance(mContext).awakenDreamsAsync(); } - public UserHandle getCurrentUserHandle() { - return new UserHandle(mCurrentUserId); - } - public void addNotification(StatusBarNotification notification, RankingMap ranking) throws InflationException { String key = notification.getKey(); @@ -1746,7 +1663,7 @@ public class StatusBar extends SystemUI implements DemoMode, boolean deferRemoval = false; abortExistingInflation(key); if (mHeadsUpManager.isHeadsUp(key)) { - // A cancel() in repsonse to a remote input shouldn't be delayed, as it makes the + // A cancel() in response to a remote input shouldn't be delayed, as it makes the // sending look longer than it takes. // Also we should not defer the removal if reordering isn't allowed since otherwise // some notifications can't disappear before the panel is closed. @@ -1772,9 +1689,7 @@ public class StatusBar extends SystemUI implements DemoMode, newHistory = new CharSequence[1]; } else { newHistory = new CharSequence[oldHistory.length + 1]; - for (int i = 0; i < oldHistory.length; i++) { - newHistory[i + 1] = oldHistory[i]; - } + System.arraycopy(oldHistory, 0, newHistory, 1, oldHistory.length); } newHistory[0] = String.valueOf(entry.remoteInputText); b.setRemoteInputHistory(newHistory); @@ -1833,7 +1748,7 @@ public class StatusBar extends SystemUI implements DemoMode, mStackScroller.cleanUpViewState(entry.row); } // Let's remove the children if this was a summary - handleGroupSummaryRemoved(key, ranking); + handleGroupSummaryRemoved(key); StatusBarNotification old = removeNotificationViews(key, ranking); if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old); @@ -1857,12 +1772,10 @@ public class StatusBar extends SystemUI implements DemoMode, * * This also ensures that the animation looks nice and only consists of a single disappear * animation instead of multiple. + * @param key the key of the notification was removed * - * @param key the key of the notification was removed - * @param ranking the current ranking */ - private void handleGroupSummaryRemoved(String key, - RankingMap ranking) { + private void handleGroupSummaryRemoved(String key) { Entry entry = mNotificationData.get(key); if (entry != null && entry.row != null && entry.row.isSummaryWithChildren()) { @@ -1873,15 +1786,13 @@ public class StatusBar extends SystemUI implements DemoMode, } List<ExpandableNotificationRow> notificationChildren = entry.row.getNotificationChildren(); - ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>(); for (int i = 0; i < notificationChildren.size(); i++) { ExpandableNotificationRow row = notificationChildren.get(i); if ((row.getStatusBarNotification().getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) { - // the child is a forground service notification which we can't remove! + // the child is a foreground service notification which we can't remove! continue; } - toRemove.add(row); row.setKeepInParent(true); // we need to set this state earlier as otherwise we might generate some weird // animations @@ -1924,19 +1835,14 @@ public class StatusBar extends SystemUI implements DemoMode, // Do not modify the notifications during collapse. if (isCollapsing()) { - addPostCollapseAction(new Runnable() { - @Override - public void run() { - updateNotificationShade(); - } - }); + addPostCollapseAction(this::updateNotificationShade); return; } ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications(); ArrayList<ExpandableNotificationRow> toShow = new ArrayList<>(activeNotifications.size()); final int N = activeNotifications.size(); - for (int i=0; i<N; i++) { + for (int i = 0; i < N; i++) { Entry ent = activeNotifications.get(i); if (ent.row.isDismissed() || ent.row.isRemoved()) { // we don't want to update removed notifications because they could @@ -1980,7 +1886,8 @@ public class StatusBar extends SystemUI implements DemoMode, for (ExpandableNotificationRow remove : toRemove) { if (mGroupManager.isChildInGroupWithSummary(remove.getStatusBarNotification())) { - // we are only transfering this notification to its parent, don't generate an animation + // we are only transferring this notification to its parent, don't generate an + // animation mStackScroller.setChildTransferInProgress(true); } if (remove.isSummaryWithChildren()) { @@ -1992,7 +1899,7 @@ public class StatusBar extends SystemUI implements DemoMode, removeNotificationChildren(); - for (int i=0; i<toShow.size(); i++) { + for (int i = 0; i < toShow.size(); i++) { View v = toShow.get(i); if (v.getParent() == null) { mVisualStabilityManager.notifyViewAddition(v); @@ -2102,7 +2009,7 @@ public class StatusBar extends SystemUI implements DemoMode, } } - // Finally after removing and adding has been beformed we can apply the order. + // Finally after removing and adding has been performed we can apply the order. orderChanged |= parent.applyChildOrder(orderedChildren, mVisualStabilityManager, this); } if (orderChanged) { @@ -2275,10 +2182,11 @@ public class StatusBar extends SystemUI implements DemoMode, MediaController controller = null; for (int i = 0; i < N; i++) { final Entry entry = activeNotifications.get(i); + if (isMediaNotification(entry)) { final MediaSession.Token token = - entry.notification.getNotification().extras - .getParcelable(Notification.EXTRA_MEDIA_SESSION); + entry.notification.getNotification().extras.getParcelable( + Notification.EXTRA_MEDIA_SESSION); if (token != null) { MediaController aController = new MediaController(mContext, token); if (PlaybackState.STATE_PLAYING == @@ -2316,7 +2224,7 @@ public class StatusBar extends SystemUI implements DemoMode, if (entry.notification.getPackageName().equals(pkg)) { if (DEBUG_MEDIA) { Log.v(TAG, "DEBUG_MEDIA: found controller matching " - + entry.notification.getKey()); + + entry.notification.getKey()); } controller = aController; mediaNotification = entry; @@ -2367,12 +2275,8 @@ public class StatusBar extends SystemUI implements DemoMode, } private boolean isPlaybackActive(int state) { - if (state != PlaybackState.STATE_STOPPED - && state != PlaybackState.STATE_ERROR - && state != PlaybackState.STATE_NONE) { - return true; - } - return false; + return state != PlaybackState.STATE_STOPPED && state != PlaybackState.STATE_ERROR + && state != PlaybackState.STATE_NONE; } private void clearCurrentMediaNotification() { @@ -2397,7 +2301,7 @@ public class StatusBar extends SystemUI implements DemoMode, /** * Hide the album artwork that is fading out and release its bitmap. */ - protected Runnable mHideBackdropFront = new Runnable() { + protected final Runnable mHideBackdropFront = new Runnable() { @Override public void run() { if (DEBUG_MEDIA) { @@ -2549,14 +2453,11 @@ public class StatusBar extends SystemUI implements DemoMode, .setInterpolator(Interpolators.ACCELERATE_DECELERATE) .setDuration(300) .setStartDelay(0) - .withEndAction(new Runnable() { - @Override - public void run() { - mBackdrop.setVisibility(View.GONE); - mBackdropFront.animate().cancel(); - mBackdropBack.setImageDrawable(null); - mHandler.post(mHideBackdropFront); - } + .withEndAction(() -> { + mBackdrop.setVisibility(View.GONE); + mBackdropFront.animate().cancel(); + mBackdropBack.setImageDrawable(null); + mHandler.post(mHideBackdropFront); }); if (mKeyguardFadingAway) { mBackdrop.animate() @@ -2587,8 +2488,6 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void disable(int state1, int state2, boolean animate) { animate &= mStatusBarWindowState != WINDOW_STATE_HIDDEN; - mDisabledUnmodified1 = state1; - mDisabledUnmodified2 = state2; final int old1 = mDisabled1; final int diff1 = state1 ^ old1; mDisabled1 = state1; @@ -2742,11 +2641,8 @@ public class StatusBar extends SystemUI implements DemoMode, // make sure that the window stays small for one frame until the touchableRegion is set. mNotificationPanel.requestLayout(); mStatusBarWindowManager.setForceWindowCollapsed(true); - mNotificationPanel.post(new Runnable() { - @Override - public void run() { - mStatusBarWindowManager.setForceWindowCollapsed(false); - } + mNotificationPanel.post(() -> { + mStatusBarWindowManager.setForceWindowCollapsed(false); }); } } else { @@ -2758,15 +2654,12 @@ public class StatusBar extends SystemUI implements DemoMode, // we need to keep the panel open artificially, let's wait until the animation // is finished. mHeadsUpManager.setHeadsUpGoingAway(true); - mStackScroller.runAfterAnimationFinished(new Runnable() { - @Override - public void run() { - if (!mHeadsUpManager.hasPinnedHeadsUp()) { - mStatusBarWindowManager.setHeadsUpShowing(false); - mHeadsUpManager.setHeadsUpGoingAway(false); - } - removeRemoteInputEntriesKeptUntilCollapsed(); + mStackScroller.runAfterAnimationFinished(() -> { + if (!mHeadsUpManager.hasPinnedHeadsUp()) { + mStatusBarWindowManager.setHeadsUpShowing(false); + mHeadsUpManager.setHeadsUpGoingAway(false); } + removeRemoteInputEntriesKeptUntilCollapsed(); }); } } @@ -3033,7 +2926,6 @@ public class StatusBar extends SystemUI implements DemoMode, mStatusBarWindowManager.setPanelVisible(true); visibilityChanged(true); - mWaitingForKeyguardExit = false; recomputeDisableFlags(!force /* animate */); setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true); } @@ -3042,23 +2934,15 @@ public class StatusBar extends SystemUI implements DemoMode, animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); } - private final Runnable mAnimateCollapsePanels = new Runnable() { - @Override - public void run() { - animateCollapsePanels(); - } - }; + private final Runnable mAnimateCollapsePanels = this::animateCollapsePanels; public void postAnimateCollapsePanels() { mHandler.post(mAnimateCollapsePanels); } public void postAnimateForceCollapsePanels() { - mHandler.post(new Runnable() { - @Override - public void run() { - animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */); - } + mHandler.post(() -> { + animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */); }); } @@ -3213,7 +3097,7 @@ public class StatusBar extends SystemUI implements DemoMode, if (SPEW) { Log.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled1=" - + mDisabled1 + " mDisabled2=" + mDisabled2 + " mTracking=" + mTracking); + + mDisabled1 + " mDisabled2=" + mDisabled2); } else if (CHATTY) { if (event.getAction() != MotionEvent.ACTION_MOVE) { Log.d(TAG, String.format( @@ -3298,10 +3182,8 @@ public class StatusBar extends SystemUI implements DemoMode, sbModeChanged = sbMode != -1; if (sbModeChanged && sbMode != mStatusBarMode) { - if (sbMode != mStatusBarMode) { - mStatusBarMode = sbMode; - checkBarModes(); - } + mStatusBarMode = sbMode; + checkBarModes(); touchAutoHide(); } @@ -3388,12 +3270,7 @@ public class StatusBar extends SystemUI implements DemoMode, } } - private final Runnable mCheckBarModes = new Runnable() { - @Override - public void run() { - checkBarModes(); - } - }; + private final Runnable mCheckBarModes = this::checkBarModes; public void setInteracting(int barWindow, boolean interacting) { final boolean changing = ((mInteractingWindows & barWindow) != 0) != interacting; @@ -3452,7 +3329,7 @@ public class StatusBar extends SystemUI implements DemoMode, } } - void checkUserAutohide(View v, MotionEvent event) { + void checkUserAutohide(MotionEvent event) { if ((mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0 // a transient bar is revealed && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar && event.getX() == 0 && event.getY() == 0 // a touch outside both bars @@ -3519,9 +3396,7 @@ public class StatusBar extends SystemUI implements DemoMode, public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { synchronized (mQueueLock) { pw.println("Current Status Bar state:"); - pw.println(" mExpandedVisible=" + mExpandedVisible - + ", mTrackingPosition=" + mTrackingPosition); - pw.println(" mTracking=" + mTracking); + pw.println(" mExpandedVisible=" + mExpandedVisible); pw.println(" mDisplayMetrics=" + mDisplayMetrics); pw.println(" mStackScroller: " + viewInfo(mStackScroller)); pw.println(" mStackScroller: " + viewInfo(mStackScroller) @@ -3609,16 +3484,12 @@ public class StatusBar extends SystemUI implements DemoMode, if (false) { pw.println("see the logcat for a dump of the views we have created."); // must happen on ui thread - mHandler.post(new Runnable() { - @Override - public void run() { - mStatusBarView.getLocationOnScreen(mAbsPos); - Log.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1] - + ") " + mStatusBarView.getWidth() + "x" - + getStatusBarHeight()); - mStatusBarView.debug(); - } - }); + mHandler.post(() -> { + mStatusBarView.getLocationOnScreen(mAbsPos); + Log.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1] + + ") " + mStatusBarView.getWidth() + "x" + getStatusBarHeight()); + mStatusBarView.debug(); + }); } } @@ -3698,49 +3569,43 @@ public class StatusBar extends SystemUI implements DemoMode, final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity( mContext, intent, mCurrentUserId); - Runnable runnable = new Runnable() { - @Override - public void run() { - mAssistManager.hideAssist(); - intent.setFlags( - Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); - int result = ActivityManager.START_CANCELED; - ActivityOptions options = new ActivityOptions(getActivityOptions()); - options.setDisallowEnterPictureInPictureWhileLaunching( - disallowEnterPictureInPictureWhileLaunching); - if (intent == KeyguardBottomAreaView.INSECURE_CAMERA_INTENT) { - // Normally an activity will set it's requested rotation - // animation on its window. However when launching an activity - // causes the orientation to change this is too late. In these cases - // the default animation is used. This doesn't look good for - // the camera (as it rotates the camera contents out of sync - // with physical reality). So, we ask the WindowManager to - // force the crossfade animation if an orientation change - // happens to occur during the launch. - options.setRotationAnimationHint( - WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS); - } - try { - result = ActivityManager.getService().startActivityAsUser( - null, mContext.getBasePackageName(), - intent, - intent.resolveTypeIfNeeded(mContext.getContentResolver()), - null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, - options.toBundle(), UserHandle.CURRENT.getIdentifier()); - } catch (RemoteException e) { - Log.w(TAG, "Unable to start activity", e); - } - if (callback != null) { - callback.onActivityStarted(result); - } + Runnable runnable = () -> { + mAssistManager.hideAssist(); + intent.setFlags( + Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); + int result = ActivityManager.START_CANCELED; + ActivityOptions options = new ActivityOptions(getActivityOptions()); + options.setDisallowEnterPictureInPictureWhileLaunching( + disallowEnterPictureInPictureWhileLaunching); + if (intent == KeyguardBottomAreaView.INSECURE_CAMERA_INTENT) { + // Normally an activity will set it's requested rotation + // animation on its window. However when launching an activity + // causes the orientation to change this is too late. In these cases + // the default animation is used. This doesn't look good for + // the camera (as it rotates the camera contents out of sync + // with physical reality). So, we ask the WindowManager to + // force the crossfade animation if an orientation change + // happens to occur during the launch. + options.setRotationAnimationHint( + WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS); + } + try { + result = ActivityManager.getService().startActivityAsUser( + null, mContext.getBasePackageName(), + intent, + intent.resolveTypeIfNeeded(mContext.getContentResolver()), + null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, + options.toBundle(), UserHandle.CURRENT.getIdentifier()); + } catch (RemoteException e) { + Log.w(TAG, "Unable to start activity", e); + } + if (callback != null) { + callback.onActivityStarted(result); } }; - Runnable cancelRunnable = new Runnable() { - @Override - public void run() { - if (callback != null) { - callback.onActivityStarted(ActivityManager.START_CANCELED); - } + Runnable cancelRunnable = () -> { + if (callback != null) { + callback.onActivityStarted(ActivityManager.START_CANCELED); } }; executeRunnableDismissingKeyguard(runnable, cancelRunnable, dismissShade, @@ -3785,7 +3650,7 @@ public class StatusBar extends SystemUI implements DemoMode, }, cancelAction, afterKeyguardGone); } - private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (DEBUG) Log.v(TAG, "onReceive: " + intent); @@ -3814,7 +3679,7 @@ public class StatusBar extends SystemUI implements DemoMode, } }; - private BroadcastReceiver mDemoReceiver = new BroadcastReceiver() { + private final BroadcastReceiver mDemoReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (DEBUG) Log.v(TAG, "onReceive: " + intent); @@ -3975,7 +3840,6 @@ public class StatusBar extends SystemUI implements DemoMode, * The LEDs are turned off when the notification panel is shown, even just a little bit. * See also StatusBar.setPanelExpanded for another place where we attempt to do this. */ - // Old BaseStatusBar.handleVisibileToUserChanged private void handleVisibleToUserChangedImpl(boolean visibleToUser) { try { if (visibleToUser) { @@ -4000,8 +3864,8 @@ public class StatusBar extends SystemUI implements DemoMode, // Report all notifications as invisible and turn down the // reporter. if (!mCurrentlyVisibleNotifications.isEmpty()) { - logNotificationVisibilityChanges(Collections.<NotificationVisibility>emptyList(), - mCurrentlyVisibleNotifications); + logNotificationVisibilityChanges( + Collections.emptyList(), mCurrentlyVisibleNotifications); recycleAllVisibilityObjects(mCurrentlyVisibleNotifications); } mHandler.removeCallbacks(mVisibilityReporter); @@ -4108,7 +3972,7 @@ public class StatusBar extends SystemUI implements DemoMode, vib.vibrate(250, VIBRATION_ATTRIBUTES); } - Runnable mStartTracing = new Runnable() { + final Runnable mStartTracing = new Runnable() { @Override public void run() { vibrate(); @@ -4119,13 +3983,10 @@ public class StatusBar extends SystemUI implements DemoMode, } }; - Runnable mStopTracing = new Runnable() { - @Override - public void run() { - android.os.Debug.stopMethodTracing(); - Log.d(TAG, "stopTracing"); - vibrate(); - } + final Runnable mStopTracing = () -> { + android.os.Debug.stopMethodTracing(); + Log.d(TAG, "stopTracing"); + vibrate(); }; @Override @@ -4152,40 +4013,6 @@ public class StatusBar extends SystemUI implements DemoMode, startActivityDismissingKeyguard(intent, onlyProvisioned, true /* dismissShade */); } - private static class FastColorDrawable extends Drawable { - private final int mColor; - - public FastColorDrawable(int color) { - mColor = 0xff000000 | color; - } - - @Override - public void draw(Canvas canvas) { - canvas.drawColor(mColor, PorterDuff.Mode.SRC); - } - - @Override - public void setAlpha(int alpha) { - } - - @Override - public void setColorFilter(ColorFilter colorFilter) { - } - - @Override - public int getOpacity() { - return PixelFormat.OPAQUE; - } - - @Override - public void setBounds(int left, int top, int right, int bottom) { - } - - @Override - public void setBounds(Rect bounds) { - } - } - public void destroy() { // Begin old BaseStatusBar.destroy(). mContext.unregisterReceiver(mBaseBroadcastReceiver); @@ -4403,31 +4230,23 @@ public class StatusBar extends SystemUI implements DemoMode, Runnable endRunnable) { mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT); mLaunchTransitionEndRunnable = endRunnable; - Runnable hideRunnable = new Runnable() { - @Override - public void run() { - mLaunchTransitionFadingAway = true; - if (beforeFading != null) { - beforeFading.run(); - } - mScrimController.forceHideScrims(true /* hide */, false /* animated */); - updateMediaMetaData(false, true); - mNotificationPanel.setAlpha(1); - mStackScroller.setParentNotFullyVisible(true); - mNotificationPanel.animate() - .alpha(0) - .setStartDelay(FADE_KEYGUARD_START_DELAY) - .setDuration(FADE_KEYGUARD_DURATION) - .withLayer() - .withEndAction(new Runnable() { - @Override - public void run() { - onLaunchTransitionFadingEnded(); - } - }); - mCommandQueue.appTransitionStarting(SystemClock.uptimeMillis(), - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true); - } + Runnable hideRunnable = () -> { + mLaunchTransitionFadingAway = true; + if (beforeFading != null) { + beforeFading.run(); + } + mScrimController.forceHideScrims(true /* hide */, false /* animated */); + updateMediaMetaData(false, true); + mNotificationPanel.setAlpha(1); + mStackScroller.setParentNotFullyVisible(true); + mNotificationPanel.animate() + .alpha(0) + .setStartDelay(FADE_KEYGUARD_START_DELAY) + .setDuration(FADE_KEYGUARD_DURATION) + .withLayer() + .withEndAction(this::onLaunchTransitionFadingEnded); + mCommandQueue.appTransitionStarting(SystemClock.uptimeMillis(), + LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true); }; if (mNotificationPanel.isLaunchTransitionRunning()) { mNotificationPanel.setLaunchTransitionEndRunnable(hideRunnable); @@ -4556,7 +4375,6 @@ public class StatusBar extends SystemUI implements DemoMode, // Treat Keyguard exit animation as an app transition to achieve nice transition for status // bar. - mKeyguardGoingAway = true; mKeyguardMonitor.notifyKeyguardGoingAway(true); mCommandQueue.appTransitionPending(true); } @@ -4565,14 +4383,13 @@ public class StatusBar extends SystemUI implements DemoMode, * Notifies the status bar the Keyguard is fading away with the specified timings. * * @param startTime the start time of the animations in uptime millis - * @param delay the precalculated animation delay in miliseconds + * @param delay the precalculated animation delay in milliseconds * @param fadeoutDuration the duration of the exit animation, in milliseconds */ public void setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration) { mKeyguardFadingAway = true; mKeyguardFadingAwayDelay = delay; mKeyguardFadingAwayDuration = fadeoutDuration; - mWaitingForKeyguardExit = false; mCommandQueue.appTransitionStarting(startTime + fadeoutDuration - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true); @@ -4592,14 +4409,9 @@ public class StatusBar extends SystemUI implements DemoMode, */ public void finishKeyguardFadingAway() { mKeyguardFadingAway = false; - mKeyguardGoingAway = false; mKeyguardMonitor.notifyKeyguardDoneFading(); } - public void stopWaitingForKeyguardExit() { - mWaitingForKeyguardExit = false; - } - private void updatePublicMode() { final boolean showingKeyguard = mStatusBarKeyguardViewManager.isShowing(); final boolean devicePublic = showingKeyguard @@ -4813,7 +4625,6 @@ public class StatusBar extends SystemUI implements DemoMode, } protected void showBouncer() { - mWaitingForKeyguardExit = mStatusBarKeyguardViewManager.isShowing(); mStatusBarKeyguardViewManager.dismiss(); } @@ -4830,7 +4641,7 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void onActivated(ActivatableNotificationView view) { - onActivated((View)view); + onActivated((View) view); mStackScroller.setActivatedChild(view); } @@ -5132,51 +4943,41 @@ public class StatusBar extends SystemUI implements DemoMode, updateNotifications(); if (mPendingWorkRemoteInputView != null && !isAnyProfilePublicMode()) { // Expand notification panel and the notification row, then click on remote input view - final Runnable clickPendingViewRunnable = new Runnable() { - @Override - public void run() { - final View pendingWorkRemoteInputView = mPendingWorkRemoteInputView; - if (pendingWorkRemoteInputView == null) { + final Runnable clickPendingViewRunnable = () -> { + final View pendingWorkRemoteInputView = mPendingWorkRemoteInputView; + if (pendingWorkRemoteInputView == null) { + return; + } + + // Climb up the hierarchy until we get to the container for this row. + ViewParent p = pendingWorkRemoteInputView.getParent(); + while (!(p instanceof ExpandableNotificationRow)) { + if (p == null) { return; } + p = p.getParent(); + } - // Climb up the hierarchy until we get to the container for this row. - ViewParent p = pendingWorkRemoteInputView.getParent(); - while (!(p instanceof ExpandableNotificationRow)) { - if (p == null) { - return; + final ExpandableNotificationRow row = (ExpandableNotificationRow) p; + ViewParent viewParent = row.getParent(); + if (viewParent instanceof NotificationStackScrollLayout) { + final NotificationStackScrollLayout scrollLayout = + (NotificationStackScrollLayout) viewParent; + row.makeActionsVisibile(); + row.post(() -> { + final Runnable finishScrollingCallback = () -> { + mPendingWorkRemoteInputView.callOnClick(); + mPendingWorkRemoteInputView = null; + scrollLayout.setFinishScrollingCallback(null); + }; + if (scrollLayout.scrollTo(row)) { + // It scrolls! So call it when it's finished. + scrollLayout.setFinishScrollingCallback(finishScrollingCallback); + } else { + // It does not scroll, so call it now! + finishScrollingCallback.run(); } - p = p.getParent(); - } - - final ExpandableNotificationRow row = (ExpandableNotificationRow) p; - ViewParent viewParent = row.getParent(); - if (viewParent instanceof NotificationStackScrollLayout) { - final NotificationStackScrollLayout scrollLayout = - (NotificationStackScrollLayout) viewParent; - row.makeActionsVisibile(); - row.post(new Runnable() { - @Override - public void run() { - final Runnable finishScrollingCallback = new Runnable() { - @Override - public void run() { - mPendingWorkRemoteInputView.callOnClick(); - mPendingWorkRemoteInputView = null; - scrollLayout.setFinishScrollingCallback(null); - } - }; - if (scrollLayout.scrollTo(row)) { - // It scrolls! So call it when it's finished. - scrollLayout.setFinishScrollingCallback( - finishScrollingCallback); - } else { - // It does not scroll, so call it now! - finishScrollingCallback.run(); - } - } - }); - } + }); } }; mNotificationPanel.getViewTreeObserver().addOnGlobalLayoutListener( @@ -5239,7 +5040,7 @@ public class StatusBar extends SystemUI implements DemoMode, } } - WakefulnessLifecycle.Observer mWakefulnessObserver = new WakefulnessLifecycle.Observer() { + final WakefulnessLifecycle.Observer mWakefulnessObserver = new WakefulnessLifecycle.Observer() { @Override public void onFinishedGoingToSleep() { mNotificationPanel.onAffordanceLaunchEnded(); @@ -5262,12 +5063,7 @@ public class StatusBar extends SystemUI implements DemoMode, // This gets executed before we will show Keyguard, so post it in order that the state // is correct. - mHandler.post(new Runnable() { - @Override - public void run() { - onCameraLaunchGestureDetected(mLastCameraLaunchSource); - } - }); + mHandler.post(() -> onCameraLaunchGestureDetected(mLastCameraLaunchSource)); } updateIsKeyguard(); } @@ -5293,7 +5089,7 @@ public class StatusBar extends SystemUI implements DemoMode, } }; - ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() { + final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() { @Override public void onScreenTurningOn() { mFalsingManager.onScreenTurningOn(); @@ -5490,7 +5286,7 @@ public class StatusBar extends SystemUI implements DemoMode, } private final class DozeServiceHost implements DozeHost { - private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>(); + private final ArrayList<Callback> mCallbacks = new ArrayList<>(); private boolean mAnimateWakeup; private boolean mIgnoreTouchWhilePulsing; @@ -5703,7 +5499,7 @@ public class StatusBar extends SystemUI implements DemoMode, protected NotificationData mNotificationData; protected NotificationStackScrollLayout mStackScroller; - protected NotificationGroupManager mGroupManager = new NotificationGroupManager(); + protected final NotificationGroupManager mGroupManager = new NotificationGroupManager(); protected RemoteInputController mRemoteInputController; @@ -5713,34 +5509,30 @@ public class StatusBar extends SystemUI implements DemoMode, private AboveShelfObserver mAboveShelfObserver; // handling reordering - protected VisualStabilityManager mVisualStabilityManager = new VisualStabilityManager(); + protected final VisualStabilityManager mVisualStabilityManager = new VisualStabilityManager(); protected int mCurrentUserId = 0; - final protected SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>(); + final protected SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>(); - protected int mLayoutDirection = -1; // invalid protected AccessibilityManager mAccessibilityManager; protected boolean mDeviceInteractive; protected boolean mVisible; - protected ArraySet<Entry> mHeadsUpEntriesToRemoveOnSwitch = new ArraySet<>(); - protected ArraySet<Entry> mRemoteInputEntriesToRemoveOnCollapse = new ArraySet<>(); + protected final ArraySet<Entry> mHeadsUpEntriesToRemoveOnSwitch = new ArraySet<>(); + protected final ArraySet<Entry> mRemoteInputEntriesToRemoveOnCollapse = new ArraySet<>(); /** * Notifications with keys in this set are not actually around anymore. We kept them around * when they were canceled in response to a remote input interaction. This allows us to show * what you replied and allows you to continue typing into it. */ - protected ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>(); + protected final ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>(); // mScreenOnFromKeyguard && mVisible. private boolean mVisibleToUser; - private Locale mLocale; - protected boolean mUseHeadsUp = false; - protected boolean mHeadsUpTicker = false; protected boolean mDisableNotificationAlerts = false; protected DevicePolicyManager mDevicePolicyManager; @@ -5775,13 +5567,11 @@ public class StatusBar extends SystemUI implements DemoMode, private NotificationGuts mNotificationGutsExposed; private MenuItem mGutsMenuItem; - private KeyboardShortcuts mKeyboardShortcuts; - protected NotificationShelf mNotificationShelf; protected DismissView mDismissView; protected EmptyShadeView mEmptyShadeView; - private NotificationClicker mNotificationClicker = new NotificationClicker(); + private final NotificationClicker mNotificationClicker = new NotificationClicker(); protected AssistManager mAssistManager; @@ -5841,15 +5631,14 @@ public class StatusBar extends SystemUI implements DemoMode, } }; - private RemoteViews.OnClickHandler mOnClickHandler = new RemoteViews.OnClickHandler() { + private final RemoteViews.OnClickHandler mOnClickHandler = new RemoteViews.OnClickHandler() { @Override public boolean onClickHandler( final View view, final PendingIntent pendingIntent, final Intent fillInIntent) { wakeUpIfDozing(SystemClock.uptimeMillis(), view); - - if (handleRemoteInput(view, pendingIntent, fillInIntent)) { + if (handleRemoteInput(view, pendingIntent)) { return true; } @@ -5867,33 +5656,29 @@ public class StatusBar extends SystemUI implements DemoMode, } final boolean isActivity = pendingIntent.isActivity(); if (isActivity) { - final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing(); final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity( mContext, pendingIntent.getIntent(), mCurrentUserId); - dismissKeyguardThenExecute(new OnDismissAction() { - @Override - public boolean onDismiss() { - try { - ActivityManager.getService().resumeAppSwitches(); - } catch (RemoteException e) { - } - - boolean handled = superOnClickHandler(view, pendingIntent, fillInIntent); + dismissKeyguardThenExecute(() -> { + try { + ActivityManager.getService().resumeAppSwitches(); + } catch (RemoteException e) { + } - // close the shade if it was open - if (handled && !mNotificationPanel.isFullyCollapsed()) { - animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, - true /* force */); - visibilityChanged(false); - mAssistManager.hideAssist(); + boolean handled = superOnClickHandler(view, pendingIntent, fillInIntent); - // Wait for activity start. - return true; - } else { - return false; - } + // close the shade if it was open + if (handled && !mNotificationPanel.isFullyCollapsed()) { + animateCollapsePanels( + CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */); + visibilityChanged(false); + mAssistManager.hideAssist(); + // Wait for activity start. + return true; + } else { + return false; } + }, afterKeyguardGone); return true; } else { @@ -5938,7 +5723,7 @@ public class StatusBar extends SystemUI implements DemoMode, WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY); } - private boolean handleRemoteInput(View view, PendingIntent pendingIntent, Intent fillInIntent) { + private boolean handleRemoteInput(View view, PendingIntent pendingIntent) { Object tag = view.getTag(com.android.internal.R.id.remote_input_tag); RemoteInput[] inputs = null; if (tag instanceof RemoteInput[]) { @@ -6053,7 +5838,7 @@ public class StatusBar extends SystemUI implements DemoMode, if (Intent.ACTION_USER_SWITCHED.equals(action)) { mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); updateCurrentProfilesCache(); - if (true) Log.v(TAG, "userId " + mCurrentUserId + " is in the house"); + Log.v(TAG, "userId " + mCurrentUserId + " is in the house"); updateLockscreenNotificationSetting(); @@ -6076,8 +5861,7 @@ public class StatusBar extends SystemUI implements DemoMode, Toast toast = Toast.makeText(mContext, R.string.managed_profile_foreground_toast, Toast.LENGTH_SHORT); - TextView text = (TextView) toast.getView().findViewById( - android.R.id.message); + TextView text = toast.getView().findViewById(android.R.id.message); text.setCompoundDrawablesRelativeWithIntrinsicBounds( R.drawable.stat_sys_managed_profile_status, 0, 0, 0); int paddingPx = mContext.getResources().getDimensionPixelSize( @@ -6153,15 +5937,12 @@ public class StatusBar extends SystemUI implements DemoMode, return; } final RankingMap currentRanking = getCurrentRanking(); - mHandler.post(new Runnable() { - @Override - public void run() { - for (StatusBarNotification sbn : notifications) { - try { - addNotification(sbn, currentRanking); - } catch (InflationException e) { - handleInflationException(sbn, e); - } + mHandler.post(() -> { + for (StatusBarNotification sbn : notifications) { + try { + addNotification(sbn, currentRanking); + } catch (InflationException e) { + handleInflationException(sbn, e); } } }); @@ -6172,40 +5953,37 @@ public class StatusBar extends SystemUI implements DemoMode, final RankingMap rankingMap) { if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn); if (sbn != null && !onPluginNotificationPosted(sbn, rankingMap)) { - mHandler.post(new Runnable() { - @Override - public void run() { - processForRemoteInput(sbn.getNotification()); - String key = sbn.getKey(); - mKeysKeptForRemoteInput.remove(key); - boolean isUpdate = mNotificationData.get(key) != null; - // In case we don't allow child notifications, we ignore children of - // notifications that have a summary, since we're not going to show them - // anyway. This is true also when the summary is canceled, - // because children are automatically canceled by NoMan in that case. - if (!ENABLE_CHILD_NOTIFICATIONS + mHandler.post(() -> { + processForRemoteInput(sbn.getNotification()); + String key = sbn.getKey(); + mKeysKeptForRemoteInput.remove(key); + boolean isUpdate = mNotificationData.get(key) != null; + // In case we don't allow child notifications, we ignore children of + // notifications that have a summary, since we're not going to show them + // anyway. This is true also when the summary is canceled, + // because children are automatically canceled by NoMan in that case. + if (!ENABLE_CHILD_NOTIFICATIONS && mGroupManager.isChildInGroupWithSummary(sbn)) { - if (DEBUG) { - Log.d(TAG, "Ignoring group child due to existing summary: " + sbn); - } + if (DEBUG) { + Log.d(TAG, "Ignoring group child due to existing summary: " + sbn); + } - // Remove existing notification to avoid stale data. - if (isUpdate) { - removeNotification(key, rankingMap); - } else { - mNotificationData.updateRanking(rankingMap); - } - return; + // Remove existing notification to avoid stale data. + if (isUpdate) { + removeNotification(key, rankingMap); + } else { + mNotificationData.updateRanking(rankingMap); } - try { - if (isUpdate) { - updateNotification(sbn, rankingMap); - } else { - addNotification(sbn, rankingMap); - } - } catch (InflationException e) { - handleInflationException(sbn, e); + return; + } + try { + if (isUpdate) { + updateNotification(sbn, rankingMap); + } else { + addNotification(sbn, rankingMap); } + } catch (InflationException e) { + handleInflationException(sbn, e); } }); } @@ -6253,7 +6031,7 @@ public class StatusBar extends SystemUI implements DemoMode, Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0); return; } - Log.d(TAG, "disabling lockecreen notifications and alerting the user"); + Log.d(TAG, "disabling lockscreen notifications and alerting the user"); // disable lockscreen notifications until user acts on the banner. Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0); @@ -6294,11 +6072,10 @@ public class StatusBar extends SystemUI implements DemoMode, @Override // NotificationData.Environment public boolean isNotificationForCurrentProfiles(StatusBarNotification n) { - final int thisUserId = mCurrentUserId; final int notificationUserId = n.getUserId(); if (DEBUG && MULTIUSER_DEBUG) { - Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d", - n, thisUserId, notificationUserId)); + Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d", n, + mCurrentUserId, notificationUserId)); } return isCurrentProfile(notificationUserId); } @@ -6346,21 +6123,15 @@ public class StatusBar extends SystemUI implements DemoMode, } private void startNotificationGutsIntent(final Intent intent, final int appUid) { - dismissKeyguardThenExecute(new OnDismissAction() { - @Override - public boolean onDismiss() { - AsyncTask.execute(new Runnable() { - @Override - public void run() { - TaskStackBuilder.create(mContext) - .addNextIntentWithParentStack(intent) - .startActivities(getActivityOptions(), - new UserHandle(UserHandle.getUserId(appUid))); - } - }); - animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */); - return true; - } + dismissKeyguardThenExecute(() -> { + AsyncTask.execute(() -> { + TaskStackBuilder.create(mContext) + .addNextIntentWithParentStack(intent) + .startActivities(getActivityOptions(), + new UserHandle(UserHandle.getUserId(appUid))); + }); + animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */); + return true; }, false /* afterKeyguardGone */); } @@ -6431,7 +6202,7 @@ public class StatusBar extends SystemUI implements DemoMode, startNotificationGutsIntent(intent, sbn.getUid()); }; final View.OnClickListener onDoneClick = (View v) -> { - saveAndCloseNotificationMenu(info, row, guts, v); + saveAndCloseNotificationMenu(row, guts, v); }; final NotificationInfo.CheckSaveListener checkSaveListener = (Runnable saveImportance) -> { @@ -6448,7 +6219,7 @@ public class StatusBar extends SystemUI implements DemoMode, } }; - ArraySet<NotificationChannel> channels = new ArraySet<NotificationChannel>(); + ArraySet<NotificationChannel> channels = new ArraySet<>(); channels.add(row.getEntry().channel); if (row.isSummaryWithChildren()) { // If this is a summary, then add in the children notification channels for the @@ -6476,7 +6247,7 @@ public class StatusBar extends SystemUI implements DemoMode, } } - private void saveAndCloseNotificationMenu(NotificationInfo info, + private void saveAndCloseNotificationMenu( ExpandableNotificationRow row, NotificationGuts guts, View done) { guts.resetFalsingCheck(); int[] rowLocation = new int[2]; @@ -6645,13 +6416,6 @@ public class StatusBar extends SystemUI implements DemoMode, updateHideIconsForBouncer(true /* animate */); } - protected void sendCloseSystemWindows(String reason) { - try { - ActivityManager.getService().closeSystemDialogs(reason); - } catch (RemoteException e) { - } - } - protected void toggleKeyboardShortcuts(int deviceId) { KeyboardShortcuts.toggle(mContext, deviceId); } @@ -6753,18 +6517,6 @@ public class StatusBar extends SystemUI implements DemoMode, return isLockscreenPublicMode(userId); } - public void onNotificationClear(StatusBarNotification notification) { - try { - mBarService.onNotificationClear( - notification.getPackageName(), - notification.getTag(), - notification.getId(), - notification.getUserId()); - } catch (android.os.RemoteException ex) { - // oh well - } - } - /** * Called when the notification panel layouts */ @@ -6922,49 +6674,42 @@ public class StatusBar extends SystemUI implements DemoMode, public void startPendingIntentDismissingKeyguard(final PendingIntent intent) { if (!isDeviceProvisioned()) return; - final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing(); final boolean afterKeyguardGone = intent.isActivity() && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(), mCurrentUserId); - dismissKeyguardThenExecute(new OnDismissAction() { - @Override - public boolean onDismiss() { - new Thread() { - @Override - public void run() { - try { - // The intent we are sending is for the application, which - // won't have permission to immediately start an activity after - // the user switches to home. We know it is safe to do at this - // point, so make sure new activity switches are now allowed. - ActivityManager.getService().resumeAppSwitches(); - } catch (RemoteException e) { - } - try { - intent.send(null, 0, null, null, null, null, getActivityOptions()); - } catch (PendingIntent.CanceledException e) { - // the stack trace isn't very helpful here. - // Just log the exception message. - Log.w(TAG, "Sending intent failed: " + e); + dismissKeyguardThenExecute(() -> { + new Thread(() -> { + try { + // The intent we are sending is for the application, which + // won't have permission to immediately start an activity after + // the user switches to home. We know it is safe to do at this + // point, so make sure new activity switches are now allowed. + ActivityManager.getService().resumeAppSwitches(); + } catch (RemoteException e) { + } + try { + intent.send(null, 0, null, null, null, null, getActivityOptions()); + } catch (PendingIntent.CanceledException e) { + // the stack trace isn't very helpful here. + // Just log the exception message. + Log.w(TAG, "Sending intent failed: " + e); - // TODO: Dismiss Keyguard. - } - if (intent.isActivity()) { - mAssistManager.hideAssist(); - } - } - }.start(); + // TODO: Dismiss Keyguard. + } + if (intent.isActivity()) { + mAssistManager.hideAssist(); + } + }).start(); - if (!mNotificationPanel.isFullyCollapsed()) { - // close the shade if it was open - animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, - true /* force */, true /* delayed */); - visibilityChanged(false); + if (!mNotificationPanel.isFullyCollapsed()) { + // close the shade if it was open + animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */, + true /* delayed */); + visibilityChanged(false); - return true; - } else { - return false; - } + return true; + } else { + return false; } }, afterKeyguardGone); } @@ -7002,130 +6747,110 @@ public class StatusBar extends SystemUI implements DemoMode, // Mark notification for one frame. row.setJustClicked(true); - DejankUtils.postAfterTraversal(new Runnable() { - @Override - public void run() { - row.setJustClicked(false); - } - }); + DejankUtils.postAfterTraversal(() -> row.setJustClicked(false)); final boolean afterKeyguardGone = intent.isActivity() && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(), mCurrentUserId); - dismissKeyguardThenExecute(new OnDismissAction() { - @Override - public boolean onDismiss() { - if (mHeadsUpManager != null && mHeadsUpManager.isHeadsUp(notificationKey)) { - // Release the HUN notification to the shade. + dismissKeyguardThenExecute(() -> { + if (mHeadsUpManager != null && mHeadsUpManager.isHeadsUp(notificationKey)) { + // Release the HUN notification to the shade. - if (isPanelFullyCollapsed()) { - HeadsUpManager.setIsClickedNotification(row, true); - } - // - // In most cases, when FLAG_AUTO_CANCEL is set, the notification will - // become canceled shortly by NoMan, but we can't assume that. - mHeadsUpManager.releaseImmediately(notificationKey); + if (isPanelFullyCollapsed()) { + HeadsUpManager.setIsClickedNotification(row, true); } - StatusBarNotification parentToCancel = null; - if (shouldAutoCancel(sbn) && mGroupManager.isOnlyChildInGroup(sbn)) { - StatusBarNotification summarySbn = mGroupManager.getLogicalGroupSummary(sbn) - .getStatusBarNotification(); - if (shouldAutoCancel(summarySbn)) { - parentToCancel = summarySbn; - } + // + // In most cases, when FLAG_AUTO_CANCEL is set, the notification will + // become canceled shortly by NoMan, but we can't assume that. + mHeadsUpManager.releaseImmediately(notificationKey); + } + StatusBarNotification parentToCancel = null; + if (shouldAutoCancel(sbn) && mGroupManager.isOnlyChildInGroup(sbn)) { + StatusBarNotification summarySbn = + mGroupManager.getLogicalGroupSummary(sbn).getStatusBarNotification(); + if (shouldAutoCancel(summarySbn)) { + parentToCancel = summarySbn; } - final StatusBarNotification parentToCancelFinal = parentToCancel; - final Runnable runnable = new Runnable() { - @Override - public void run() { - try { - // The intent we are sending is for the application, which - // won't have permission to immediately start an activity after - // the user switches to home. We know it is safe to do at this - // point, so make sure new activity switches are now allowed. - ActivityManager.getService().resumeAppSwitches(); - } catch (RemoteException e) { - } - if (intent != null) { - // If we are launching a work activity and require to launch - // separate work challenge, we defer the activity action and cancel - // notification until work challenge is unlocked. - if (intent.isActivity()) { - final int userId = intent.getCreatorUserHandle() - .getIdentifier(); - if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId) - && mKeyguardManager.isDeviceLocked(userId)) { - // TODO(b/28935539): should allow certain activities to - // bypass work challenge - if (startWorkChallengeIfNecessary(userId, - intent.getIntentSender(), notificationKey)) { - // Show work challenge, do not run PendingIntent and - // remove notification - return; - } - } - } - try { - intent.send(null, 0, null, null, null, null, - getActivityOptions()); - } catch (PendingIntent.CanceledException e) { - // the stack trace isn't very helpful here. - // Just log the exception message. - Log.w(TAG, "Sending contentIntent failed: " + e); - - // TODO: Dismiss Keyguard. - } - if (intent.isActivity()) { - mAssistManager.hideAssist(); + } + final StatusBarNotification parentToCancelFinal = parentToCancel; + final Runnable runnable = () -> { + try { + // The intent we are sending is for the application, which + // won't have permission to immediately start an activity after + // the user switches to home. We know it is safe to do at this + // point, so make sure new activity switches are now allowed. + ActivityManager.getService().resumeAppSwitches(); + } catch (RemoteException e) { + } + if (intent != null) { + // If we are launching a work activity and require to launch + // separate work challenge, we defer the activity action and cancel + // notification until work challenge is unlocked. + if (intent.isActivity()) { + final int userId = intent.getCreatorUserHandle().getIdentifier(); + if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId) + && mKeyguardManager.isDeviceLocked(userId)) { + // TODO(b/28935539): should allow certain activities to + // bypass work challenge + if (startWorkChallengeIfNecessary(userId, intent.getIntentSender(), + notificationKey)) { + // Show work challenge, do not run PendingIntent and + // remove notification + return; } } + } + try { + intent.send(null, 0, null, null, null, null, getActivityOptions()); + } catch (PendingIntent.CanceledException e) { + // the stack trace isn't very helpful here. + // Just log the exception message. + Log.w(TAG, "Sending contentIntent failed: " + e); - try { - mBarService.onNotificationClick(notificationKey); - } catch (RemoteException ex) { - // system process is dead if we're here. - } - if (parentToCancelFinal != null) { - // We have to post it to the UI thread for synchronization - mHandler.post(new Runnable() { - @Override - public void run() { - Runnable removeRunnable = new Runnable() { - @Override - public void run() { - performRemoveNotification(parentToCancelFinal); - } - }; - if (isCollapsing()) { - // To avoid lags we're only performing the remove - // after the shade was collapsed - addPostCollapseAction(removeRunnable); - } else { - removeRunnable.run(); - } - } - }); - } + // TODO: Dismiss Keyguard. + } + if (intent.isActivity()) { + mAssistManager.hideAssist(); } - }; + } - if (mStatusBarKeyguardViewManager.isShowing() - && mStatusBarKeyguardViewManager.isOccluded()) { - mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable); - } else { - new Thread(runnable).start(); + try { + mBarService.onNotificationClick(notificationKey); + } catch (RemoteException ex) { + // system process is dead if we're here. } + if (parentToCancelFinal != null) { + // We have to post it to the UI thread for synchronization + mHandler.post(() -> { + Runnable removeRunnable = + () -> performRemoveNotification(parentToCancelFinal); + if (isCollapsing()) { + // To avoid lags we're only performing the remove + // after the shade was collapsed + addPostCollapseAction(removeRunnable); + } else { + removeRunnable.run(); + } + }); + } + }; - if (!mNotificationPanel.isFullyCollapsed()) { - // close the shade if it was open - animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, - true /* force */, true /* delayed */); - visibilityChanged(false); + if (mStatusBarKeyguardViewManager.isShowing() + && mStatusBarKeyguardViewManager.isOccluded()) { + mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable); + } else { + new Thread(runnable).start(); + } - return true; - } else { - return false; - } + if (!mNotificationPanel.isFullyCollapsed()) { + // close the shade if it was open + animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */, + true /* delayed */); + visibilityChanged(false); + + return true; + } else { + return false; } }, afterKeyguardGone); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index bbce751dcdfd..09828dcd9dc9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -225,7 +225,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb if (mShowing) { if (mOccluded && !mDozing) { mStatusBar.hideKeyguard(); - mStatusBar.stopWaitingForKeyguardExit(); if (hideBouncerWhenShowing || mBouncer.needsFullscreenBouncer()) { hideBouncer(false /* destroyView */); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index c217bda935c4..9d6fc5e9094e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -804,6 +804,10 @@ public class NetworkControllerImpl extends BroadcastReceiver } else { mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_NONE); } + String ssid = args.getString("ssid"); + if (ssid != null) { + mDemoWifiState.ssid = ssid; + } mDemoWifiState.enabled = show; mWifiSignalController.notifyListeners(); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 57bcda7a5646..7295bcb9bc91 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1711,6 +1711,7 @@ public class ActivityManagerService extends IActivityManager.Stub static final int PUSH_TEMP_WHITELIST_UI_MSG = 68; static final int SERVICE_FOREGROUND_CRASH_MSG = 69; static final int DISPATCH_OOM_ADJ_OBSERVER_MSG = 70; + static final int TOP_APP_KILLED_BY_LMK_MSG = 73; static final int FIRST_ACTIVITY_STACK_MSG = 100; static final int FIRST_BROADCAST_QUEUE_MSG = 200; @@ -1938,6 +1939,17 @@ public class ActivityManagerService extends IActivityManager.Stub dispatchProcessDied(pid, uid); break; } + case TOP_APP_KILLED_BY_LMK_MSG: { + final String appName = (String) msg.obj; + final AlertDialog d = new BaseErrorDialog(mUiContext); + d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR); + d.setTitle(mUiContext.getText(R.string.top_app_killed_title)); + d.setMessage(mUiContext.getString(R.string.top_app_killed_message, appName)); + d.setButton(DialogInterface.BUTTON_POSITIVE, mUiContext.getText(R.string.close), + obtainMessage(DISMISS_DIALOG_UI_MSG, d)); + d.show(); + break; + } case DISPATCH_UIDS_CHANGED_UI_MSG: { dispatchUidsChanged(); } break; @@ -5396,6 +5408,7 @@ public class ActivityManagerService extends IActivityManager.Stub boolean doLowMem = app.instr == null; boolean doOomAdj = doLowMem; if (!app.killedByAm) { + maybeNotifyTopAppKilled(app); Slog.i(TAG, "Process " + app.processName + " (pid " + pid + ") has died: " + ProcessList.makeOomAdjString(app.setAdj) + ProcessList.makeProcStateString(app.setProcState)); @@ -5429,6 +5442,23 @@ public class ActivityManagerService extends IActivityManager.Stub } } + /** Show system error dialog when a top app is killed by LMK */ + void maybeNotifyTopAppKilled(ProcessRecord app) { + if (!shouldNotifyTopAppKilled(app)) { + return; + } + + Message msg = mHandler.obtainMessage(TOP_APP_KILLED_BY_LMK_MSG); + msg.obj = mContext.getPackageManager().getApplicationLabel(app.info); + mUiHandler.sendMessage(msg); + } + + /** Only show notification when the top app is killed on low ram devices */ + private boolean shouldNotifyTopAppKilled(ProcessRecord app) { + return app.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP && + ActivityManager.isLowRamDeviceStatic(); + } + /** * If a stack trace dump file is configured, dump process stack traces. * @param clearTraces causes the dump file to be erased prior to the new diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index bbb58ac7886c..3f31b0814e20 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -3315,6 +3315,24 @@ public class PackageManagerService extends IPackageManager.Stub removeCodePathLI(dstCodePath); return null; } + + // If we have a profile for a compressed APK, copy it to the reference location. + // Since the package is the stub one, remove the stub suffix to get the normal package and + // APK name. + File profileFile = new File(getPrebuildProfilePath(pkg).replace(STUB_SUFFIX, "")); + if (profileFile.exists()) { + try { + // We could also do this lazily before calling dexopt in + // PackageDexOptimizer to prevent this happening on first boot. The issue + // is that we don't have a good way to say "do this only once". + if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(), + pkg.applicationInfo.uid, pkg.packageName)) { + Log.e(TAG, "decompressPackage failed to copy system profile!"); + } + } catch (Exception e) { + Log.e(TAG, "Failed to copy profile " + profileFile.getAbsolutePath() + " ", e); + } + } return dstCodePath; } @@ -9739,7 +9757,7 @@ public class PackageManagerService extends IPackageManager.Stub * and {@code numberOfPackagesFailed}. */ private int[] performDexOptUpgrade(List<PackageParser.Package> pkgs, boolean showDialog, - String compilerFilter, boolean bootComplete) { + final String compilerFilter, boolean bootComplete) { int numberOfPackagesVisited = 0; int numberOfPackagesOptimized = 0; @@ -9750,6 +9768,8 @@ public class PackageManagerService extends IPackageManager.Stub for (PackageParser.Package pkg : pkgs) { numberOfPackagesVisited++; + boolean useProfileForDexopt = false; + if ((isFirstBoot() || isUpgrade()) && isSystemApp(pkg)) { // Copy over initial preopt profiles since we won't get any JIT samples for methods // that are already compiled. @@ -9763,11 +9783,30 @@ public class PackageManagerService extends IPackageManager.Stub if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(), pkg.applicationInfo.uid, pkg.packageName)) { Log.e(TAG, "Installer failed to copy system profile!"); + } else { + // Disabled as this causes speed-profile compilation during first boot + // even if things are already compiled. + // useProfileForDexopt = true; } } catch (Exception e) { Log.e(TAG, "Failed to copy profile " + profileFile.getAbsolutePath() + " ", e); } + } else { + PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(pkg.packageName); + // Handle compressed APKs in this path. Only do this for stubs with profiles to + // minimize the number off apps being speed-profile compiled during first boot. + // The other paths will not change the filter. + if (disabledPs != null && disabledPs.pkg.isStub) { + // The package is the stub one, remove the stub suffix to get the normal + // package and APK names. + String systemProfilePath = + getPrebuildProfilePath(disabledPs.pkg).replace(STUB_SUFFIX, ""); + File systemProfile = new File(systemProfilePath); + // Use the profile for compilation if there exists one for the same package + // in the system partition. + useProfileForDexopt = systemProfile.exists(); + } } } @@ -9796,6 +9835,15 @@ public class PackageManagerService extends IPackageManager.Stub } } + String pkgCompilerFilter = compilerFilter; + if (useProfileForDexopt) { + // Use background dexopt mode to try and use the profile. Note that this does not + // guarantee usage of the profile. + pkgCompilerFilter = + PackageManagerServiceCompilerMapping.getCompilerFilterForReason( + PackageManagerService.REASON_BACKGROUND_DEXOPT); + } + // checkProfiles is false to avoid merging profiles during boot which // might interfere with background compilation (b/28612421). // Unfortunately this will also means that "pm.dexopt.boot=speed-profile" will @@ -9804,7 +9852,7 @@ public class PackageManagerService extends IPackageManager.Stub int dexoptFlags = bootComplete ? DexoptOptions.DEXOPT_BOOT_COMPLETE : 0; int primaryDexOptStaus = performDexOptTraced(new DexoptOptions( pkg.packageName, - compilerFilter, + pkgCompilerFilter, dexoptFlags)); switch (primaryDexOptStaus) { diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp index 43918da75ad4..f0ebf10ec527 100644 --- a/tools/aapt2/Android.bp +++ b/tools/aapt2/Android.bp @@ -139,6 +139,7 @@ cc_library_host_static { "xml/XmlDom.cpp", "xml/XmlPullParser.cpp", "xml/XmlUtil.cpp", + "Configuration.proto", "Resources.proto", "ResourcesInternal.proto", ], diff --git a/tools/aapt2/ConfigDescription.cpp b/tools/aapt2/ConfigDescription.cpp index a9278c136cff..59a6e1281783 100644 --- a/tools/aapt2/ConfigDescription.cpp +++ b/tools/aapt2/ConfigDescription.cpp @@ -876,6 +876,12 @@ ConfigDescription ConfigDescription::CopyWithoutSdkVersion() const { return copy; } +std::string ConfigDescription::GetBcp47LanguageTag(bool canonicalize) const { + char locale[RESTABLE_MAX_LOCALE_LEN]; + getBcp47Locale(locale, canonicalize); + return std::string(locale); +} + bool ConfigDescription::Dominates(const ConfigDescription& o) const { if (*this == o) { return true; diff --git a/tools/aapt2/ConfigDescription.h b/tools/aapt2/ConfigDescription.h index 65c96175091c..c1d0e1084186 100644 --- a/tools/aapt2/ConfigDescription.h +++ b/tools/aapt2/ConfigDescription.h @@ -61,6 +61,9 @@ struct ConfigDescription : public android::ResTable_config { ConfigDescription CopyWithoutSdkVersion() const; + // Returns the BCP-47 language tag of this configuration's locale. + std::string GetBcp47LanguageTag(bool canonicalize = false) const; + /** * A configuration X dominates another configuration Y, if X has at least the * precedence of Y and X is strictly more general than Y: for any type defined diff --git a/tools/aapt2/Configuration.proto b/tools/aapt2/Configuration.proto new file mode 100644 index 000000000000..fc636a43ec40 --- /dev/null +++ b/tools/aapt2/Configuration.proto @@ -0,0 +1,207 @@ +/* + * 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"; + +package aapt.pb; + +option java_package = "com.android.aapt"; +option optimize_for = LITE_RUNTIME; + +// A description of the requirements a device must have in order for a +// resource to be matched and selected. +message Configuration { + enum LayoutDirection { + LAYOUT_DIRECTION_UNSET = 0; + LAYOUT_DIRECTION_LTR = 1; + LAYOUT_DIRECTION_RTL = 2; + } + + enum ScreenLayoutSize { + SCREEN_LAYOUT_SIZE_UNSET = 0; + SCREEN_LAYOUT_SIZE_SMALL = 1; + SCREEN_LAYOUT_SIZE_NORMAL = 2; + SCREEN_LAYOUT_SIZE_LARGE = 3; + SCREEN_LAYOUT_SIZE_XLARGE = 4; + } + + enum ScreenLayoutLong { + SCREEN_LAYOUT_LONG_UNSET = 0; + SCREEN_LAYOUT_LONG_LONG = 1; + SCREEN_LAYOUT_LONG_NOTLONG = 2; + } + + enum ScreenRound { + SCREEN_ROUND_UNSET = 0; + SCREEN_ROUND_ROUND = 1; + SCREEN_ROUND_NOTROUND = 2; + } + + enum WideColorGamut { + WIDE_COLOR_GAMUT_UNSET = 0; + WIDE_COLOR_GAMUT_WIDECG = 1; + WIDE_COLOR_GAMUT_NOWIDECG = 2; + } + + enum Hdr { + HDR_UNSET = 0; + HDR_HIGHDR = 1; + HDR_LOWDR = 2; + } + + enum Orientation { + ORIENTATION_UNSET = 0; + ORIENTATION_PORT = 1; + ORIENTATION_LAND = 2; + ORIENTATION_SQUARE = 3; + } + + enum UiModeType { + UI_MODE_TYPE_UNSET = 0; + UI_MODE_TYPE_NORMAL = 1; + UI_MODE_TYPE_DESK = 2; + UI_MODE_TYPE_CAR = 3; + UI_MODE_TYPE_TELEVISION = 4; + UI_MODE_TYPE_APPLIANCE = 5; + UI_MODE_TYPE_WATCH = 6; + UI_MODE_TYPE_VRHEADSET = 7; + } + + enum UiModeNight { + UI_MODE_NIGHT_UNSET = 0; + UI_MODE_NIGHT_NIGHT = 1; + UI_MODE_NIGHT_NOTNIGHT = 2; + } + + enum Touchscreen { + TOUCHSCREEN_UNSET = 0; + TOUCHSCREEN_NOTOUCH = 1; + TOUCHSCREEN_STYLUS = 2; + TOUCHSCREEN_FINGER = 3; + } + + enum KeysHidden { + KEYS_HIDDEN_UNSET = 0; + KEYS_HIDDEN_KEYSEXPOSED = 1; + KEYS_HIDDEN_KEYSHIDDEN = 2; + KEYS_HIDDEN_KEYSSOFT = 3; + } + + enum Keyboard { + KEYBOARD_UNSET = 0; + KEYBOARD_NOKEYS = 1; + KEYBOARD_QWERTY = 2; + KEYBOARD_TWELVEKEY = 3; + } + + enum NavHidden { + NAV_HIDDEN_UNSET = 0; + NAV_HIDDEN_NAVEXPOSED = 1; + NAV_HIDDEN_NAVHIDDEN = 2; + } + + enum Navigation { + NAVIGATION_UNSET = 0; + NAVIGATION_NONAV = 1; + NAVIGATION_DPAD = 2; + NAVIGATION_TRACKBALL = 3; + NAVIGATION_WHEEL = 4; + } + + // + // Axis/dimensions that are understood by the runtime. + // + + // Mobile country code. + uint32 mcc = 1; + + // Mobile network code. + uint32 mnc = 2; + + // BCP-47 locale tag. + string locale = 3; + + // Left-to-right, right-to-left... + LayoutDirection layout_direction = 4; + + // Screen width in pixels. Prefer screen_width_dp. + uint32 screen_width = 5; + + // Screen height in pixels. Prefer screen_height_dp. + uint32 screen_height = 6; + + // Screen width in density independent pixels (dp). + uint32 screen_width_dp = 7; + + // Screen height in density independent pixels (dp). + uint32 screen_height_dp = 8; + + // The smallest screen dimension, regardless of orientation, in dp. + uint32 smallest_screen_width_dp = 9; + + // Whether the device screen is classified as small, normal, large, xlarge. + ScreenLayoutSize screen_layout_size = 10; + + // Whether the device screen is long. + ScreenLayoutLong screen_layout_long = 11; + + // Whether the screen is round (Android Wear). + ScreenRound screen_round = 12; + + // Whether the screen supports wide color gamut. + WideColorGamut wide_color_gamut = 13; + + // Whether the screen has high dynamic range. + Hdr hdr = 14; + + // Which orientation the device is in (portrait, landscape). + Orientation orientation = 15; + + // Which type of UI mode the device is in (television, car, etc.). + UiModeType ui_mode_type = 16; + + // Whether the device is in night mode. + UiModeNight ui_mode_night = 17; + + // The device's screen density in dots-per-inch (dpi). + uint32 density = 18; + + // Whether a touchscreen exists, supports a stylus, or finger. + Touchscreen touchscreen = 19; + + // Whether the keyboard hardware keys are currently hidden, exposed, or + // if the keyboard is a software keyboard. + KeysHidden keys_hidden = 20; + + // The type of keyboard present (none, QWERTY, 12-key). + Keyboard keyboard = 21; + + // Whether the navigation is exposed or hidden. + NavHidden nav_hidden = 22; + + // The type of navigation present on the device + // (trackball, wheel, dpad, etc.). + Navigation navigation = 23; + + // The minimum SDK version of the device. + uint32 sdk_version = 24; + + // + // Build-time only dimensions. + // + + string product = 25; +} diff --git a/tools/aapt2/Locale.cpp b/tools/aapt2/Locale.cpp index 7664fac44be1..d81921f23904 100644 --- a/tools/aapt2/Locale.cpp +++ b/tools/aapt2/Locale.cpp @@ -24,9 +24,10 @@ #include "util/Util.h" -namespace aapt { +using ::android::ResTable_config; +using ::android::StringPiece; -using android::ResTable_config; +namespace aapt { void LocaleValue::set_language(const char* language_chars) { size_t i = 0; @@ -72,7 +73,7 @@ static inline bool is_number(const std::string& str) { return std::all_of(std::begin(str), std::end(str), ::isdigit); } -bool LocaleValue::InitFromFilterString(const android::StringPiece& str) { +bool LocaleValue::InitFromFilterString(const StringPiece& str) { // A locale (as specified in the filter) is an underscore separated name such // as "en_US", "en_Latn_US", or "en_US_POSIX". std::vector<std::string> parts = util::SplitAndLowercase(str, '_'); @@ -138,6 +139,71 @@ bool LocaleValue::InitFromFilterString(const android::StringPiece& str) { return true; } +bool LocaleValue::InitFromBcp47Tag(const StringPiece& bcp47tag) { + return InitFromBcp47TagImpl(bcp47tag, '-'); +} + +bool LocaleValue::InitFromBcp47TagImpl(const StringPiece& bcp47tag, const char separator) { + std::vector<std::string> subtags = util::SplitAndLowercase(bcp47tag, separator); + if (subtags.size() == 1) { + set_language(subtags[0].c_str()); + } else if (subtags.size() == 2) { + set_language(subtags[0].c_str()); + + // The second tag can either be a region, a variant or a script. + switch (subtags[1].size()) { + case 2: + case 3: + set_region(subtags[1].c_str()); + break; + case 4: + if ('0' <= subtags[1][0] && subtags[1][0] <= '9') { + // This is a variant: fall through + } else { + set_script(subtags[1].c_str()); + break; + } + case 5: + case 6: + case 7: + case 8: + set_variant(subtags[1].c_str()); + break; + default: + return false; + } + } else if (subtags.size() == 3) { + // The language is always the first subtag. + set_language(subtags[0].c_str()); + + // The second subtag can either be a script or a region code. + // If its size is 4, it's a script code, else it's a region code. + if (subtags[1].size() == 4) { + set_script(subtags[1].c_str()); + } else if (subtags[1].size() == 2 || subtags[1].size() == 3) { + set_region(subtags[1].c_str()); + } else { + return false; + } + + // The third tag can either be a region code (if the second tag was + // a script), else a variant code. + if (subtags[2].size() >= 4) { + set_variant(subtags[2].c_str()); + } else { + set_region(subtags[2].c_str()); + } + } else if (subtags.size() == 4) { + set_language(subtags[0].c_str()); + set_script(subtags[1].c_str()); + set_region(subtags[2].c_str()); + set_variant(subtags[3].c_str()); + } else { + return false; + } + return true; +} + ssize_t LocaleValue::InitFromParts(std::vector<std::string>::iterator iter, std::vector<std::string>::iterator end) { const std::vector<std::string>::iterator start_iter = iter; @@ -145,71 +211,13 @@ ssize_t LocaleValue::InitFromParts(std::vector<std::string>::iterator iter, std::string& part = *iter; if (part[0] == 'b' && part[1] == '+') { // This is a "modified" BCP 47 language tag. Same semantics as BCP 47 tags, - // except that the separator is "+" and not "-". - std::vector<std::string> subtags = util::SplitAndLowercase(part, '+'); - subtags.erase(subtags.begin()); - if (subtags.size() == 1) { - set_language(subtags[0].c_str()); - } else if (subtags.size() == 2) { - set_language(subtags[0].c_str()); - - // The second tag can either be a region, a variant or a script. - switch (subtags[1].size()) { - case 2: - case 3: - set_region(subtags[1].c_str()); - break; - case 4: - if ('0' <= subtags[1][0] && subtags[1][0] <= '9') { - // This is a variant: fall through - } else { - set_script(subtags[1].c_str()); - break; - } - case 5: - case 6: - case 7: - case 8: - set_variant(subtags[1].c_str()); - break; - default: - return -1; - } - } else if (subtags.size() == 3) { - // The language is always the first subtag. - set_language(subtags[0].c_str()); - - // The second subtag can either be a script or a region code. - // If its size is 4, it's a script code, else it's a region code. - if (subtags[1].size() == 4) { - set_script(subtags[1].c_str()); - } else if (subtags[1].size() == 2 || subtags[1].size() == 3) { - set_region(subtags[1].c_str()); - } else { - return -1; - } - - // The third tag can either be a region code (if the second tag was - // a script), else a variant code. - if (subtags[2].size() >= 4) { - set_variant(subtags[2].c_str()); - } else { - set_region(subtags[2].c_str()); - } - } else if (subtags.size() == 4) { - set_language(subtags[0].c_str()); - set_script(subtags[1].c_str()); - set_region(subtags[2].c_str()); - set_variant(subtags[3].c_str()); - } else { + // except that the separator is "+" and not "-". Skip the prefix 'b+'. + if (!InitFromBcp47TagImpl(StringPiece(part).substr(2), '+')) { return -1; } - ++iter; - } else { - if ((part.length() == 2 || part.length() == 3) && is_alpha(part) && - part != "car") { + if ((part.length() == 2 || part.length() == 3) && is_alpha(part) && part != "car") { set_language(part.c_str()); ++iter; @@ -222,7 +230,6 @@ ssize_t LocaleValue::InitFromParts(std::vector<std::string>::iterator iter, } } } - return static_cast<ssize_t>(iter - start_iter); } diff --git a/tools/aapt2/Locale.h b/tools/aapt2/Locale.h index 3d73b2eb17bf..6d8b598415cc 100644 --- a/tools/aapt2/Locale.h +++ b/tools/aapt2/Locale.h @@ -41,6 +41,9 @@ struct LocaleValue { */ bool InitFromFilterString(const android::StringPiece& config); + // Initializes this LocaleValue from a BCP-47 locale tag. + bool InitFromBcp47Tag(const android::StringPiece& bcp47tag); + /** * Initialize this LocaleValue from parts of a vector. */ @@ -67,6 +70,8 @@ struct LocaleValue { inline bool operator>(const LocaleValue& o) const; private: + bool InitFromBcp47TagImpl(const android::StringPiece& bcp47tag, const char separator); + void set_language(const char* language); void set_region(const char* language); void set_script(const char* script); diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto index c1af88a1a74e..174b7f6b7c8c 100644 --- a/tools/aapt2/Resources.proto +++ b/tools/aapt2/Resources.proto @@ -16,19 +16,13 @@ syntax = "proto3"; +import "frameworks/base/tools/aapt2/Configuration.proto"; + package aapt.pb; option java_package = "com.android.aapt"; option optimize_for = LITE_RUNTIME; -// A configuration description that wraps the binary form of the C++ class -// aapt::ConfigDescription, with an added product definition. -// TODO(adamlesinski): Flesh this out to be represented in proto. -message ConfigDescription { - bytes data = 1; - string product = 2; -} - // A string pool that wraps the binary form of the C++ class android::ResStringPool. message StringPool { bytes data = 1; @@ -163,7 +157,7 @@ message Entry { // A Configuration/Value pair. message ConfigValue { - ConfigDescription config = 1; + Configuration config = 1; Value value = 2; } diff --git a/tools/aapt2/ResourcesInternal.proto b/tools/aapt2/ResourcesInternal.proto index 17604e4c6fe8..0b0a252a3452 100644 --- a/tools/aapt2/ResourcesInternal.proto +++ b/tools/aapt2/ResourcesInternal.proto @@ -16,6 +16,7 @@ syntax = "proto3"; +import "frameworks/base/tools/aapt2/Configuration.proto"; import "frameworks/base/tools/aapt2/Resources.proto"; package aapt.pb.internal; @@ -38,7 +39,7 @@ message CompiledFile { string resource_name = 1; // The configuration for which the resource is defined. - aapt.pb.ConfigDescription config = 2; + aapt.pb.Configuration config = 2; // The filesystem path to where the source file originated. // Mainly used to display helpful error messages. diff --git a/tools/aapt2/proto/ProtoHelpers.cpp b/tools/aapt2/proto/ProtoHelpers.cpp index 59ca8e484fbe..18f7e1d2ff7d 100644 --- a/tools/aapt2/proto/ProtoHelpers.cpp +++ b/tools/aapt2/proto/ProtoHelpers.cpp @@ -16,6 +16,8 @@ #include "proto/ProtoHelpers.h" +#include "Locale.h" + namespace aapt { void SerializeStringPoolToPb(const StringPool& pool, pb::StringPool* out_pb_pool) { @@ -70,27 +72,507 @@ SymbolState DeserializeVisibilityFromPb(pb::SymbolStatus_Visibility pb_visibilit return SymbolState::kUndefined; } -void SerializeConfig(const ConfigDescription& config, pb::ConfigDescription* out_pb_config) { - android::ResTable_config flat_config = config; - flat_config.size = sizeof(flat_config); - flat_config.swapHtoD(); - out_pb_config->set_data(&flat_config, sizeof(flat_config)); +void SerializeConfig(const ConfigDescription& config, pb::Configuration* out_pb_config) { + out_pb_config->set_mcc(config.mcc); + out_pb_config->set_mnc(config.mnc); + out_pb_config->set_locale(config.GetBcp47LanguageTag()); + + switch (config.screenLayout & ConfigDescription::MASK_LAYOUTDIR) { + case ConfigDescription::LAYOUTDIR_LTR: + out_pb_config->set_layout_direction(pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_LTR); + break; + + case ConfigDescription::LAYOUTDIR_RTL: + out_pb_config->set_layout_direction(pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_RTL); + break; + } + + out_pb_config->set_screen_width(config.screenWidth); + out_pb_config->set_screen_height(config.screenHeight); + out_pb_config->set_screen_width_dp(config.screenWidthDp); + out_pb_config->set_screen_height_dp(config.screenHeightDp); + out_pb_config->set_smallest_screen_width_dp(config.smallestScreenWidthDp); + + switch (config.screenLayout & ConfigDescription::MASK_SCREENSIZE) { + case ConfigDescription::SCREENSIZE_SMALL: + out_pb_config->set_screen_layout_size( + pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_SMALL); + break; + + case ConfigDescription::SCREENSIZE_NORMAL: + out_pb_config->set_screen_layout_size( + pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_NORMAL); + break; + + case ConfigDescription::SCREENSIZE_LARGE: + out_pb_config->set_screen_layout_size( + pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_LARGE); + break; + + case ConfigDescription::SCREENSIZE_XLARGE: + out_pb_config->set_screen_layout_size( + pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_XLARGE); + break; + } + + switch (config.screenLayout & ConfigDescription::MASK_SCREENLONG) { + case ConfigDescription::SCREENLONG_YES: + out_pb_config->set_screen_layout_long( + pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_LONG); + break; + + case ConfigDescription::SCREENLONG_NO: + out_pb_config->set_screen_layout_long( + pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_NOTLONG); + break; + } + + switch (config.screenLayout2 & ConfigDescription::MASK_SCREENROUND) { + case ConfigDescription::SCREENROUND_YES: + out_pb_config->set_screen_round(pb::Configuration_ScreenRound_SCREEN_ROUND_ROUND); + break; + + case ConfigDescription::SCREENROUND_NO: + out_pb_config->set_screen_round(pb::Configuration_ScreenRound_SCREEN_ROUND_NOTROUND); + break; + } + + switch (config.colorMode & ConfigDescription::MASK_WIDE_COLOR_GAMUT) { + case ConfigDescription::WIDE_COLOR_GAMUT_YES: + out_pb_config->set_wide_color_gamut(pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_WIDECG); + break; + + case ConfigDescription::WIDE_COLOR_GAMUT_NO: + out_pb_config->set_wide_color_gamut( + pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_NOWIDECG); + break; + } + + switch (config.colorMode & ConfigDescription::MASK_HDR) { + case ConfigDescription::HDR_YES: + out_pb_config->set_hdr(pb::Configuration_Hdr_HDR_HIGHDR); + break; + + case ConfigDescription::HDR_NO: + out_pb_config->set_hdr(pb::Configuration_Hdr_HDR_LOWDR); + break; + } + + switch (config.orientation) { + case ConfigDescription::ORIENTATION_PORT: + out_pb_config->set_orientation(pb::Configuration_Orientation_ORIENTATION_PORT); + break; + + case ConfigDescription::ORIENTATION_LAND: + out_pb_config->set_orientation(pb::Configuration_Orientation_ORIENTATION_LAND); + break; + + case ConfigDescription::ORIENTATION_SQUARE: + out_pb_config->set_orientation(pb::Configuration_Orientation_ORIENTATION_SQUARE); + break; + } + + switch (config.uiMode & ConfigDescription::MASK_UI_MODE_TYPE) { + case ConfigDescription::UI_MODE_TYPE_NORMAL: + out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_NORMAL); + break; + + case ConfigDescription::UI_MODE_TYPE_DESK: + out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_DESK); + break; + + case ConfigDescription::UI_MODE_TYPE_CAR: + out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_CAR); + break; + + case ConfigDescription::UI_MODE_TYPE_TELEVISION: + out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_TELEVISION); + break; + + case ConfigDescription::UI_MODE_TYPE_APPLIANCE: + out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_APPLIANCE); + break; + + case ConfigDescription::UI_MODE_TYPE_WATCH: + out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_WATCH); + break; + + case ConfigDescription::UI_MODE_TYPE_VR_HEADSET: + out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_VRHEADSET); + break; + } + + switch (config.uiMode & ConfigDescription::MASK_UI_MODE_NIGHT) { + case ConfigDescription::UI_MODE_NIGHT_YES: + out_pb_config->set_ui_mode_night(pb::Configuration_UiModeNight_UI_MODE_NIGHT_NIGHT); + break; + + case ConfigDescription::UI_MODE_NIGHT_NO: + out_pb_config->set_ui_mode_night(pb::Configuration_UiModeNight_UI_MODE_NIGHT_NOTNIGHT); + break; + } + + out_pb_config->set_density(config.density); + + switch (config.touchscreen) { + case ConfigDescription::TOUCHSCREEN_NOTOUCH: + out_pb_config->set_touchscreen(pb::Configuration_Touchscreen_TOUCHSCREEN_NOTOUCH); + break; + + case ConfigDescription::TOUCHSCREEN_STYLUS: + out_pb_config->set_touchscreen(pb::Configuration_Touchscreen_TOUCHSCREEN_STYLUS); + break; + + case ConfigDescription::TOUCHSCREEN_FINGER: + out_pb_config->set_touchscreen(pb::Configuration_Touchscreen_TOUCHSCREEN_FINGER); + break; + } + + switch (config.inputFlags & ConfigDescription::MASK_KEYSHIDDEN) { + case ConfigDescription::KEYSHIDDEN_NO: + out_pb_config->set_keys_hidden(pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSEXPOSED); + break; + + case ConfigDescription::KEYSHIDDEN_YES: + out_pb_config->set_keys_hidden(pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSHIDDEN); + break; + + case ConfigDescription::KEYSHIDDEN_SOFT: + out_pb_config->set_keys_hidden(pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSSOFT); + break; + } + + switch (config.keyboard) { + case ConfigDescription::KEYBOARD_NOKEYS: + out_pb_config->set_keyboard(pb::Configuration_Keyboard_KEYBOARD_NOKEYS); + break; + + case ConfigDescription::KEYBOARD_QWERTY: + out_pb_config->set_keyboard(pb::Configuration_Keyboard_KEYBOARD_QWERTY); + break; + + case ConfigDescription::KEYBOARD_12KEY: + out_pb_config->set_keyboard(pb::Configuration_Keyboard_KEYBOARD_TWELVEKEY); + break; + } + + switch (config.inputFlags & ConfigDescription::MASK_NAVHIDDEN) { + case ConfigDescription::NAVHIDDEN_NO: + out_pb_config->set_nav_hidden(pb::Configuration_NavHidden_NAV_HIDDEN_NAVEXPOSED); + break; + + case ConfigDescription::NAVHIDDEN_YES: + out_pb_config->set_nav_hidden(pb::Configuration_NavHidden_NAV_HIDDEN_NAVHIDDEN); + break; + } + + switch (config.navigation) { + case ConfigDescription::NAVIGATION_NONAV: + out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_NONAV); + break; + + case ConfigDescription::NAVIGATION_DPAD: + out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_DPAD); + break; + + case ConfigDescription::NAVIGATION_TRACKBALL: + out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_TRACKBALL); + break; + + case ConfigDescription::NAVIGATION_WHEEL: + out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_WHEEL); + break; + } + + out_pb_config->set_sdk_version(config.sdkVersion); } -bool DeserializeConfigDescriptionFromPb(const pb::ConfigDescription& pb_config, +bool DeserializeConfigDescriptionFromPb(const pb::Configuration& pb_config, ConfigDescription* out_config) { - // a ConfigDescription must be at least 4 bytes to store the size. - if (pb_config.data().size() < 4) { - return false; + out_config->mcc = static_cast<uint16_t>(pb_config.mcc()); + out_config->mnc = static_cast<uint16_t>(pb_config.mnc()); + + if (!pb_config.locale().empty()) { + LocaleValue lv; + if (!lv.InitFromBcp47Tag(pb_config.locale())) { + return false; + } + lv.WriteTo(out_config); + } + + switch (pb_config.layout_direction()) { + case pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_LTR: + out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_LAYOUTDIR) | + ConfigDescription::LAYOUTDIR_LTR; + break; + + case pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_RTL: + out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_LAYOUTDIR) | + ConfigDescription::LAYOUTDIR_RTL; + break; + + default: + break; } - const android::ResTable_config* config; - if (pb_config.data().size() > sizeof(*config)) { - return false; + out_config->smallestScreenWidthDp = static_cast<uint16_t>(pb_config.smallest_screen_width_dp()); + out_config->screenWidthDp = static_cast<uint16_t>(pb_config.screen_width_dp()); + out_config->screenHeightDp = static_cast<uint16_t>(pb_config.screen_height_dp()); + + switch (pb_config.screen_layout_size()) { + case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_SMALL: + out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) | + ConfigDescription::SCREENSIZE_SMALL; + break; + + case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_NORMAL: + out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) | + ConfigDescription::SCREENSIZE_NORMAL; + break; + + case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_LARGE: + out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) | + ConfigDescription::SCREENSIZE_LARGE; + break; + + case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_XLARGE: + out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) | + ConfigDescription::SCREENSIZE_XLARGE; + break; + + default: + break; + } + + switch (pb_config.screen_layout_long()) { + case pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_LONG: + out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENLONG) | + ConfigDescription::SCREENLONG_YES; + break; + + case pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_NOTLONG: + out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENLONG) | + ConfigDescription::SCREENLONG_NO; + break; + + default: + break; + } + + switch (pb_config.screen_round()) { + case pb::Configuration_ScreenRound_SCREEN_ROUND_ROUND: + out_config->screenLayout2 = + (out_config->screenLayout2 & ~ConfigDescription::MASK_SCREENROUND) | + ConfigDescription::SCREENROUND_YES; + break; + + case pb::Configuration_ScreenRound_SCREEN_ROUND_NOTROUND: + out_config->screenLayout2 = + (out_config->screenLayout2 & ~ConfigDescription::MASK_SCREENROUND) | + ConfigDescription::SCREENROUND_NO; + break; + + default: + break; + } + + switch (pb_config.wide_color_gamut()) { + case pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_WIDECG: + out_config->colorMode = (out_config->colorMode & ~ConfigDescription::MASK_WIDE_COLOR_GAMUT) | + ConfigDescription::WIDE_COLOR_GAMUT_YES; + break; + + case pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_NOWIDECG: + out_config->colorMode = (out_config->colorMode & ~ConfigDescription::MASK_WIDE_COLOR_GAMUT) | + ConfigDescription::WIDE_COLOR_GAMUT_NO; + break; + + default: + break; + } + + switch (pb_config.hdr()) { + case pb::Configuration_Hdr_HDR_HIGHDR: + out_config->colorMode = + (out_config->colorMode & ~ConfigDescription::MASK_HDR) | ConfigDescription::HDR_YES; + break; + + case pb::Configuration_Hdr_HDR_LOWDR: + out_config->colorMode = + (out_config->colorMode & ~ConfigDescription::MASK_HDR) | ConfigDescription::HDR_NO; + break; + + default: + break; + } + + switch (pb_config.orientation()) { + case pb::Configuration_Orientation_ORIENTATION_PORT: + out_config->orientation = ConfigDescription::ORIENTATION_PORT; + break; + + case pb::Configuration_Orientation_ORIENTATION_LAND: + out_config->orientation = ConfigDescription::ORIENTATION_LAND; + break; + + case pb::Configuration_Orientation_ORIENTATION_SQUARE: + out_config->orientation = ConfigDescription::ORIENTATION_SQUARE; + break; + + default: + break; + } + + switch (pb_config.ui_mode_type()) { + case pb::Configuration_UiModeType_UI_MODE_TYPE_NORMAL: + out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) | + ConfigDescription::UI_MODE_TYPE_NORMAL; + break; + + case pb::Configuration_UiModeType_UI_MODE_TYPE_DESK: + out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) | + ConfigDescription::UI_MODE_TYPE_DESK; + break; + + case pb::Configuration_UiModeType_UI_MODE_TYPE_CAR: + out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) | + ConfigDescription::UI_MODE_TYPE_CAR; + break; + + case pb::Configuration_UiModeType_UI_MODE_TYPE_TELEVISION: + out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) | + ConfigDescription::UI_MODE_TYPE_TELEVISION; + break; + + case pb::Configuration_UiModeType_UI_MODE_TYPE_APPLIANCE: + out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) | + ConfigDescription::UI_MODE_TYPE_APPLIANCE; + break; + + case pb::Configuration_UiModeType_UI_MODE_TYPE_WATCH: + out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) | + ConfigDescription::UI_MODE_TYPE_WATCH; + break; + + case pb::Configuration_UiModeType_UI_MODE_TYPE_VRHEADSET: + out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) | + ConfigDescription::UI_MODE_TYPE_VR_HEADSET; + break; + + default: + break; + } + + switch (pb_config.ui_mode_night()) { + case pb::Configuration_UiModeNight_UI_MODE_NIGHT_NIGHT: + out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_NIGHT) | + ConfigDescription::UI_MODE_NIGHT_YES; + break; + + case pb::Configuration_UiModeNight_UI_MODE_NIGHT_NOTNIGHT: + out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_NIGHT) | + ConfigDescription::UI_MODE_NIGHT_NO; + break; + + default: + break; + } + + out_config->density = static_cast<uint16_t>(pb_config.density()); + + switch (pb_config.touchscreen()) { + case pb::Configuration_Touchscreen_TOUCHSCREEN_NOTOUCH: + out_config->touchscreen = ConfigDescription::TOUCHSCREEN_NOTOUCH; + break; + + case pb::Configuration_Touchscreen_TOUCHSCREEN_STYLUS: + out_config->touchscreen = ConfigDescription::TOUCHSCREEN_STYLUS; + break; + + case pb::Configuration_Touchscreen_TOUCHSCREEN_FINGER: + out_config->touchscreen = ConfigDescription::TOUCHSCREEN_FINGER; + break; + + default: + break; + } + + switch (pb_config.keys_hidden()) { + case pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSEXPOSED: + out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_KEYSHIDDEN) | + ConfigDescription::KEYSHIDDEN_NO; + break; + + case pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSHIDDEN: + out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_KEYSHIDDEN) | + ConfigDescription::KEYSHIDDEN_YES; + break; + + case pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSSOFT: + out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_KEYSHIDDEN) | + ConfigDescription::KEYSHIDDEN_SOFT; + break; + + default: + break; + } + + switch (pb_config.keyboard()) { + case pb::Configuration_Keyboard_KEYBOARD_NOKEYS: + out_config->keyboard = ConfigDescription::KEYBOARD_NOKEYS; + break; + + case pb::Configuration_Keyboard_KEYBOARD_QWERTY: + out_config->keyboard = ConfigDescription::KEYBOARD_QWERTY; + break; + + case pb::Configuration_Keyboard_KEYBOARD_TWELVEKEY: + out_config->keyboard = ConfigDescription::KEYBOARD_12KEY; + break; + + default: + break; + } + + switch (pb_config.nav_hidden()) { + case pb::Configuration_NavHidden_NAV_HIDDEN_NAVEXPOSED: + out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_NAVHIDDEN) | + ConfigDescription::NAVHIDDEN_NO; + break; + + case pb::Configuration_NavHidden_NAV_HIDDEN_NAVHIDDEN: + out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_NAVHIDDEN) | + ConfigDescription::NAVHIDDEN_YES; + break; + + default: + break; + } + + switch (pb_config.navigation()) { + case pb::Configuration_Navigation_NAVIGATION_NONAV: + out_config->navigation = ConfigDescription::NAVIGATION_NONAV; + break; + + case pb::Configuration_Navigation_NAVIGATION_DPAD: + out_config->navigation = ConfigDescription::NAVIGATION_DPAD; + break; + + case pb::Configuration_Navigation_NAVIGATION_TRACKBALL: + out_config->navigation = ConfigDescription::NAVIGATION_TRACKBALL; + break; + + case pb::Configuration_Navigation_NAVIGATION_WHEEL: + out_config->navigation = ConfigDescription::NAVIGATION_WHEEL; + break; + + default: + break; } - config = reinterpret_cast<const android::ResTable_config*>(pb_config.data().data()); - out_config->copyFromDtoH(*config); + out_config->screenWidth = static_cast<uint16_t>(pb_config.screen_width()); + out_config->screenHeight = static_cast<uint16_t>(pb_config.screen_height()); + out_config->sdkVersion = static_cast<uint16_t>(pb_config.sdk_version()); return true; } diff --git a/tools/aapt2/proto/ProtoHelpers.h b/tools/aapt2/proto/ProtoHelpers.h index 2f268f44752c..714a2b27bf7f 100644 --- a/tools/aapt2/proto/ProtoHelpers.h +++ b/tools/aapt2/proto/ProtoHelpers.h @@ -20,11 +20,12 @@ #include "androidfw/ResourceTypes.h" #include "ConfigDescription.h" +#include "Configuration.pb.h" #include "ResourceTable.h" -#include "Source.h" -#include "StringPool.h" #include "Resources.pb.h" #include "ResourcesInternal.pb.h" +#include "Source.h" +#include "StringPool.h" namespace aapt { @@ -39,9 +40,9 @@ pb::SymbolStatus_Visibility SerializeVisibilityToPb(SymbolState state); SymbolState DeserializeVisibilityFromPb(pb::SymbolStatus_Visibility pb_visibility); -void SerializeConfig(const ConfigDescription& config, pb::ConfigDescription* out_pb_config); +void SerializeConfig(const ConfigDescription& config, pb::Configuration* out_pb_config); -bool DeserializeConfigDescriptionFromPb(const pb::ConfigDescription& pb_config, +bool DeserializeConfigDescriptionFromPb(const pb::Configuration& pb_config, ConfigDescription* out_config); pb::Reference_Type SerializeReferenceTypeToPb(Reference::Type type); diff --git a/tools/aapt2/proto/TableProtoDeserializer.cpp b/tools/aapt2/proto/TableProtoDeserializer.cpp index f4a2b1e19331..4a88d61ef84c 100644 --- a/tools/aapt2/proto/TableProtoDeserializer.cpp +++ b/tools/aapt2/proto/TableProtoDeserializer.cpp @@ -123,7 +123,7 @@ class PackagePbDeserializer { } for (const pb::ConfigValue& pb_config_value : pb_entry.config_value()) { - const pb::ConfigDescription& pb_config = pb_config_value.config(); + const pb::Configuration& pb_config = pb_config_value.config(); ConfigDescription config; if (!DeserializeConfigDescriptionFromPb(pb_config, &config)) { @@ -395,14 +395,16 @@ std::unique_ptr<ResourceFile> DeserializeCompiledFileFromPb( } file->name = name_ref.ToResourceName(); file->source.path = pb_file.source_path(); - DeserializeConfigDescriptionFromPb(pb_file.config(), &file->config); + if (!DeserializeConfigDescriptionFromPb(pb_file.config(), &file->config)) { + diag->Error(DiagMessage(source) << "invalid resource configuration in compiled file header"); + return {}; + } for (const pb::internal::CompiledFile_Symbol& pb_symbol : pb_file.exported_symbol()) { // Need to create an lvalue here so that nameRef can point to something real. if (!ResourceUtils::ParseResourceName(pb_symbol.resource_name(), &name_ref)) { diag->Error(DiagMessage(source) - << "invalid resource name for exported symbol in " - "compiled file header: " + << "invalid resource name for exported symbol in compiled file header: " << pb_file.resource_name()); return {}; } diff --git a/tools/aapt2/proto/TableProtoSerializer.cpp b/tools/aapt2/proto/TableProtoSerializer.cpp index 981b72ab7221..3d5407c137b1 100644 --- a/tools/aapt2/proto/TableProtoSerializer.cpp +++ b/tools/aapt2/proto/TableProtoSerializer.cpp @@ -282,10 +282,10 @@ CompiledFileOutputStream::CompiledFileOutputStream(ZeroCopyOutputStream* out) : } void CompiledFileOutputStream::EnsureAlignedWrite() { - const int padding = out_.ByteCount() % 4; - if (padding > 0) { + const int overflow = out_.ByteCount() % 4; + if (overflow > 0) { uint32_t zero = 0u; - out_.WriteRaw(&zero, padding); + out_.WriteRaw(&zero, 4 - overflow); } } @@ -322,10 +322,10 @@ CompiledFileInputStream::CompiledFileInputStream(const void* data, size_t size) : in_(static_cast<const uint8_t*>(data), size) {} void CompiledFileInputStream::EnsureAlignedRead() { - const int padding = in_.CurrentPosition() % 4; - if (padding > 0) { + const int overflow = in_.CurrentPosition() % 4; + if (overflow > 0) { // Reads are always 4 byte aligned. - in_.Skip(padding); + in_.Skip(4 - overflow); } } diff --git a/tools/aapt2/proto/TableProtoSerializer_test.cpp b/tools/aapt2/proto/TableProtoSerializer_test.cpp index 80608b3d9c05..8f6414c68a43 100644 --- a/tools/aapt2/proto/TableProtoSerializer_test.cpp +++ b/tools/aapt2/proto/TableProtoSerializer_test.cpp @@ -19,6 +19,7 @@ #include "ResourceTable.h" #include "test/Test.h" +using ::android::StringPiece; using ::google::protobuf::io::StringOutputStream; using ::testing::Eq; using ::testing::NotNull; @@ -239,4 +240,97 @@ TEST(TableProtoSerializer, DeserializeCorruptHeaderSafely) { EXPECT_FALSE(in_file_stream.ReadDataMetaData(&offset, &len)); } +static void ExpectConfigSerializes(const StringPiece& config_str) { + const ConfigDescription expected_config = test::ParseConfigOrDie(config_str); + pb::Configuration pb_config; + SerializeConfig(expected_config, &pb_config); + + ConfigDescription actual_config; + ASSERT_TRUE(DeserializeConfigDescriptionFromPb(pb_config, &actual_config)); + EXPECT_EQ(expected_config, actual_config); +} + +TEST(TableProtoSerializer, SerializeDeserializeConfiguration) { + ExpectConfigSerializes(""); + + ExpectConfigSerializes("mcc123"); + + ExpectConfigSerializes("mnc123"); + + ExpectConfigSerializes("en"); + ExpectConfigSerializes("en-rGB"); + ExpectConfigSerializes("b+en+GB"); + + ExpectConfigSerializes("ldltr"); + ExpectConfigSerializes("ldrtl"); + + ExpectConfigSerializes("sw3600dp"); + + ExpectConfigSerializes("w300dp"); + + ExpectConfigSerializes("h400dp"); + + ExpectConfigSerializes("small"); + ExpectConfigSerializes("normal"); + ExpectConfigSerializes("large"); + ExpectConfigSerializes("xlarge"); + + ExpectConfigSerializes("long"); + ExpectConfigSerializes("notlong"); + + ExpectConfigSerializes("round"); + ExpectConfigSerializes("notround"); + + ExpectConfigSerializes("widecg"); + ExpectConfigSerializes("nowidecg"); + + ExpectConfigSerializes("highdr"); + ExpectConfigSerializes("lowdr"); + + ExpectConfigSerializes("port"); + ExpectConfigSerializes("land"); + ExpectConfigSerializes("square"); + + ExpectConfigSerializes("desk"); + ExpectConfigSerializes("car"); + ExpectConfigSerializes("television"); + ExpectConfigSerializes("appliance"); + ExpectConfigSerializes("watch"); + ExpectConfigSerializes("vrheadset"); + + ExpectConfigSerializes("night"); + ExpectConfigSerializes("notnight"); + + ExpectConfigSerializes("300dpi"); + ExpectConfigSerializes("hdpi"); + + ExpectConfigSerializes("notouch"); + ExpectConfigSerializes("stylus"); + ExpectConfigSerializes("finger"); + + ExpectConfigSerializes("keysexposed"); + ExpectConfigSerializes("keyshidden"); + ExpectConfigSerializes("keyssoft"); + + ExpectConfigSerializes("nokeys"); + ExpectConfigSerializes("qwerty"); + ExpectConfigSerializes("12key"); + + ExpectConfigSerializes("navhidden"); + ExpectConfigSerializes("navexposed"); + + ExpectConfigSerializes("nonav"); + ExpectConfigSerializes("dpad"); + ExpectConfigSerializes("trackball"); + ExpectConfigSerializes("wheel"); + + ExpectConfigSerializes("300x200"); + + ExpectConfigSerializes("v8"); + + ExpectConfigSerializes( + "mcc123-mnc456-b+en+GB-ldltr-sw300dp-w300dp-h400dp-large-long-round-widecg-highdr-land-car-" + "night-xhdpi-stylus-keysexposed-qwerty-navhidden-dpad-300x200-v23"); +} + } // namespace aapt |