summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/idmap2/include/idmap2/FabricatedOverlay.h11
-rw-r--r--cmds/idmap2/libidmap2/FabricatedOverlay.cpp108
-rw-r--r--cmds/idmap2/tests/FabricatedOverlayTests.cpp25
-rw-r--r--cmds/idmap2/tests/IdmapTests.cpp10
-rw-r--r--cmds/idmap2/tests/R.h1
-rw-r--r--cmds/idmap2/tests/ResourceMappingTests.cpp8
-rw-r--r--cmds/uiautomator/library/core-src/com/android/uiautomator/core/UiDevice.java4
-rw-r--r--core/api/current.txt2
-rw-r--r--core/java/android/hardware/face/FaceManager.java40
-rw-r--r--core/java/android/hardware/face/IFaceAuthenticatorsRegisteredCallback.aidl35
-rw-r--r--core/java/android/hardware/face/IFaceService.aidl9
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintService.aidl2
-rw-r--r--core/java/android/service/dreams/IDreamManager.aidl2
-rw-r--r--core/proto/android/server/peopleservice.proto5
-rw-r--r--core/res/res/values/config.xml12
-rw-r--r--core/res/res/values/symbols.xml4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java4
-rwxr-xr-xlibs/androidfw/ApkAssets.cpp3
-rw-r--r--libs/androidfw/LoadedArsc.cpp17
-rw-r--r--libs/androidfw/include/androidfw/LoadedArsc.h3
-rw-r--r--libs/androidfw/include/androidfw/ResourceTypes.h2
-rw-r--r--media/java/android/media/AudioSystem.java4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java15
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LockIconViewController.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java86
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolver.kt27
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java20
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java92
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolverTest.kt132
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java47
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BiometricServiceProvider.java61
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BiometricServiceRegistry.java235
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BiometricStateCallback.java94
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceService.java221
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceServiceRegistry.java71
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java30
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java5
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java5
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java373
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceRegistry.java72
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java37
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java5
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java5
-rw-r--r--services/core/java/com/android/server/display/AutomaticBrightnessController.java5
-rw-r--r--services/core/java/com/android/server/dreams/DreamManagerService.java21
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java3
-rw-r--r--services/core/java/com/android/server/notification/ZenLog.java27
-rw-r--r--services/core/java/com/android/server/notification/ZenModeFiltering.java48
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java6
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerShellCommand.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java6
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityStartController.java3
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java51
-rw-r--r--services/people/java/com/android/server/people/data/ConversationInfo.java49
-rw-r--r--services/people/java/com/android/server/people/data/DataManager.java29
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/face/FaceServiceRegistryTest.java165
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/BiometricStateCallbackTest.java51
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceRegistryTest.java161
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java41
-rw-r--r--services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java106
-rw-r--r--services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java73
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java30
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java32
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java49
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java7
72 files changed, 1472 insertions, 1495 deletions
diff --git a/cmds/idmap2/include/idmap2/FabricatedOverlay.h b/cmds/idmap2/include/idmap2/FabricatedOverlay.h
index 65916d7ebf49..2fc4d43b798a 100644
--- a/cmds/idmap2/include/idmap2/FabricatedOverlay.h
+++ b/cmds/idmap2/include/idmap2/FabricatedOverlay.h
@@ -66,18 +66,21 @@ struct FabricatedOverlay {
private:
struct SerializedData {
- std::unique_ptr<uint8_t[]> data;
- size_t data_size;
- uint32_t crc;
- };
+ std::unique_ptr<uint8_t[]> pb_data;
+ size_t pb_data_size;
+ uint32_t pb_crc;
+ std::string sp_data;
+ };
Result<SerializedData*> InitializeData() const;
Result<uint32_t> GetCrc() const;
explicit FabricatedOverlay(pb::FabricatedOverlay&& overlay,
+ std::string&& string_pool_data_,
std::optional<uint32_t> crc_from_disk = {});
pb::FabricatedOverlay overlay_pb_;
+ std::string string_pool_data_;
std::optional<uint32_t> crc_from_disk_;
mutable std::optional<SerializedData> data_;
diff --git a/cmds/idmap2/libidmap2/FabricatedOverlay.cpp b/cmds/idmap2/libidmap2/FabricatedOverlay.cpp
index 4d49674efce3..5bbe08524c18 100644
--- a/cmds/idmap2/libidmap2/FabricatedOverlay.cpp
+++ b/cmds/idmap2/libidmap2/FabricatedOverlay.cpp
@@ -17,8 +17,9 @@
#include "idmap2/FabricatedOverlay.h"
#include <androidfw/ResourceUtils.h>
+#include <androidfw/StringPool.h>
#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <utils/ByteOrder.h>
#include <zlib.h>
@@ -30,6 +31,8 @@
namespace android::idmap2 {
+constexpr auto kBufferSize = 1024;
+
namespace {
bool Read32(std::istream& stream, uint32_t* out) {
uint32_t value;
@@ -47,8 +50,11 @@ void Write32(std::ostream& stream, uint32_t value) {
} // namespace
FabricatedOverlay::FabricatedOverlay(pb::FabricatedOverlay&& overlay,
+ std::string&& string_pool_data,
std::optional<uint32_t> crc_from_disk)
- : overlay_pb_(std::forward<pb::FabricatedOverlay>(overlay)), crc_from_disk_(crc_from_disk) {
+ : overlay_pb_(std::forward<pb::FabricatedOverlay>(overlay)),
+ string_pool_data_(std::move(string_pool_data)),
+ crc_from_disk_(crc_from_disk) {
}
FabricatedOverlay::Builder::Builder(const std::string& package_name, const std::string& name,
@@ -76,7 +82,11 @@ FabricatedOverlay::Builder& FabricatedOverlay::Builder::SetResourceValue(
}
Result<FabricatedOverlay> FabricatedOverlay::Builder::Build() {
- std::map<std::string, std::map<std::string, std::map<std::string, TargetValue>>> entries;
+ using EntryMap = std::map<std::string, TargetValue>;
+ using TypeMap = std::map<std::string, EntryMap>;
+ using PackageMap = std::map<std::string, TypeMap>;
+ PackageMap package_map;
+ android::StringPool string_pool;
for (const auto& res_entry : entries_) {
StringPiece package_substr;
StringPiece type_name;
@@ -96,11 +106,10 @@ Result<FabricatedOverlay> FabricatedOverlay::Builder::Build() {
return Error("resource name '%s' missing entry name", res_entry.resource_name.c_str());
}
- auto package = entries.find(package_name);
- if (package == entries.end()) {
- package = entries
- .insert(std::make_pair(
- package_name, std::map<std::string, std::map<std::string, TargetValue>>()))
+ auto package = package_map.find(package_name);
+ if (package == package_map.end()) {
+ package = package_map
+ .insert(std::make_pair(package_name, TypeMap()))
.first;
}
@@ -108,7 +117,7 @@ Result<FabricatedOverlay> FabricatedOverlay::Builder::Build() {
if (type == package->second.end()) {
type =
package->second
- .insert(std::make_pair(type_name.to_string(), std::map<std::string, TargetValue>()))
+ .insert(std::make_pair(type_name.to_string(), EntryMap()))
.first;
}
@@ -127,25 +136,32 @@ Result<FabricatedOverlay> FabricatedOverlay::Builder::Build() {
overlay_pb.set_target_package_name(target_package_name_);
overlay_pb.set_target_overlayable(target_overlayable_);
- for (const auto& package : entries) {
+ for (auto& package : package_map) {
auto package_pb = overlay_pb.add_packages();
package_pb->set_name(package.first);
- for (const auto& type : package.second) {
+ for (auto& type : package.second) {
auto type_pb = package_pb->add_types();
type_pb->set_name(type.first);
- for (const auto& entry : type.second) {
+ for (auto& entry : type.second) {
auto entry_pb = type_pb->add_entries();
entry_pb->set_name(entry.first);
pb::ResourceValue* value = entry_pb->mutable_res_value();
value->set_data_type(entry.second.data_type);
- value->set_data_value(entry.second.data_value);
+ if (entry.second.data_type == Res_value::TYPE_STRING) {
+ auto ref = string_pool.MakeRef(entry.second.data_string_value);
+ value->set_data_value(ref.index());
+ } else {
+ value->set_data_value(entry.second.data_value);
+ }
}
}
}
- return FabricatedOverlay(std::move(overlay_pb));
+ android::BigBuffer string_buffer(kBufferSize);
+ android::StringPool::FlattenUtf8(&string_buffer, string_pool, nullptr);
+ return FabricatedOverlay(std::move(overlay_pb), string_buffer.to_string());
}
Result<FabricatedOverlay> FabricatedOverlay::FromBinaryStream(std::istream& stream) {
@@ -163,48 +179,67 @@ Result<FabricatedOverlay> FabricatedOverlay::FromBinaryStream(std::istream& stre
return Error("Failed to read fabricated overlay version.");
}
- if (version != 1) {
+ if (version != 1 && version != 2) {
return Error("Invalid fabricated overlay version '%u'.", version);
}
uint32_t crc;
if (!Read32(stream, &crc)) {
- return Error("Failed to read fabricated overlay version.");
+ return Error("Failed to read fabricated overlay crc.");
}
pb::FabricatedOverlay overlay{};
- if (!overlay.ParseFromIstream(&stream)) {
- return Error("Failed read fabricated overlay proto.");
+ std::string sp_data;
+ if (version == 2) {
+ uint32_t sp_size;
+ if (!Read32(stream, &sp_size)) {
+ return Error("Failed read string pool size.");
+ }
+ std::string buf(sp_size, '\0');
+ if (!stream.read(buf.data(), sp_size)) {
+ return Error("Failed to read string pool.");
+ }
+ sp_data = buf;
+
+ if (!overlay.ParseFromIstream(&stream)) {
+ return Error("Failed read fabricated overlay proto.");
+ }
+ } else {
+ if (!overlay.ParseFromIstream(&stream)) {
+ return Error("Failed read fabricated overlay proto.");
+ }
}
// If the proto version is the latest version, then the contents of the proto must be the same
// when the proto is re-serialized; otherwise, the crc must be calculated because migrating the
// proto to the latest version will likely change the contents of the fabricated overlay.
- return FabricatedOverlay(std::move(overlay), version == kFabricatedOverlayCurrentVersion
+ return FabricatedOverlay(std::move(overlay), std::move(sp_data),
+ version == kFabricatedOverlayCurrentVersion
? std::optional<uint32_t>(crc)
: std::nullopt);
}
Result<FabricatedOverlay::SerializedData*> FabricatedOverlay::InitializeData() const {
if (!data_.has_value()) {
- auto size = overlay_pb_.ByteSizeLong();
- auto data = std::unique_ptr<uint8_t[]>(new uint8_t[size]);
+ auto pb_size = overlay_pb_.ByteSizeLong();
+ auto pb_data = std::unique_ptr<uint8_t[]>(new uint8_t[pb_size]);
// Ensure serialization is deterministic
- google::protobuf::io::ArrayOutputStream array_stream(data.get(), size);
+ google::protobuf::io::ArrayOutputStream array_stream(pb_data.get(), pb_size);
google::protobuf::io::CodedOutputStream output_stream(&array_stream);
output_stream.SetSerializationDeterministic(true);
overlay_pb_.SerializeWithCachedSizes(&output_stream);
- if (output_stream.HadError() || size != output_stream.ByteCount()) {
+ if (output_stream.HadError() || pb_size != output_stream.ByteCount()) {
return Error("Failed to serialize fabricated overlay.");
}
// Calculate the crc using the proto data and the version.
- uint32_t crc = crc32(0L, Z_NULL, 0);
- crc = crc32(crc, reinterpret_cast<const uint8_t*>(&kFabricatedOverlayCurrentVersion),
+ uint32_t pb_crc = crc32(0L, Z_NULL, 0);
+ pb_crc = crc32(pb_crc, reinterpret_cast<const uint8_t*>(&kFabricatedOverlayCurrentVersion),
sizeof(uint32_t));
- crc = crc32(crc, data.get(), size);
- data_ = SerializedData{std::move(data), size, crc};
+ pb_crc = crc32(pb_crc, pb_data.get(), pb_size);
+
+ data_ = SerializedData{std::move(pb_data), pb_size, pb_crc, string_pool_data_};
}
return &(*data_);
}
@@ -216,7 +251,7 @@ Result<uint32_t> FabricatedOverlay::GetCrc() const {
if (!data) {
return data.GetError();
}
- return (*data)->crc;
+ return (*data)->pb_crc;
}
Result<Unit> FabricatedOverlay::ToBinaryStream(std::ostream& stream) const {
@@ -227,8 +262,13 @@ Result<Unit> FabricatedOverlay::ToBinaryStream(std::ostream& stream) const {
Write32(stream, kFabricatedOverlayMagic);
Write32(stream, kFabricatedOverlayCurrentVersion);
- Write32(stream, (*data)->crc);
- stream.write(reinterpret_cast<const char*>((*data)->data.get()), (*data)->data_size);
+ Write32(stream, (*data)->pb_crc);
+ Write32(stream, (*data)->sp_data.length());
+ stream.write((*data)->sp_data.data(), (*data)->sp_data.length());
+ if (stream.bad()) {
+ return Error("Failed to write string pool data.");
+ }
+ stream.write(reinterpret_cast<const char*>((*data)->pb_data.get()), (*data)->pb_data_size);
if (stream.bad()) {
return Error("Failed to write serialized fabricated overlay.");
}
@@ -295,6 +335,14 @@ Result<OverlayData> FabContainer::GetOverlayData(const OverlayManifestInfo& info
}
}
}
+ const uint32_t string_pool_data_length = overlay_.string_pool_data_.length();
+ result.string_pool_data = OverlayData::InlineStringPoolData{
+ .data = std::unique_ptr<uint8_t[]>(new uint8_t[string_pool_data_length]),
+ .data_length = string_pool_data_length,
+ .string_pool_offset = 0,
+ };
+ memcpy(result.string_pool_data->data.get(), overlay_.string_pool_data_.data(),
+ string_pool_data_length);
return result;
}
diff --git a/cmds/idmap2/tests/FabricatedOverlayTests.cpp b/cmds/idmap2/tests/FabricatedOverlayTests.cpp
index 468ea0c634c1..91331ca1cc76 100644
--- a/cmds/idmap2/tests/FabricatedOverlayTests.cpp
+++ b/cmds/idmap2/tests/FabricatedOverlayTests.cpp
@@ -46,6 +46,7 @@ TEST(FabricatedOverlayTests, SetResourceValue) {
.SetResourceValue("com.example.target:integer/int1", Res_value::TYPE_INT_DEC, 1U)
.SetResourceValue("com.example.target.split:integer/int2", Res_value::TYPE_INT_DEC, 2U)
.SetResourceValue("string/int3", Res_value::TYPE_REFERENCE, 0x7f010000)
+ .SetResourceValue("com.example.target:string/string1", Res_value::TYPE_STRING, "foobar")
.Build();
ASSERT_TRUE(overlay);
auto container = FabricatedOverlayContainer::FromOverlay(std::move(*overlay));
@@ -59,8 +60,9 @@ TEST(FabricatedOverlayTests, SetResourceValue) {
auto pairs = container->GetOverlayData(*info);
ASSERT_TRUE(pairs);
- EXPECT_FALSE(pairs->string_pool_data.has_value());
- ASSERT_EQ(3U, pairs->pairs.size());
+ ASSERT_EQ(4U, pairs->pairs.size());
+ auto string_pool = ResStringPool(pairs->string_pool_data->data.get(),
+ pairs->string_pool_data->data_length, false);
auto& it = pairs->pairs[0];
ASSERT_EQ("com.example.target:integer/int1", it.resource_name);
@@ -77,6 +79,13 @@ TEST(FabricatedOverlayTests, SetResourceValue) {
ASSERT_EQ(Res_value::TYPE_REFERENCE, entry->data_type);
it = pairs->pairs[2];
+ ASSERT_EQ("com.example.target:string/string1", it.resource_name);
+ entry = std::get_if<TargetValue>(&it.value);
+ ASSERT_NE(nullptr, entry);
+ ASSERT_EQ(Res_value::TYPE_STRING, entry->data_type);
+ ASSERT_EQ(std::string("foobar"), string_pool.string8At(entry->data_value).value_or(""));
+
+ it = pairs->pairs[3];
ASSERT_EQ("com.example.target.split:integer/int2", it.resource_name);
entry = std::get_if<TargetValue>(&it.value);
ASSERT_NE(nullptr, entry);
@@ -104,6 +113,7 @@ TEST(FabricatedOverlayTests, SerializeAndDeserialize) {
FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "com.example.target")
.SetOverlayable("TestResources")
.SetResourceValue("com.example.target:integer/int1", Res_value::TYPE_INT_DEC, 1U)
+ .SetResourceValue("com.example.target:string/string1", Res_value::TYPE_STRING, "foobar")
.Build();
ASSERT_TRUE(overlay);
TemporaryFile tf;
@@ -126,7 +136,9 @@ TEST(FabricatedOverlayTests, SerializeAndDeserialize) {
auto pairs = (*container)->GetOverlayData(*info);
ASSERT_TRUE(pairs) << pairs.GetErrorMessage();
- EXPECT_EQ(1U, pairs->pairs.size());
+ EXPECT_EQ(2U, pairs->pairs.size());
+ auto string_pool = ResStringPool(pairs->string_pool_data->data.get(),
+ pairs->string_pool_data->data_length, false);
auto& it = pairs->pairs[0];
ASSERT_EQ("com.example.target:integer/int1", it.resource_name);
@@ -134,6 +146,13 @@ TEST(FabricatedOverlayTests, SerializeAndDeserialize) {
ASSERT_NE(nullptr, entry);
EXPECT_EQ(1U, entry->data_value);
EXPECT_EQ(Res_value::TYPE_INT_DEC, entry->data_type);
+
+ it = pairs->pairs[1];
+ ASSERT_EQ("com.example.target:string/string1", it.resource_name);
+ entry = std::get_if<TargetValue>(&it.value);
+ ASSERT_NE(nullptr, entry);
+ ASSERT_EQ(Res_value::TYPE_STRING, entry->data_type);
+ ASSERT_EQ(std::string("foobar"), string_pool.string8At(entry->data_value).value_or(""));
}
} // namespace android::idmap2
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index 738b9cf237c9..a3799f98c90c 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -263,6 +263,7 @@ TEST(IdmapTests, FabricatedOverlay) {
.SetOverlayable("TestResources")
.SetResourceValue("integer/int1", Res_value::TYPE_INT_DEC, 2U)
.SetResourceValue("string/str1", Res_value::TYPE_REFERENCE, 0x7f010000)
+ .SetResourceValue("string/str2", Res_value::TYPE_STRING, "foobar")
.Build();
ASSERT_TRUE(frro);
@@ -288,12 +289,19 @@ TEST(IdmapTests, FabricatedOverlay) {
ASSERT_EQ(data->GetTargetEntries().size(), 0U);
ASSERT_EQ(data->GetOverlayEntries().size(), 0U);
+ auto string_pool_data = data->GetStringPoolData();
+ auto string_pool = ResStringPool(string_pool_data.data(), string_pool_data.size(), false);
+
+
const auto& target_inline_entries = data->GetTargetInlineEntries();
- ASSERT_EQ(target_inline_entries.size(), 2U);
+ ASSERT_EQ(target_inline_entries.size(), 3U);
ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[0], R::target::integer::int1,
Res_value::TYPE_INT_DEC, 2U);
ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[1], R::target::string::str1,
Res_value::TYPE_REFERENCE, 0x7f010000);
+ ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[2], R::target::string::str2,
+ Res_value::TYPE_STRING,
+ (uint32_t) (string_pool.indexOfString(u"foobar", 6)).value_or(-1));
}
TEST(IdmapTests, FailCreateIdmapInvalidName) {
diff --git a/cmds/idmap2/tests/R.h b/cmds/idmap2/tests/R.h
index 89219c9c8213..ad998b9a7a4c 100644
--- a/cmds/idmap2/tests/R.h
+++ b/cmds/idmap2/tests/R.h
@@ -41,6 +41,7 @@ namespace R::target {
constexpr ResourceId policy_system = 0x7f02000c;
constexpr ResourceId policy_system_vendor = 0x7f02000d;
constexpr ResourceId str1 = 0x7f02000e;
+ constexpr ResourceId str2 = 0x7f02000f;
constexpr ResourceId str3 = 0x7f020010;
constexpr ResourceId str4 = 0x7f020011;
} // namespace string
diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp
index 32b3d1326d92..c05abcf31532 100644
--- a/cmds/idmap2/tests/ResourceMappingTests.cpp
+++ b/cmds/idmap2/tests/ResourceMappingTests.cpp
@@ -196,6 +196,7 @@ TEST(ResourceMappingTests, FabricatedOverlay) {
.SetOverlayable("TestResources")
.SetResourceValue("integer/int1", Res_value::TYPE_INT_DEC, 2U)
.SetResourceValue("string/str1", Res_value::TYPE_REFERENCE, 0x7f010000)
+ .SetResourceValue("string/str2", Res_value::TYPE_STRING, "foobar")
.Build();
ASSERT_TRUE(frro);
@@ -209,9 +210,14 @@ TEST(ResourceMappingTests, FabricatedOverlay) {
ASSERT_TRUE(resources) << resources.GetErrorMessage();
auto& res = *resources;
- ASSERT_EQ(res.GetTargetToOverlayMap().size(), 2U);
+ auto string_pool_data = res.GetStringPoolData();
+ auto string_pool = ResStringPool(string_pool_data.data(), string_pool_data.size(), false);
+
+ ASSERT_EQ(res.GetTargetToOverlayMap().size(), 3U);
ASSERT_EQ(res.GetOverlayToTargetMap().size(), 0U);
ASSERT_RESULT(MappingExists(res, R::target::string::str1, Res_value::TYPE_REFERENCE, 0x7f010000));
+ ASSERT_RESULT(MappingExists(res, R::target::string::str2, Res_value::TYPE_STRING,
+ (uint32_t) (string_pool.indexOfString(u"foobar", 6)).value_or(-1)));
ASSERT_RESULT(MappingExists(res, R::target::integer::int1, Res_value::TYPE_INT_DEC, 2U));
}
diff --git a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/UiDevice.java b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/UiDevice.java
index b1b432bf79ab..6fd2bf250e2c 100644
--- a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/UiDevice.java
+++ b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/UiDevice.java
@@ -380,7 +380,7 @@ public class UiDevice {
Tracer.trace();
Display display = getAutomatorBridge().getDefaultDisplay();
Point p = new Point();
- display.getSize(p);
+ display.getRealSize(p);
return p.x;
}
@@ -394,7 +394,7 @@ public class UiDevice {
Tracer.trace();
Display display = getAutomatorBridge().getDefaultDisplay();
Point p = new Point();
- display.getSize(p);
+ display.getRealSize(p);
return p.y;
}
diff --git a/core/api/current.txt b/core/api/current.txt
index 1eb4c02ed1c3..32bdec010647 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -41342,6 +41342,8 @@ package android.telephony {
field public static final String KEY_CARRIER_INSTANT_LETTERING_ESCAPED_CHARS_STRING = "carrier_instant_lettering_escaped_chars_string";
field public static final String KEY_CARRIER_INSTANT_LETTERING_INVALID_CHARS_STRING = "carrier_instant_lettering_invalid_chars_string";
field public static final String KEY_CARRIER_INSTANT_LETTERING_LENGTH_LIMIT_INT = "carrier_instant_lettering_length_limit_int";
+ field public static final String KEY_CARRIER_METERED_APN_TYPES_STRINGS = "carrier_metered_apn_types_strings";
+ field public static final String KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS = "carrier_metered_roaming_apn_types_strings";
field public static final String KEY_CARRIER_NAME_OVERRIDE_BOOL = "carrier_name_override_bool";
field public static final String KEY_CARRIER_NAME_STRING = "carrier_name_string";
field public static final String KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY = "carrier_nr_availabilities_int_array";
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 7247ef77afb4..7092e43596ec 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -29,7 +29,6 @@ import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricFaceConstants;
-import android.hardware.biometrics.BiometricStateListener;
import android.hardware.biometrics.CryptoObject;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.os.Binder;
@@ -675,45 +674,6 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
}
/**
- * Forwards BiometricStateListener to FaceService.
- *
- * @param listener new BiometricStateListener being added
- * @hide
- */
- public void registerBiometricStateListener(@NonNull BiometricStateListener listener) {
- try {
- mService.registerBiometricStateListener(listener);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Adds a callback that gets called when the service registers all of the face
- * authenticators (HALs).
- *
- * If the face authenticators are already registered when the callback is added, the
- * callback is invoked immediately.
- *
- * The callback is automatically removed after it's invoked.
- *
- * @hide
- */
- @RequiresPermission(USE_BIOMETRIC_INTERNAL)
- public void addAuthenticatorsRegisteredCallback(
- IFaceAuthenticatorsRegisteredCallback callback) {
- if (mService != null) {
- try {
- mService.addAuthenticatorsRegisteredCallback(callback);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- } else {
- Slog.w(TAG, "addAuthenticatorsRegisteredCallback(): Service not connected!");
- }
- }
-
- /**
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
diff --git a/core/java/android/hardware/face/IFaceAuthenticatorsRegisteredCallback.aidl b/core/java/android/hardware/face/IFaceAuthenticatorsRegisteredCallback.aidl
deleted file mode 100644
index 78f978d21ed7..000000000000
--- a/core/java/android/hardware/face/IFaceAuthenticatorsRegisteredCallback.aidl
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.hardware.face;
-
-import android.hardware.face.FaceSensorPropertiesInternal;
-import java.util.List;
-
-/**
- * Callback to notify FaceManager that FaceService has registered all of the
- * face authenticators (HALs).
- * See {@link android.hardware.face.IFaceService#registerAuthenticators}.
- *
- * @hide
- */
-oneway interface IFaceAuthenticatorsRegisteredCallback {
- /**
- * Notifies FaceManager that all of the face authenticators have been registered.
- *
- * @param sensors A consolidated list of sensor properties for all of the authenticators.
- */
- void onAllAuthenticatorsRegistered(in List<FaceSensorPropertiesInternal> sensors);
-}
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index 9b56f43a0f22..369248edd580 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -17,11 +17,9 @@ package android.hardware.face;
import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
-import android.hardware.biometrics.IBiometricStateListener;
import android.hardware.biometrics.IInvalidationCallback;
import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.ITestSessionCallback;
-import android.hardware.face.IFaceAuthenticatorsRegisteredCallback;
import android.hardware.face.IFaceServiceReceiver;
import android.hardware.face.Face;
import android.hardware.face.FaceSensorPropertiesInternal;
@@ -165,11 +163,4 @@ interface IFaceService {
// hidlSensors must be non-null and empty. See AuthService.java
@EnforcePermission("USE_BIOMETRIC_INTERNAL")
void registerAuthenticators(in List<FaceSensorPropertiesInternal> hidlSensors);
-
- // Adds a callback which gets called when the service registers all of the face
- // authenticators. The callback is automatically removed after it's invoked.
- void addAuthenticatorsRegisteredCallback(IFaceAuthenticatorsRegisteredCallback callback);
-
- // Registers BiometricStateListener.
- void registerBiometricStateListener(IBiometricStateListener listener);
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 1ba9a0471c88..cc7ed183ed64 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -202,10 +202,8 @@ interface IFingerprintService {
void setSidefpsController(in ISidefpsController controller);
// Registers BiometricStateListener.
- @EnforcePermission("USE_BIOMETRIC_INTERNAL")
void registerBiometricStateListener(IBiometricStateListener listener);
// Sends a power button pressed event to all listeners.
- @EnforcePermission("USE_BIOMETRIC_INTERNAL")
oneway void onPowerPressed();
}
diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl
index 3e0deeb556e9..53ae6576ef95 100644
--- a/core/java/android/service/dreams/IDreamManager.aidl
+++ b/core/java/android/service/dreams/IDreamManager.aidl
@@ -35,6 +35,8 @@ interface IDreamManager {
void testDream(int userId, in ComponentName componentName);
@UnsupportedAppUsage
boolean isDreaming();
+ @UnsupportedAppUsage
+ boolean isDreamingOrInPreview();
void finishSelf(in IBinder token, boolean immediate);
void startDozing(in IBinder token, int screenState, int screenBrightness);
void stopDozing(in IBinder token);
diff --git a/core/proto/android/server/peopleservice.proto b/core/proto/android/server/peopleservice.proto
index c465233036c4..a96ec41d3708 100644
--- a/core/proto/android/server/peopleservice.proto
+++ b/core/proto/android/server/peopleservice.proto
@@ -62,7 +62,10 @@ message ConversationInfoProto {
// The timestamp of the last event in millis.
optional int64 last_event_timestamp = 9;
- // Next tag: 10
+ // The timestamp this conversation was created in millis.
+ optional int64 creation_timestamp = 10;
+
+ // Next tag: 11
}
// On disk data of events.
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 9faf5e85c31f..9890614c010c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2000,6 +2000,18 @@
are controlled together (aliasing is true) or not. -->
<bool name="config_alias_ring_notif_stream_types">true</bool>
+ <!-- The number of volume steps for the notification stream -->
+ <integer name="config_audio_notif_vol_steps">7</integer>
+
+ <!-- The default volume for the notification stream -->
+ <integer name="config_audio_notif_vol_default">5</integer>
+
+ <!-- The number of volume steps for the ring stream -->
+ <integer name="config_audio_ring_vol_steps">7</integer>
+
+ <!-- The default volume for the ring stream -->
+ <integer name="config_audio_ring_vol_default">5</integer>
+
<!-- Flag indicating whether platform level volume adjustments are enabled for remote sessions
on grouped devices. -->
<bool name="config_volumeAdjustmentForRemoteGroupSessions">true</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 51712ff5e35f..00dab0416af1 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -276,6 +276,10 @@
<java-symbol type="bool" name="action_bar_embed_tabs" />
<java-symbol type="bool" name="action_bar_expanded_action_views_exclusive" />
<java-symbol type="bool" name="config_alias_ring_notif_stream_types" />
+ <java-symbol type="integer" name="config_audio_notif_vol_default" />
+ <java-symbol type="integer" name="config_audio_notif_vol_steps" />
+ <java-symbol type="integer" name="config_audio_ring_vol_default" />
+ <java-symbol type="integer" name="config_audio_ring_vol_steps" />
<java-symbol type="bool" name="config_avoidGfxAccel" />
<java-symbol type="bool" name="config_bluetooth_address_validation" />
<java-symbol type="integer" name="config_chooser_max_targets_per_row" />
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
index a0e22011b5d0..7619646804ad 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
@@ -288,8 +288,10 @@ public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListen
if (mTargetViewContainer.getVisibility() != View.VISIBLE) {
mTargetViewContainer.getViewTreeObserver().addOnPreDrawListener(this);
- mTargetViewContainer.show();
}
+ // always invoke show, since the target might still be VISIBLE while playing hide animation,
+ // so we want to ensure it will show back again
+ mTargetViewContainer.show();
}
/** Animates the magnetic dismiss target out and then sets it to GONE. */
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index 2beb33abe782..9aa37872b8de 100755
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -141,6 +141,9 @@ std::unique_ptr<ApkAssets> ApkAssets::LoadImpl(std::unique_ptr<Asset> resources_
return {};
}
loaded_arsc = LoadedArsc::Load(data, length, loaded_idmap.get(), property_flags);
+ } else if (loaded_idmap != nullptr &&
+ IsFabricatedOverlay(std::string(loaded_idmap->OverlayApkPath()))) {
+ loaded_arsc = LoadedArsc::Load(loaded_idmap.get());
} else {
loaded_arsc = LoadedArsc::CreateEmpty();
}
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index 35b6170fae5b..5b69cca2d747 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -820,6 +820,13 @@ bool LoadedArsc::LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap,
return true;
}
+bool LoadedArsc::LoadStringPool(const LoadedIdmap* loaded_idmap) {
+ if (loaded_idmap != nullptr) {
+ global_string_pool_ = util::make_unique<OverlayStringPool>(loaded_idmap);
+ }
+ return true;
+}
+
std::unique_ptr<LoadedArsc> LoadedArsc::Load(incfs::map_ptr<void> data,
const size_t length,
const LoadedIdmap* loaded_idmap,
@@ -855,6 +862,16 @@ std::unique_ptr<LoadedArsc> LoadedArsc::Load(incfs::map_ptr<void> data,
return loaded_arsc;
}
+std::unique_ptr<LoadedArsc> LoadedArsc::Load(const LoadedIdmap* loaded_idmap) {
+ ATRACE_NAME("LoadedArsc::Load");
+
+ // Not using make_unique because the constructor is private.
+ std::unique_ptr<LoadedArsc> loaded_arsc(new LoadedArsc());
+ loaded_arsc->LoadStringPool(loaded_idmap);
+ return loaded_arsc;
+}
+
+
std::unique_ptr<LoadedArsc> LoadedArsc::CreateEmpty() {
return std::unique_ptr<LoadedArsc>(new LoadedArsc());
}
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index b3d6a4dcb955..e45963950b04 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -314,6 +314,8 @@ class LoadedArsc {
const LoadedIdmap* loaded_idmap = nullptr,
package_property_t property_flags = 0U);
+ static std::unique_ptr<LoadedArsc> Load(const LoadedIdmap* loaded_idmap = nullptr);
+
// Create an empty LoadedArsc. This is used when an APK has no resources.arsc.
static std::unique_ptr<LoadedArsc> CreateEmpty();
@@ -338,6 +340,7 @@ class LoadedArsc {
LoadedArsc() = default;
bool LoadTable(
const Chunk& chunk, const LoadedIdmap* loaded_idmap, package_property_t property_flags);
+ bool LoadStringPool(const LoadedIdmap* loaded_idmap);
std::unique_ptr<ResStringPool> global_string_pool_ = util::make_unique<ResStringPool>();
std::vector<std::unique_ptr<const LoadedPackage>> packages_;
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 3d66244646d5..8c614bcf7145 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -53,7 +53,7 @@ constexpr const uint32_t kFabricatedOverlayMagic = 0x4f525246; // FRRO (big endi
// The version should only be changed when a backwards-incompatible change must be made to the
// fabricated overlay file format. Old fabricated overlays must be migrated to the new file format
// to prevent losing fabricated overlay data.
-constexpr const uint32_t kFabricatedOverlayCurrentVersion = 1;
+constexpr const uint32_t kFabricatedOverlayCurrentVersion = 2;
// Returns whether or not the path represents a fabricated overlay.
bool IsFabricatedOverlay(const std::string& path);
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 444366adf265..c666140765aa 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -2294,10 +2294,10 @@ public class AudioSystem
public static int[] DEFAULT_STREAM_VOLUME = new int[] {
4, // STREAM_VOICE_CALL
7, // STREAM_SYSTEM
- 5, // STREAM_RING
+ 5, // STREAM_RING // configured in AudioService by config_audio_notif_vol_default
5, // STREAM_MUSIC
6, // STREAM_ALARM
- 5, // STREAM_NOTIFICATION
+ 5, // STREAM_NOTIFICATION // configured in AudioService by config_audio_ring_vol_default
7, // STREAM_BLUETOOTH_SCO
7, // STREAM_SYSTEM_ENFORCED
5, // STREAM_DTMF
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 35202742bb90..2f9bc1c59624 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -54,7 +54,6 @@ import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.hardware.SensorPrivacyManager;
-import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricSourceType;
@@ -2019,13 +2018,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
// in case authenticators aren't registered yet at this point:
mAuthController.addCallback(new AuthController.Callback() {
@Override
- public void onAllAuthenticatorsRegistered(
- @BiometricAuthenticator.Modality int modality) {
+ public void onAllAuthenticatorsRegistered() {
mainExecutor.execute(() -> updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE));
}
@Override
- public void onEnrollmentsChanged(@BiometricAuthenticator.Modality int modality) {
+ public void onEnrollmentsChanged() {
mainExecutor.execute(() -> updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE));
}
});
@@ -2566,8 +2564,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
private boolean isOnlyFaceEnrolled() {
- return isFaceAuthEnabledForUser(getCurrentUser())
- && !isUnlockWithFingerprintPossible(getCurrentUser());
+ return isFaceEnrolled()
+ && !getCachedIsUnlockWithFingerprintPossible(sCurrentUser);
}
private void maybeLogListenerModelData(KeyguardListenModel model) {
@@ -2682,7 +2680,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
return isUnlockWithFacePossible(userId) || isUnlockWithFingerprintPossible(userId);
}
- private boolean isUnlockWithFingerprintPossible(int userId) {
+ @VisibleForTesting
+ boolean isUnlockWithFingerprintPossible(int userId) {
+ // TODO (b/242022358), make this rely on onEnrollmentChanged event and update it only once.
mIsUnlockWithFingerprintPossible.put(userId, mFpm != null && mFpm.isHardwareDetected()
&& !isFingerprintDisabled(userId) && mFpm.hasEnrolledTemplates(userId));
return mIsUnlockWithFingerprintPossible.get(userId);
@@ -2704,6 +2704,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
* If face hardware is available, user has enrolled and enabled auth via setting.
*/
public boolean isFaceAuthEnabledForUser(int userId) {
+ // TODO (b/242022358), make this rely on onEnrollmentChanged event and update it only once.
updateFaceEnrolled(userId);
return mIsFaceEnrolled;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index d6974dfac570..06e1828ef9f4 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -16,7 +16,6 @@
package com.android.keyguard;
-import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT;
import static com.android.keyguard.LockIconView.ICON_FINGERPRINT;
@@ -30,7 +29,6 @@ import android.content.res.Resources;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.AnimatedStateListDrawable;
-import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricSourceType;
import android.os.Process;
import android.os.VibrationAttributes;
@@ -703,17 +701,13 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
private final AuthController.Callback mAuthControllerCallback = new AuthController.Callback() {
@Override
- public void onAllAuthenticatorsRegistered(@BiometricAuthenticator.Modality int modality) {
- if (modality == TYPE_FINGERPRINT) {
- updateUdfpsConfig();
- }
+ public void onAllAuthenticatorsRegistered() {
+ updateUdfpsConfig();
}
@Override
- public void onEnrollmentsChanged(@BiometricAuthenticator.Modality int modality) {
- if (modality == TYPE_FINGERPRINT) {
- updateUdfpsConfig();
- }
+ public void onEnrollmentsChanged() {
+ updateUdfpsConfig();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 282f25104c44..47ff59cfc281 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -46,7 +46,6 @@ import android.hardware.biometrics.PromptInfo;
import android.hardware.display.DisplayManager;
import android.hardware.face.FaceManager;
import android.hardware.face.FaceSensorPropertiesInternal;
-import android.hardware.face.IFaceAuthenticatorsRegisteredCallback;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
@@ -157,6 +156,25 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
}
};
+ private final IFingerprintAuthenticatorsRegisteredCallback
+ mFingerprintAuthenticatorsRegisteredCallback =
+ new IFingerprintAuthenticatorsRegisteredCallback.Stub() {
+ @Override
+ public void onAllAuthenticatorsRegistered(
+ List<FingerprintSensorPropertiesInternal> sensors) {
+ mHandler.post(() -> handleAllFingerprintAuthenticatorsRegistered(sensors));
+ }
+ };
+
+ private final BiometricStateListener mBiometricStateListener =
+ new BiometricStateListener() {
+ @Override
+ public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {
+ mHandler.post(
+ () -> handleEnrollmentsChanged(userId, sensorId, hasEnrollments));
+ }
+ };
+
@VisibleForTesting
final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -231,8 +249,8 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
List<FingerprintSensorPropertiesInternal> sensors) {
mExecution.assertIsMainThread();
if (DEBUG) {
- Log.d(TAG, "handleAllFingerprintAuthenticatorsRegistered | sensors: "
- + Arrays.toString(sensors.toArray()));
+ Log.d(TAG, "handleAllAuthenticatorsRegistered | sensors: " + Arrays.toString(
+ sensors.toArray()));
}
mAllFingerprintAuthenticatorsRegistered = true;
mFpProps = sensors;
@@ -274,42 +292,15 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
mSidefpsController = mSidefpsControllerFactory.get();
}
- mFingerprintManager.registerBiometricStateListener(new BiometricStateListener() {
- @Override
- public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {
- mHandler.post(() -> handleEnrollmentsChanged(
- TYPE_FINGERPRINT, userId, sensorId, hasEnrollments));
- }
- });
+ mFingerprintManager.registerBiometricStateListener(mBiometricStateListener);
updateFingerprintLocation();
for (Callback cb : mCallbacks) {
- cb.onAllAuthenticatorsRegistered(TYPE_FINGERPRINT);
+ cb.onAllAuthenticatorsRegistered();
}
}
- private void handleAllFaceAuthenticatorsRegistered(List<FaceSensorPropertiesInternal> sensors) {
- mExecution.assertIsMainThread();
- if (DEBUG) {
- Log.d(TAG, "handleAllFaceAuthenticatorsRegistered | sensors: " + Arrays.toString(
- sensors.toArray()));
- }
-
- mFaceManager.registerBiometricStateListener(new BiometricStateListener() {
- @Override
- public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {
- mHandler.post(() -> handleEnrollmentsChanged(
- TYPE_FACE, userId, sensorId, hasEnrollments));
- }
- });
-
- for (Callback cb : mCallbacks) {
- cb.onAllAuthenticatorsRegistered(TYPE_FACE);
- }
- }
-
- private void handleEnrollmentsChanged(@Modality int modality, int userId, int sensorId,
- boolean hasEnrollments) {
+ private void handleEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {
mExecution.assertIsMainThread();
Log.d(TAG, "handleEnrollmentsChanged, userId: " + userId + ", sensorId: " + sensorId
+ ", hasEnrollments: " + hasEnrollments);
@@ -323,7 +314,7 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
}
}
for (Callback cb : mCallbacks) {
- cb.onEnrollmentsChanged(modality);
+ cb.onEnrollmentsChanged();
}
}
@@ -709,26 +700,7 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
if (mFingerprintManager != null) {
mFingerprintManager.addAuthenticatorsRegisteredCallback(
- new IFingerprintAuthenticatorsRegisteredCallback.Stub() {
- @Override
- public void onAllAuthenticatorsRegistered(
- List<FingerprintSensorPropertiesInternal> sensors) {
- mHandler.post(() ->
- handleAllFingerprintAuthenticatorsRegistered(sensors));
- }
- });
- }
- if (mFaceManager != null) {
- mFaceManager.addAuthenticatorsRegisteredCallback(
- new IFaceAuthenticatorsRegisteredCallback.Stub() {
- @Override
- public void onAllAuthenticatorsRegistered(
- List<FaceSensorPropertiesInternal> sensors) {
- mHandler.post(() ->
- handleAllFaceAuthenticatorsRegistered(sensors));
- }
- }
- );
+ mFingerprintAuthenticatorsRegisteredCallback);
}
mStableDisplaySize = mDisplayManager.getStableDisplaySize();
@@ -1144,13 +1116,13 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
* Called when authenticators are registered. If authenticators are already
* registered before this call, this callback will never be triggered.
*/
- default void onAllAuthenticatorsRegistered(@Modality int modality) {}
+ default void onAllAuthenticatorsRegistered() {}
/**
- * Called when enrollments have changed. This is called after boot and on changes to
+ * Called when UDFPS enrollments have changed. This is called after boot and on changes to
* enrollment.
*/
- default void onEnrollmentsChanged(@Modality int modality) {}
+ default void onEnrollmentsChanged() {}
/**
* Called when the biometric prompt starts showing.
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index fd3f6007d8a9..38fab8ffbfad 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -308,7 +308,7 @@ class AuthRippleController @Inject constructor(
private val authControllerCallback =
object : AuthController.Callback {
- override fun onAllAuthenticatorsRegistered(modality: Int) {
+ override fun onAllAuthenticatorsRegistered() {
updateUdfpsDependentParams()
updateSensorLocation()
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
index 7da2cf150147..a9e310d25f9c 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
@@ -16,15 +16,12 @@
package com.android.systemui.doze;
-import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
-
import static com.android.systemui.doze.DozeMachine.State.DOZE;
import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD;
import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSED;
import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSING;
import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSE_DONE;
-import android.hardware.biometrics.BiometricAuthenticator;
import android.os.Handler;
import android.util.Log;
import android.view.Display;
@@ -235,17 +232,13 @@ public class DozeScreenState implements DozeMachine.Part {
private final AuthController.Callback mAuthControllerCallback = new AuthController.Callback() {
@Override
- public void onAllAuthenticatorsRegistered(@BiometricAuthenticator.Modality int modality) {
- if (modality == TYPE_FINGERPRINT) {
- updateUdfpsController();
- }
+ public void onAllAuthenticatorsRegistered() {
+ updateUdfpsController();
}
@Override
- public void onEnrollmentsChanged(@BiometricAuthenticator.Modality int modality) {
- if (modality == TYPE_FINGERPRINT) {
- updateUdfpsController();
- }
+ public void onEnrollmentsChanged() {
+ updateUdfpsController();
}
};
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 997a6e554364..da6c163b1eea 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -16,8 +16,6 @@
package com.android.systemui.doze;
-import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
-
import static com.android.systemui.doze.DozeLog.REASON_SENSOR_QUICK_PICKUP;
import static com.android.systemui.doze.DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS;
import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_DISPLAY;
@@ -31,7 +29,6 @@ import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.hardware.TriggerEvent;
import android.hardware.TriggerEventListener;
-import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.display.AmbientDisplayConfiguration;
import android.net.Uri;
import android.os.Handler;
@@ -838,17 +835,13 @@ public class DozeSensors {
private final AuthController.Callback mAuthControllerCallback = new AuthController.Callback() {
@Override
- public void onAllAuthenticatorsRegistered(@BiometricAuthenticator.Modality int modality) {
- if (modality == TYPE_FINGERPRINT) {
- updateUdfpsEnrolled();
- }
+ public void onAllAuthenticatorsRegistered() {
+ updateUdfpsEnrolled();
}
@Override
- public void onEnrollmentsChanged(@BiometricAuthenticator.Modality int modality) {
- if (modality == TYPE_FINGERPRINT) {
- updateUdfpsEnrolled();
- }
+ public void onEnrollmentsChanged() {
+ updateUdfpsEnrolled();
}
private void updateUdfpsEnrolled() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolver.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolver.kt
index c71eade79cdf..0c49713131e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolver.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolver.kt
@@ -16,7 +16,9 @@
package com.android.systemui.statusbar.notification.collection
+import android.app.Notification
import android.content.Context
+import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.service.notification.StatusBarNotification
import android.util.Log
@@ -39,17 +41,28 @@ class TargetSdkResolver @Inject constructor(
}
private fun resolveNotificationSdk(sbn: StatusBarNotification): Int {
+ val applicationInfo = getApplicationInfoFromExtras(sbn.notification)
+ ?: getApplicationInfoFromPackageManager(sbn)
+
+ return applicationInfo?.targetSdkVersion ?: 0
+ }
+
+ private fun getApplicationInfoFromExtras(notification: Notification): ApplicationInfo? =
+ notification.extras.getParcelable(
+ Notification.EXTRA_BUILDER_APPLICATION_INFO,
+ ApplicationInfo::class.java
+ )
+
+ private fun getApplicationInfoFromPackageManager(sbn: StatusBarNotification): ApplicationInfo? {
val pmUser = CentralSurfaces.getPackageManagerForUser(context, sbn.user.identifier)
- var targetSdk = 0
- // Extract target SDK version.
- try {
- val info = pmUser.getApplicationInfo(sbn.packageName, 0)
- targetSdk = info.targetSdkVersion
+
+ return try {
+ pmUser.getApplicationInfo(sbn.packageName, 0)
} catch (ex: PackageManager.NameNotFoundException) {
Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.packageName, ex)
+ null
}
- return targetSdk
}
private val TAG = "TargetSdkResolver"
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index cde30af447f6..c281965550e4 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -16,7 +16,6 @@
package com.android.keyguard;
-import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT;
import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE;
import static android.telephony.SubscriptionManager.NAME_SOURCE_CARRIER_ID;
@@ -582,6 +581,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
@Test
public void testTriesToAuthenticate_whenBouncer() {
fingerprintIsNotEnrolled();
+ faceAuthEnabled();
setKeyguardBouncerVisibility(true);
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
@@ -1006,7 +1006,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
// WHEN udfps is now enrolled
when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(true);
- callback.onEnrollmentsChanged(TYPE_FINGERPRINT);
+ callback.onEnrollmentsChanged();
// THEN isUdfspEnrolled is TRUE
assertThat(mKeyguardUpdateMonitor.isUdfpsEnrolled()).isTrue();
@@ -1219,6 +1219,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
public void testShouldListenForFace_whenFaceIsAlreadyAuthenticated_returnsFalse()
throws RemoteException {
// Face auth should run when the following is true.
+ faceAuthEnabled();
bouncerFullyVisibleAndNotGoingToSleep();
fingerprintIsNotEnrolled();
keyguardNotGoingAway();
@@ -1285,6 +1286,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
public void testShouldListenForFace_whenBiometricsDisabledForUser_returnsFalse()
throws RemoteException {
// Preconditions for face auth to run
+ faceAuthEnabled();
keyguardNotGoingAway();
bouncerFullyVisibleAndNotGoingToSleep();
fingerprintIsNotEnrolled();
@@ -1308,6 +1310,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
public void testShouldListenForFace_whenUserCurrentlySwitching_returnsFalse()
throws RemoteException {
// Preconditions for face auth to run
+ faceAuthEnabled();
keyguardNotGoingAway();
bouncerFullyVisibleAndNotGoingToSleep();
fingerprintIsNotEnrolled();
@@ -1330,6 +1333,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
public void testShouldListenForFace_whenSecureCameraLaunched_returnsFalse()
throws RemoteException {
// Preconditions for face auth to run
+ faceAuthEnabled();
keyguardNotGoingAway();
bouncerFullyVisibleAndNotGoingToSleep();
fingerprintIsNotEnrolled();
@@ -1375,6 +1379,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
public void testShouldListenForFace_whenBouncerShowingAndDeviceIsAwake_returnsTrue()
throws RemoteException {
// Preconditions for face auth to run
+ faceAuthEnabled();
keyguardNotGoingAway();
currentUserIsPrimary();
currentUserDoesNotHaveTrust();
@@ -1540,8 +1545,19 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(anyBoolean())).isEqualTo(true);
}
+ private void faceAuthEnabled() {
+ // this ensures KeyguardUpdateMonitor updates the cached mIsFaceEnrolled flag using the
+ // face manager mock wire-up in setup()
+ mKeyguardUpdateMonitor.isFaceAuthEnabledForUser(mCurrentUserId);
+ }
+
private void fingerprintIsNotEnrolled() {
when(mFingerprintManager.hasEnrolledTemplates(mCurrentUserId)).thenReturn(false);
+ // This updates the cached fingerprint state.
+ // There is no straightforward API to update the fingerprint state.
+ // It currently works updates after enrollment changes because something else invokes
+ // startListeningForFingerprint(), which internally calls this method.
+ mKeyguardUpdateMonitor.isUnlockWithFingerprintPossible(mCurrentUserId);
}
private void statusBarShadeIsNotLocked() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index e0d1f7a19130..d158892e4ec5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -60,9 +60,6 @@ import android.hardware.biometrics.PromptInfo;
import android.hardware.biometrics.SensorProperties;
import android.hardware.display.DisplayManager;
import android.hardware.face.FaceManager;
-import android.hardware.face.FaceSensorProperties;
-import android.hardware.face.FaceSensorPropertiesInternal;
-import android.hardware.face.IFaceAuthenticatorsRegisteredCallback;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
@@ -157,9 +154,7 @@ public class AuthControllerTest extends SysuiTestCase {
@Mock
private InteractionJankMonitor mInteractionJankMonitor;
@Captor
- ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback> mFpAuthenticatorsRegisteredCaptor;
- @Captor
- ArgumentCaptor<IFaceAuthenticatorsRegisteredCallback> mFaceAuthenticatorsRegisteredCaptor;
+ ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback> mAuthenticatorsRegisteredCaptor;
@Captor
ArgumentCaptor<BiometricStateListener> mBiometricStateCaptor;
@Captor
@@ -198,38 +193,25 @@ public class AuthControllerTest extends SysuiTestCase {
when(mDisplayManager.getStableDisplaySize()).thenReturn(new Point());
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
- when(mFaceManager.isHardwareDetected()).thenReturn(true);
-
- final List<ComponentInfoInternal> fpComponentInfo = List.of(
- new ComponentInfoInternal("faceSensor" /* componentId */,
- "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */,
- "00000001" /* serialNumber */, "" /* softwareVersion */));
- final List<ComponentInfoInternal> faceComponentInfo = List.of(
- new ComponentInfoInternal("matchingAlgorithm" /* componentId */,
- "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */,
- "vendor/version/revision" /* softwareVersion */));
-
- final List<FingerprintSensorPropertiesInternal> fpProps = List.of(
- new FingerprintSensorPropertiesInternal(
- 1 /* sensorId */,
- SensorProperties.STRENGTH_STRONG,
- 1 /* maxEnrollmentsPerUser */,
- fpComponentInfo,
- FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
- true /* resetLockoutRequireHardwareAuthToken */));
- when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(fpProps);
-
- final List<FaceSensorPropertiesInternal> faceProps = List.of(
- new FaceSensorPropertiesInternal(
- 2 /* sensorId */,
- SensorProperties.STRENGTH_STRONG,
- 1 /* maxEnrollmentsPerUser */,
- fpComponentInfo,
- FaceSensorProperties.TYPE_RGB,
- true /* supportsFaceDetection */,
- true /* supportsSelfIllumination */,
- true /* resetLockoutRequireHardwareAuthToken */));
- when(mFaceManager.getSensorPropertiesInternal()).thenReturn(faceProps);
+
+ final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
+ componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */,
+ "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */,
+ "00000001" /* serialNumber */, "" /* softwareVersion */));
+ componentInfo.add(new ComponentInfoInternal("matchingAlgorithm" /* componentId */,
+ "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */,
+ "vendor/version/revision" /* softwareVersion */));
+
+ FingerprintSensorPropertiesInternal prop = new FingerprintSensorPropertiesInternal(
+ 1 /* sensorId */,
+ SensorProperties.STRENGTH_STRONG,
+ 1 /* maxEnrollmentsPerUser */,
+ componentInfo,
+ FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
+ true /* resetLockoutRequireHardwareAuthToken */);
+ List<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
+ props.add(prop);
+ when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(props);
mAuthController = new TestableAuthController(mContextSpy, mExecution, mCommandQueue,
mActivityTaskManager, mWindowManager, mFingerprintManager, mFaceManager,
@@ -237,15 +219,12 @@ public class AuthControllerTest extends SysuiTestCase {
mAuthController.start();
verify(mFingerprintManager).addAuthenticatorsRegisteredCallback(
- mFpAuthenticatorsRegisteredCaptor.capture());
- verify(mFaceManager).addAuthenticatorsRegisteredCallback(
- mFaceAuthenticatorsRegisteredCaptor.capture());
+ mAuthenticatorsRegisteredCaptor.capture());
when(mStatusBarStateController.isDozing()).thenReturn(false);
verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
- mFpAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(fpProps);
- mFaceAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(faceProps);
+ mAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(props);
// Ensures that the operations posted on the handler get executed.
mTestableLooper.processAllMessages();
@@ -258,7 +237,6 @@ public class AuthControllerTest extends SysuiTestCase {
throws RemoteException {
// This test is sensitive to prior FingerprintManager interactions.
reset(mFingerprintManager);
- reset(mFaceManager);
// This test requires an uninitialized AuthController.
AuthController authController = new TestableAuthController(mContextSpy, mExecution,
@@ -268,27 +246,21 @@ public class AuthControllerTest extends SysuiTestCase {
authController.start();
verify(mFingerprintManager).addAuthenticatorsRegisteredCallback(
- mFpAuthenticatorsRegisteredCaptor.capture());
- verify(mFaceManager).addAuthenticatorsRegisteredCallback(
- mFaceAuthenticatorsRegisteredCaptor.capture());
+ mAuthenticatorsRegisteredCaptor.capture());
mTestableLooper.processAllMessages();
verify(mFingerprintManager, never()).registerBiometricStateListener(any());
- verify(mFaceManager, never()).registerBiometricStateListener(any());
- mFpAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(List.of());
- mFaceAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(List.of());
+ mAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(new ArrayList<>());
mTestableLooper.processAllMessages();
verify(mFingerprintManager).registerBiometricStateListener(any());
- verify(mFaceManager).registerBiometricStateListener(any());
}
@Test
public void testDoesNotCrash_afterEnrollmentsChangedForUnknownSensor() throws RemoteException {
// This test is sensitive to prior FingerprintManager interactions.
reset(mFingerprintManager);
- reset(mFaceManager);
// This test requires an uninitialized AuthController.
AuthController authController = new TestableAuthController(mContextSpy, mExecution,
@@ -298,25 +270,18 @@ public class AuthControllerTest extends SysuiTestCase {
authController.start();
verify(mFingerprintManager).addAuthenticatorsRegisteredCallback(
- mFpAuthenticatorsRegisteredCaptor.capture());
- verify(mFaceManager).addAuthenticatorsRegisteredCallback(
- mFaceAuthenticatorsRegisteredCaptor.capture());
+ mAuthenticatorsRegisteredCaptor.capture());
// Emulates a device with no authenticators (empty list).
- mFpAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(List.of());
- mFaceAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(List.of());
+ mAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(new ArrayList<>());
mTestableLooper.processAllMessages();
verify(mFingerprintManager).registerBiometricStateListener(
mBiometricStateCaptor.capture());
- verify(mFaceManager).registerBiometricStateListener(
- mBiometricStateCaptor.capture());
// Enrollments changed for an unknown sensor.
- for (BiometricStateListener listener : mBiometricStateCaptor.getAllValues()) {
- listener.onEnrollmentsChanged(0 /* userId */,
- 0xbeef /* sensorId */, true /* hasEnrollments */);
- }
+ mBiometricStateCaptor.getValue().onEnrollmentsChanged(0 /* userId */,
+ 0xbeef /* sensorId */, true /* hasEnrollments */);
mTestableLooper.processAllMessages();
// Nothing should crash.
@@ -862,3 +827,4 @@ public class AuthControllerTest extends SysuiTestCase {
}
}
}
+
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
index b33f9a7f3933..9ffc5a57cef6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
@@ -16,8 +16,6 @@
package com.android.systemui.doze;
-import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
-
import static com.android.systemui.doze.DozeLog.REASON_SENSOR_TAP;
import static com.android.systemui.doze.DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS;
import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_LOCK_SCREEN;
@@ -414,7 +412,7 @@ public class DozeSensorsTest extends SysuiTestCase {
// WHEN enrollment changes to TRUE
when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(true);
- mAuthControllerCallback.onEnrollmentsChanged(TYPE_FINGERPRINT);
+ mAuthControllerCallback.onEnrollmentsChanged();
// THEN mConfigured = TRUE
assertTrue(triggerSensor.mConfigured);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
index 5ec6bdf3c00b..24d051508fde 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
@@ -16,8 +16,6 @@
package com.android.systemui.keyguard;
-import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
-
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.keyguard.LockIconView.ICON_LOCK;
import static com.android.keyguard.LockIconView.ICON_UNLOCK;
@@ -221,7 +219,7 @@ public class LockIconViewControllerTest extends SysuiTestCase {
Pair<Float, PointF> udfps = setupUdfps();
// WHEN all authenticators are registered
- mAuthControllerCallback.onAllAuthenticatorsRegistered(TYPE_FINGERPRINT);
+ mAuthControllerCallback.onAllAuthenticatorsRegistered();
mDelayableExecutor.runAllReady();
// THEN lock icon view location is updated with the same coordinates as auth controller vals
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolverTest.kt
new file mode 100644
index 000000000000..8275c0c24339
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolverTest.kt
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.statusbar.notification.collection
+
+import android.app.Notification
+import android.app.NotificationManager
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
+import android.os.Bundle
+import android.os.UserHandle
+import android.service.notification.NotificationListenerService.Ranking
+import android.service.notification.StatusBarNotification
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.withArgCaptor
+import junit.framework.Assert.assertEquals
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.anyString
+import org.mockito.Mockito.eq
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyZeroInteractions
+import org.mockito.Mockito.`when` as whenever
+
+private const val SDK_VERSION = 33
+private const val PACKAGE = "pkg"
+private const val USER_ID = -1
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class TargetSdkResolverTest : SysuiTestCase() {
+ private val packageManager: PackageManager = mock()
+ private val applicationInfo = ApplicationInfo().apply { targetSdkVersion = SDK_VERSION }
+
+ private lateinit var targetSdkResolver: TargetSdkResolver
+ private lateinit var notifListener: NotifCollectionListener
+
+ @Before
+ fun setUp() {
+ targetSdkResolver = TargetSdkResolver(mContext)
+ mContext.setMockPackageManager(packageManager)
+
+ val notifCollection: CommonNotifCollection = mock()
+ targetSdkResolver.initialize(notifCollection)
+ notifListener = withArgCaptor {
+ verify(notifCollection).addCollectionListener(capture())
+ }
+ }
+
+ @Test
+ fun resolveFromNotificationExtras() {
+ val extras = Bundle().apply {
+ putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, applicationInfo)
+ }
+ val notification = Notification().apply { this.extras = extras }
+ val sbn = createSbn(notification)
+ val entry = createNotificationEntry(sbn)
+
+ notifListener.onEntryBind(entry, sbn)
+
+ assertEquals(SDK_VERSION, entry.targetSdk)
+ verifyZeroInteractions(packageManager)
+ }
+
+ @Test
+ fun resolveFromPackageManager() {
+ val sbn = createSbn(Notification())
+ val entry = createNotificationEntry(sbn)
+ whenever(packageManager.getApplicationInfo(anyString(), anyInt()))
+ .thenReturn(applicationInfo)
+
+ notifListener.onEntryBind(entry, sbn)
+
+ assertEquals(SDK_VERSION, entry.targetSdk)
+ verify(packageManager).getApplicationInfo(eq(PACKAGE), anyInt())
+ }
+
+ @Test
+ fun resolveFromPackageManager_andPackageManagerCrashes() {
+ val sbn = createSbn(Notification())
+ val entry = createNotificationEntry(sbn)
+ whenever(packageManager.getApplicationInfo(anyString(), anyInt()))
+ .thenThrow(PackageManager.NameNotFoundException())
+
+ notifListener.onEntryBind(entry, sbn)
+
+ assertEquals(0, entry.targetSdk)
+ verify(packageManager).getApplicationInfo(eq(PACKAGE), anyInt())
+ }
+
+ private fun createSbn(notification: Notification) = StatusBarNotification(
+ PACKAGE, "opPkg", 0, "tag", 0, 0,
+ notification, UserHandle(USER_ID), "", 0
+ )
+
+ private fun createNotificationEntry(sbn: StatusBarNotification) =
+ NotificationEntry(sbn, createRanking(sbn.key), 0)
+
+ private fun createRanking(key: String) = Ranking().apply {
+ populate(
+ key,
+ 0,
+ false,
+ 0,
+ 0,
+ NotificationManager.IMPORTANCE_DEFAULT,
+ null, null,
+ null, null, null, true, 0, false, -1, false, null, null, false, false,
+ false, null, 0, false)
+ }
+}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 5a20db309f19..785040ea8202 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -63,6 +63,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.database.ContentObserver;
import android.hardware.SensorPrivacyManager;
import android.hardware.SensorPrivacyManagerInternal;
@@ -412,10 +413,10 @@ public class AudioService extends IAudioService.Stub
protected static int[] MAX_STREAM_VOLUME = new int[] {
5, // STREAM_VOICE_CALL
7, // STREAM_SYSTEM
- 7, // STREAM_RING
+ 7, // STREAM_RING // configured by config_audio_ring_vol_steps
15, // STREAM_MUSIC
7, // STREAM_ALARM
- 7, // STREAM_NOTIFICATION
+ 7, // STREAM_NOTIFICATION // configured by config_audio_notif_vol_steps
15, // STREAM_BLUETOOTH_SCO
7, // STREAM_SYSTEM_ENFORCED
15, // STREAM_DTMF
@@ -1116,6 +1117,48 @@ public class AudioService extends IAudioService.Stub
MAX_STREAM_VOLUME[AudioSystem.STREAM_SYSTEM];
}
+ // Read following properties to configure max volume (number of steps) and default volume
+ // for STREAM_NOTIFICATION and STREAM_RING:
+ // config_audio_notif_vol_default
+ // config_audio_notif_vol_steps
+ // config_audio_ring_vol_default
+ // config_audio_ring_vol_steps
+ int[] streams = { AudioSystem.STREAM_NOTIFICATION, AudioSystem.STREAM_RING };
+ int[] stepsResId = { com.android.internal.R.integer.config_audio_notif_vol_steps,
+ com.android.internal.R.integer.config_audio_ring_vol_steps };
+ int[] defaultResId = { com.android.internal.R.integer.config_audio_notif_vol_default,
+ com.android.internal.R.integer.config_audio_ring_vol_default };
+ for (int s = 0; s < streams.length; s++) {
+ try {
+ final int maxVol = mContext.getResources().getInteger(stepsResId[s]);
+ if (maxVol <= 0) {
+ throw new IllegalArgumentException("Invalid negative max volume for stream "
+ + streams[s]);
+ }
+ Log.i(TAG, "Stream " + streams[s] + ": using max vol of " + maxVol);
+ MAX_STREAM_VOLUME[streams[s]] = maxVol;
+ } catch (Resources.NotFoundException e) {
+ Log.e(TAG, "Error querying max vol for stream type " + streams[s], e);
+ }
+ try {
+ final int defaultVol = mContext.getResources().getInteger(defaultResId[s]);
+ if (defaultVol > MAX_STREAM_VOLUME[streams[s]]) {
+ throw new IllegalArgumentException("Invalid default volume (" + defaultVol
+ + ") for stream " + streams[s] + ", greater than max volume of "
+ + MAX_STREAM_VOLUME[streams[s]]);
+ }
+ if (defaultVol < MIN_STREAM_VOLUME[streams[s]]) {
+ throw new IllegalArgumentException("Invalid default volume (" + defaultVol
+ + ") for stream " + streams[s] + ", lower than min volume of "
+ + MIN_STREAM_VOLUME[streams[s]]);
+ }
+ Log.i(TAG, "Stream " + streams[s] + ": using default vol of " + defaultVol);
+ AudioSystem.DEFAULT_STREAM_VOLUME[streams[s]] = defaultVol;
+ } catch (Resources.NotFoundException e) {
+ Log.e(TAG, "Error querying default vol for stream type " + streams[s], e);
+ }
+ }
+
if (looper == null) {
createAudioSystemThread();
} else {
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/BiometricServiceProvider.java
deleted file mode 100644
index 0f1fe68ad1d7..000000000000
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricServiceProvider.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.biometrics.sensors;
-
-import android.annotation.NonNull;
-import android.hardware.biometrics.SensorPropertiesInternal;
-import android.util.proto.ProtoOutputStream;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.List;
-
-/**
- * Common attributes for all biometric service providers.
- *
- * @param <T> Internal settings type.
- */
-public interface BiometricServiceProvider<T extends SensorPropertiesInternal> {
-
- /** Checks if the specified sensor is owned by this provider. */
- boolean containsSensor(int sensorId);
-
- /** All sensor properties. */
- @NonNull
- List<T> getSensorProperties();
-
- /** Properties for the given sensor id. */
- @NonNull
- T getSensorProperties(int sensorId);
-
- boolean isHardwareDetected(int sensorId);
-
- /** If the user has any enrollments for the given sensor. */
- boolean hasEnrollments(int sensorId, int userId);
-
- long getAuthenticatorId(int sensorId, int userId);
-
- @LockoutTracker.LockoutMode
- int getLockoutModeForUser(int sensorId, int userId);
-
- void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto,
- boolean clearSchedulerBuffer);
-
- void dumpProtoMetrics(int sensorId, @NonNull FileDescriptor fd);
-
- void dumpInternal(int sensorId, @NonNull PrintWriter pw);
-}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricServiceRegistry.java b/services/core/java/com/android/server/biometrics/sensors/BiometricServiceRegistry.java
deleted file mode 100644
index 7574523f0662..000000000000
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricServiceRegistry.java
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.biometrics.sensors;
-
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.hardware.biometrics.IBiometricAuthenticator;
-import android.hardware.biometrics.IBiometricService;
-import android.hardware.biometrics.SensorPropertiesInternal;
-import android.os.Handler;
-import android.os.IInterface;
-import android.os.Process;
-import android.os.RemoteCallbackList;
-import android.os.RemoteException;
-import android.util.Pair;
-import android.util.Slog;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.ServiceThread;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.function.Supplier;
-
-/**
- * Container for all BiometricServiceProvider implementations.
- *
- * @param <T> The service provider type.
- * @param <P> The internal properties type.
- * @param <C> The registration callback for {@link #invokeRegisteredCallback(IInterface, List)}.
- */
-public abstract class BiometricServiceRegistry<T extends BiometricServiceProvider<P>,
- P extends SensorPropertiesInternal,
- C extends IInterface> {
-
- private static final String TAG = "BiometricServiceRegistry";
-
- // Volatile so they can be read without a lock once all services are registered.
- // But, ideally remove this and provide immutable copies via the callback instead.
- @Nullable
- private volatile List<T> mServiceProviders;
- @Nullable
- private volatile List<P> mAllProps;
-
- @NonNull
- private final Supplier<IBiometricService> mBiometricServiceSupplier;
- @NonNull
- private final RemoteCallbackList<C> mRegisteredCallbacks = new RemoteCallbackList<>();
-
- public BiometricServiceRegistry(@NonNull Supplier<IBiometricService> biometricSupplier) {
- mBiometricServiceSupplier = biometricSupplier;
- }
-
- /**
- * Register an implementation by creating a new authenticator and initializing it via
- * {@link IBiometricService#registerAuthenticator(int, int, int, IBiometricAuthenticator)}
- * using the given properties.
- *
- * @param service service to register with
- * @param props internal properties to initialize the authenticator
- */
- protected abstract void registerService(@NonNull IBiometricService service, @NonNull P props);
-
- /**
- * Invoke the callback to notify clients that all authenticators have been registered.
- *
- * @param callback callback to invoke
- * @param allProps properties of all authenticators
- */
- protected abstract void invokeRegisteredCallback(@NonNull C callback,
- @NonNull List<P> allProps) throws RemoteException;
-
- /**
- * Register all authenticators in a background thread.
- *
- * @param serviceProvider Supplier function that will be invoked on the background thread.
- */
- public void registerAll(Supplier<List<T>> serviceProvider) {
- // Some HAL might not be started before the system service and will cause the code below
- // to wait, and some of the operations below might take a significant amount of time to
- // complete (calls to the HALs). To avoid blocking the rest of system server we put
- // this on a background thread.
- final ServiceThread thread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND,
- true /* allowIo */);
- thread.start();
- final Handler handler = new Handler(thread.getLooper());
- handler.post(() -> registerAllInBackground(serviceProvider));
- thread.quitSafely();
- }
-
- /** Register authenticators now, only called by {@link #registerAll(Supplier).} */
- @VisibleForTesting
- public void registerAllInBackground(Supplier<List<T>> serviceProvider) {
- List<T> providers = serviceProvider.get();
- if (providers == null) {
- providers = new ArrayList<>();
- }
-
- final IBiometricService biometricService = mBiometricServiceSupplier.get();
- if (biometricService == null) {
- throw new IllegalStateException("biometric service cannot be null");
- }
-
- // Register each sensor individually with BiometricService
- final List<P> allProps = new ArrayList<>();
- for (T provider : providers) {
- final List<P> props = provider.getSensorProperties();
- for (P prop : props) {
- registerService(biometricService, prop);
- }
- allProps.addAll(props);
- }
-
- finishRegistration(providers, allProps);
- }
-
- private synchronized void finishRegistration(
- @NonNull List<T> providers, @NonNull List<P> allProps) {
- mServiceProviders = Collections.unmodifiableList(providers);
- mAllProps = Collections.unmodifiableList(allProps);
- broadcastAllAuthenticatorsRegistered();
- }
-
- /**
- * Add a callback that will be invoked once the work from {@link #registerAll(Supplier)}
- * has finished registering all providers (executes immediately if already done).
- *
- * @param callback registration callback
- */
- public synchronized void addAllRegisteredCallback(@Nullable C callback) {
- if (callback == null) {
- Slog.e(TAG, "addAllRegisteredCallback, callback is null");
- return;
- }
-
- final boolean registered = mRegisteredCallbacks.register(callback);
- final boolean allRegistered = mServiceProviders != null;
- if (registered && allRegistered) {
- broadcastAllAuthenticatorsRegistered();
- } else if (!registered) {
- Slog.e(TAG, "addAllRegisteredCallback failed to register callback");
- }
- }
-
- private synchronized void broadcastAllAuthenticatorsRegistered() {
- final int n = mRegisteredCallbacks.beginBroadcast();
- for (int i = 0; i < n; ++i) {
- final C cb = mRegisteredCallbacks.getBroadcastItem(i);
- try {
- invokeRegisteredCallback(cb, mAllProps);
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception in broadcastAllAuthenticatorsRegistered", e);
- } finally {
- mRegisteredCallbacks.unregister(cb);
- }
- }
- mRegisteredCallbacks.finishBroadcast();
- }
-
- /**
- * Get a list of registered providers.
- *
- * Undefined until {@link #registerAll(Supplier)} has fired the completion callback.
- */
- @NonNull
- public List<T> getProviders() {
- return mServiceProviders != null ? mServiceProviders : Collections.emptyList();
- }
-
- /**
- * Gets the provider for given sensor id or null if not registered.
- *
- * Undefined until {@link #registerAll(Supplier)} has fired the completion callback.
- */
- @Nullable
- public T getProviderForSensor(int sensorId) {
- if (mServiceProviders != null) {
- for (T provider : mServiceProviders) {
- if (provider.containsSensor(sensorId)) {
- return provider;
- }
- }
- }
- return null;
- }
-
- /**
- * For devices with only a single provider, returns that provider.
- * If no providers, or multiple providers exist, returns null.
- *
- * Undefined until {@link #registerAll(Supplier)} has fired the completion callback.
- */
- @Nullable
- public Pair<Integer, T> getSingleProvider() {
- if (mAllProps == null || mAllProps.size() != 1) {
- Slog.e(TAG, "Multiple sensors found: " + mAllProps.size());
- return null;
- }
-
- final int sensorId = mAllProps.get(0).sensorId;
- final T provider = getProviderForSensor(sensorId);
- if (provider != null) {
- return new Pair<>(sensorId, provider);
- }
-
- Slog.e(TAG, "Single sensor, but provider not found");
- return null;
- }
-
- /**
- * Get the properties for all providers.
- *
- * Undefined until {@link #registerAll(Supplier)} has fired the completion callback.
- */
- @NonNull
- public List<P> getAllProperties() {
- return mAllProps != null ? mAllProps : Collections.emptyList();
- }
-}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricStateCallback.java b/services/core/java/com/android/server/biometrics/sensors/BiometricStateCallback.java
index f8543162f95e..0d789f7a1840 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricStateCallback.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricStateCallback.java
@@ -23,64 +23,32 @@ import static android.hardware.biometrics.BiometricStateListener.STATE_IDLE;
import static android.hardware.biometrics.BiometricStateListener.STATE_KEYGUARD_AUTH;
import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.pm.UserInfo;
import android.hardware.biometrics.BiometricStateListener;
import android.hardware.biometrics.IBiometricStateListener;
-import android.hardware.biometrics.SensorPropertiesInternal;
import android.os.RemoteException;
-import android.os.UserManager;
import android.util.Slog;
import com.android.server.biometrics.Utils;
-import java.util.Collections;
-import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* A callback for receiving notifications about biometric sensor state changes.
- *
- * @param <T> service provider type
- * @param <P> internal property type
*/
-public class BiometricStateCallback<T extends BiometricServiceProvider<P>,
- P extends SensorPropertiesInternal> implements ClientMonitorCallback {
+public class BiometricStateCallback implements ClientMonitorCallback {
private static final String TAG = "BiometricStateCallback";
@NonNull
- private final CopyOnWriteArrayList<IBiometricStateListener> mBiometricStateListeners =
- new CopyOnWriteArrayList<>();
- @NonNull
- private final UserManager mUserManager;
- @BiometricStateListener.State
- private int mBiometricState;
- @NonNull
- private List<T> mProviders = List.of();
+ private final CopyOnWriteArrayList<IBiometricStateListener>
+ mBiometricStateListeners = new CopyOnWriteArrayList<>();
- /**
- * Create a new callback that must be {@link #start(List)}ed.
- *
- * @param userManager user manager
- */
- public BiometricStateCallback(@NonNull UserManager userManager) {
- mBiometricState = STATE_IDLE;
- mUserManager = userManager;
- }
+ private @BiometricStateListener.State int mBiometricState;
- /**
- * This should be called when the service has been initialized and all providers are ready.
- *
- * @param allProviders all registered biometric service providers
- */
- public synchronized void start(@NonNull List<T> allProviders) {
- mProviders = Collections.unmodifiableList(allProviders);
- broadcastCurrentEnrollmentState(null /* listener */);
+ public BiometricStateCallback() {
+ mBiometricState = STATE_IDLE;
}
- /** Get the current state. */
- @BiometricStateListener.State
public int getBiometricState() {
return mBiometricState;
}
@@ -152,43 +120,23 @@ public class BiometricStateCallback<T extends BiometricServiceProvider<P>,
}
/**
- * Enables clients to register a BiometricStateListener. For example, this is used to forward
- * fingerprint sensor state changes to SideFpsEventHandler.
- *
- * @param listener listener to register
+ * This should be invoked when:
+ * 1) Enrolled --> None-enrolled
+ * 2) None-enrolled --> enrolled
+ * 3) HAL becomes ready
+ * 4) Listener is registered
*/
- public synchronized void registerBiometricStateListener(
- @NonNull IBiometricStateListener listener) {
- mBiometricStateListeners.add(listener);
- broadcastCurrentEnrollmentState(listener);
- }
-
- private synchronized void broadcastCurrentEnrollmentState(
- @Nullable IBiometricStateListener listener) {
- for (T provider : mProviders) {
- for (SensorPropertiesInternal prop : provider.getSensorProperties()) {
- for (UserInfo userInfo : mUserManager.getAliveUsers()) {
- final boolean enrolled = provider.hasEnrollments(prop.sensorId, userInfo.id);
- if (listener != null) {
- notifyEnrollmentStateChanged(
- listener, userInfo.id, prop.sensorId, enrolled);
- } else {
- notifyAllEnrollmentStateChanged(
- userInfo.id, prop.sensorId, enrolled);
- }
- }
- }
- }
- }
-
- private void notifyAllEnrollmentStateChanged(int userId, int sensorId,
+ public void notifyAllEnrollmentStateChanged(int userId, int sensorId,
boolean hasEnrollments) {
for (IBiometricStateListener listener : mBiometricStateListeners) {
notifyEnrollmentStateChanged(listener, userId, sensorId, hasEnrollments);
}
}
- private void notifyEnrollmentStateChanged(@NonNull IBiometricStateListener listener,
+ /**
+ * Notifies the listener of enrollment state changes.
+ */
+ public void notifyEnrollmentStateChanged(@NonNull IBiometricStateListener listener,
int userId, int sensorId, boolean hasEnrollments) {
try {
listener.onEnrollmentsChanged(userId, sensorId, hasEnrollments);
@@ -196,4 +144,14 @@ public class BiometricStateCallback<T extends BiometricServiceProvider<P>,
Slog.e(TAG, "Remote exception", e);
}
}
+
+ /**
+ * Enables clients to register a BiometricStateListener. For example, this is used to forward
+ * fingerprint sensor state changes to SideFpsEventHandler.
+ *
+ * @param listener
+ */
+ public void registerBiometricStateListener(@NonNull IBiometricStateListener listener) {
+ mBiometricStateListeners.add(listener);
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index 271bce9890c6..79e65cc6d2e5 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -17,18 +17,20 @@
package com.android.server.biometrics.sensors.face;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
+import static android.Manifest.permission.MANAGE_BIOMETRIC;
import static android.Manifest.permission.MANAGE_FACE;
import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
+import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.Context;
+import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
-import android.hardware.biometrics.IBiometricStateListener;
import android.hardware.biometrics.IInvalidationCallback;
import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.ITestSessionCallback;
@@ -37,18 +39,18 @@ import android.hardware.biometrics.face.SensorProps;
import android.hardware.face.Face;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.face.FaceServiceReceiver;
-import android.hardware.face.IFaceAuthenticatorsRegisteredCallback;
import android.hardware.face.IFaceService;
import android.hardware.face.IFaceServiceReceiver;
import android.os.Binder;
+import android.os.Handler;
import android.os.IBinder;
import android.os.NativeHandle;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.ShellCallback;
import android.os.UserHandle;
-import android.os.UserManager;
import android.util.Pair;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -56,10 +58,10 @@ import android.view.Surface;
import com.android.internal.util.DumpUtils;
import com.android.internal.widget.LockPatternUtils;
+import com.android.server.ServiceThread;
import com.android.server.SystemService;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.log.BiometricContext;
-import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.LockoutTracker;
@@ -86,10 +88,51 @@ public class FaceService extends SystemService {
private final LockoutResetDispatcher mLockoutResetDispatcher;
private final LockPatternUtils mLockPatternUtils;
@NonNull
- private final FaceServiceRegistry mRegistry;
+ private final List<ServiceProvider> mServiceProviders;
+
+ @Nullable
+ private ServiceProvider getProviderForSensor(int sensorId) {
+ for (ServiceProvider provider : mServiceProviders) {
+ if (provider.containsSensor(sensorId)) {
+ return provider;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * For devices with only a single provider, returns that provider. If no providers, or multiple
+ * providers exist, returns null.
+ */
+ @Nullable
+ private Pair<Integer, ServiceProvider> getSingleProvider() {
+ final List<FaceSensorPropertiesInternal> properties = getSensorProperties();
+ if (properties.size() != 1) {
+ Slog.e(TAG, "Multiple sensors found: " + properties.size());
+ return null;
+ }
+
+ // Theoretically we can just return the first provider, but maybe this is easier to
+ // understand.
+ final int sensorId = properties.get(0).sensorId;
+ for (ServiceProvider provider : mServiceProviders) {
+ if (provider.containsSensor(sensorId)) {
+ return new Pair<>(sensorId, provider);
+ }
+ }
+
+ Slog.e(TAG, "Single sensor, but provider not found");
+ return null;
+ }
+
@NonNull
- private final BiometricStateCallback<ServiceProvider, FaceSensorPropertiesInternal>
- mBiometricStateCallback;
+ private List<FaceSensorPropertiesInternal> getSensorProperties() {
+ final List<FaceSensorPropertiesInternal> properties = new ArrayList<>();
+ for (ServiceProvider provider : mServiceProviders) {
+ properties.addAll(provider.getSensorProperties());
+ }
+ return properties;
+ }
/**
* Receives the incoming binder calls from FaceManager.
@@ -99,7 +142,8 @@ public class FaceService extends SystemService {
@Override
public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
@NonNull String opPackageName) {
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for createTestSession, sensorId: " + sensorId);
@@ -112,8 +156,9 @@ public class FaceService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public byte[] dumpSensorServiceStateProto(int sensorId, boolean clearSchedulerBuffer) {
+
final ProtoOutputStream proto = new ProtoOutputStream();
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider != null) {
provider.dumpProtoState(sensorId, proto, clearSchedulerBuffer);
}
@@ -125,14 +170,16 @@ public class FaceService extends SystemService {
@Override // Binder call
public List<FaceSensorPropertiesInternal> getSensorPropertiesInternal(
String opPackageName) {
- return mRegistry.getAllProperties();
+
+ return FaceService.this.getSensorProperties();
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public FaceSensorPropertiesInternal getSensorProperties(int sensorId,
@NonNull String opPackageName) {
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "No matching sensor for getSensorProperties, sensorId: " + sensorId
+ ", caller: " + opPackageName);
@@ -146,7 +193,8 @@ public class FaceService extends SystemService {
@Override // Binder call
public void generateChallenge(IBinder token, int sensorId, int userId,
IFaceServiceReceiver receiver, String opPackageName) {
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "No matching sensor for generateChallenge, sensorId: " + sensorId);
return;
@@ -159,7 +207,8 @@ public class FaceService extends SystemService {
@Override // Binder call
public void revokeChallenge(IBinder token, int sensorId, int userId, String opPackageName,
long challenge) {
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "No matching sensor for revokeChallenge, sensorId: " + sensorId);
return;
@@ -173,7 +222,8 @@ public class FaceService extends SystemService {
public long enroll(int userId, final IBinder token, final byte[] hardwareAuthToken,
final IFaceServiceReceiver receiver, final String opPackageName,
final int[] disabledFeatures, Surface previewSurface, boolean debugConsent) {
- final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
+
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for enroll");
return -1;
@@ -195,7 +245,8 @@ public class FaceService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_BIOMETRIC)
@Override // Binder call
public void cancelEnrollment(final IBinder token, long requestId) {
- final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
+
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for cancelEnrollment");
return;
@@ -209,6 +260,7 @@ public class FaceService extends SystemService {
public long authenticate(final IBinder token, final long operationId, int userId,
final IFaceServiceReceiver receiver, final String opPackageName,
boolean isKeyguardBypassEnabled) {
+
// TODO(b/152413782): If the sensor supports face detect and the device is encrypted or
// lockdown, something wrong happened. See similar path in FingerprintService.
@@ -221,7 +273,7 @@ public class FaceService extends SystemService {
// permission.
final boolean isKeyguard = Utils.isKeyguard(getContext(), opPackageName);
- final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for authenticate");
return -1;
@@ -249,7 +301,7 @@ public class FaceService extends SystemService {
return -1;
}
- final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for detectFace");
return -1;
@@ -266,7 +318,8 @@ public class FaceService extends SystemService {
IBinder token, long operationId, int userId,
IBiometricSensorReceiver sensorReceiver, String opPackageName, long requestId,
int cookie, boolean allowBackgroundAuthentication) {
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for prepareForAuthentication");
return;
@@ -283,7 +336,8 @@ public class FaceService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public void startPreparedClient(int sensorId, int cookie) {
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for startPreparedClient");
return;
@@ -296,7 +350,8 @@ public class FaceService extends SystemService {
@Override // Binder call
public void cancelAuthentication(final IBinder token, final String opPackageName,
final long requestId) {
- final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
+
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for cancelAuthentication");
return;
@@ -315,7 +370,7 @@ public class FaceService extends SystemService {
return;
}
- final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for cancelFaceDetect");
return;
@@ -328,7 +383,8 @@ public class FaceService extends SystemService {
@Override // Binder call
public void cancelAuthenticationFromService(int sensorId, final IBinder token,
final String opPackageName, final long requestId) {
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for cancelAuthenticationFromService");
return;
@@ -341,7 +397,8 @@ public class FaceService extends SystemService {
@Override // Binder call
public void remove(final IBinder token, final int faceId, final int userId,
final IFaceServiceReceiver receiver, final String opPackageName) {
- final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
+
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for remove");
return;
@@ -355,6 +412,7 @@ public class FaceService extends SystemService {
@Override // Binder call
public void removeAll(final IBinder token, final int userId,
final IFaceServiceReceiver receiver, final String opPackageName) {
+
final FaceServiceReceiver internalReceiver = new FaceServiceReceiver() {
int sensorsFinishedRemoving = 0;
final int numSensors = getSensorPropertiesInternal(
@@ -374,7 +432,7 @@ public class FaceService extends SystemService {
// This effectively iterates through all sensors, but has to do so by finding all
// sensors under each provider.
- for (ServiceProvider provider : mRegistry.getProviders()) {
+ for (ServiceProvider provider : mServiceProviders) {
List<FaceSensorPropertiesInternal> props = provider.getSensorProperties();
for (FaceSensorPropertiesInternal prop : props) {
provider.scheduleRemoveAll(prop.sensorId, token, userId, internalReceiver,
@@ -409,27 +467,27 @@ public class FaceService extends SystemService {
try {
if (args.length > 1 && "--proto".equals(args[0]) && "--state".equals(args[1])) {
final ProtoOutputStream proto = new ProtoOutputStream(fd);
- for (ServiceProvider provider : mRegistry.getProviders()) {
+ for (ServiceProvider provider : mServiceProviders) {
for (FaceSensorPropertiesInternal props : provider.getSensorProperties()) {
provider.dumpProtoState(props.sensorId, proto, false);
}
}
proto.flush();
} else if (args.length > 0 && "--proto".equals(args[0])) {
- for (ServiceProvider provider : mRegistry.getProviders()) {
+ for (ServiceProvider provider : mServiceProviders) {
for (FaceSensorPropertiesInternal props : provider.getSensorProperties()) {
provider.dumpProtoMetrics(props.sensorId, fd);
}
}
} else if (args.length > 1 && "--hal".equals(args[0])) {
- for (ServiceProvider provider : mRegistry.getProviders()) {
+ for (ServiceProvider provider : mServiceProviders) {
for (FaceSensorPropertiesInternal props : provider.getSensorProperties()) {
provider.dumpHal(props.sensorId, fd,
Arrays.copyOfRange(args, 1, args.length, args.getClass()));
}
}
} else {
- for (ServiceProvider provider : mRegistry.getProviders()) {
+ for (ServiceProvider provider : mServiceProviders) {
for (FaceSensorPropertiesInternal props : provider.getSensorProperties()) {
pw.println("Dumping for sensorId: " + props.sensorId
+ ", provider: " + provider.getClass().getSimpleName());
@@ -446,9 +504,10 @@ public class FaceService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public boolean isHardwareDetected(int sensorId, String opPackageName) {
+
final long token = Binder.clearCallingIdentity();
try {
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for isHardwareDetected, caller: " + opPackageName);
return false;
@@ -462,11 +521,12 @@ public class FaceService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public List<Face> getEnrolledFaces(int sensorId, int userId, String opPackageName) {
+
if (userId != UserHandle.getCallingUserId()) {
Utils.checkPermission(getContext(), INTERACT_ACROSS_USERS);
}
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for getEnrolledFaces, caller: " + opPackageName);
return Collections.emptyList();
@@ -478,11 +538,12 @@ public class FaceService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public boolean hasEnrolledFaces(int sensorId, int userId, String opPackageName) {
+
if (userId != UserHandle.getCallingUserId()) {
Utils.checkPermission(getContext(), INTERACT_ACROSS_USERS);
}
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for hasEnrolledFaces, caller: " + opPackageName);
return false;
@@ -494,7 +555,8 @@ public class FaceService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public @LockoutTracker.LockoutMode int getLockoutModeForUser(int sensorId, int userId) {
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for getLockoutModeForUser");
return LockoutTracker.LOCKOUT_NONE;
@@ -507,7 +569,8 @@ public class FaceService extends SystemService {
@Override
public void invalidateAuthenticatorId(int sensorId, int userId,
IInvalidationCallback callback) {
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for invalidateAuthenticatorId");
return;
@@ -519,7 +582,7 @@ public class FaceService extends SystemService {
@Override // Binder call
public long getAuthenticatorId(int sensorId, int userId) {
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for getAuthenticatorId");
return 0;
@@ -532,7 +595,8 @@ public class FaceService extends SystemService {
@Override // Binder call
public void resetLockout(IBinder token, int sensorId, int userId, byte[] hardwareAuthToken,
String opPackageName) {
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for resetLockout, caller: " + opPackageName);
return;
@@ -546,7 +610,8 @@ public class FaceService extends SystemService {
public void setFeature(final IBinder token, int userId, int feature, boolean enabled,
final byte[] hardwareAuthToken, IFaceServiceReceiver receiver,
final String opPackageName) {
- final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
+
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for setFeature");
return;
@@ -560,7 +625,8 @@ public class FaceService extends SystemService {
@Override
public void getFeature(final IBinder token, int userId, int feature,
IFaceServiceReceiver receiver, final String opPackageName) {
- final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
+
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for getFeature");
return;
@@ -570,14 +636,18 @@ public class FaceService extends SystemService {
new ClientMonitorCallbackConverter(receiver), opPackageName);
}
- private List<ServiceProvider> getAidlProviders() {
- final List<ServiceProvider> providers = new ArrayList<>();
+ private void addHidlProviders(@NonNull List<FaceSensorPropertiesInternal> hidlSensors) {
+ for (FaceSensorPropertiesInternal hidlSensor : hidlSensors) {
+ mServiceProviders.add(
+ Face10.newInstance(getContext(), hidlSensor, mLockoutResetDispatcher));
+ }
+ }
+ private void addAidlProviders() {
final String[] instances = ServiceManager.getDeclaredInstances(IFace.DESCRIPTOR);
if (instances == null || instances.length == 0) {
- return providers;
+ return;
}
-
for (String instance : instances) {
final String fqName = IFace.DESCRIPTOR + "/" + instance;
final IFace face = IFace.Stub.asInterface(
@@ -590,41 +660,53 @@ public class FaceService extends SystemService {
final SensorProps[] props = face.getSensorProps();
final FaceProvider provider = new FaceProvider(getContext(), props, instance,
mLockoutResetDispatcher, BiometricContext.getInstance(getContext()));
- providers.add(provider);
+ mServiceProviders.add(provider);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception in getSensorProps: " + fqName);
}
}
-
- return providers;
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public void registerAuthenticators(
@NonNull List<FaceSensorPropertiesInternal> hidlSensors) {
- mRegistry.registerAll(() -> {
- final List<ServiceProvider> providers = new ArrayList<>();
- for (FaceSensorPropertiesInternal hidlSensor : hidlSensors) {
- providers.add(
- Face10.newInstance(getContext(), hidlSensor, mLockoutResetDispatcher));
+
+ // Some HAL might not be started before the system service and will cause the code below
+ // to wait, and some of the operations below might take a significant amount of time to
+ // complete (calls to the HALs). To avoid blocking the rest of system server we put
+ // this on a background thread.
+ final ServiceThread thread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND,
+ true /* allowIo */);
+ thread.start();
+ final Handler handler = new Handler(thread.getLooper());
+
+ handler.post(() -> {
+ addHidlProviders(hidlSensors);
+ addAidlProviders();
+
+ final IBiometricService biometricService = IBiometricService.Stub.asInterface(
+ ServiceManager.getService(Context.BIOMETRIC_SERVICE));
+
+ // Register each sensor individually with BiometricService
+ for (ServiceProvider provider : mServiceProviders) {
+ final List<FaceSensorPropertiesInternal> props = provider.getSensorProperties();
+ for (FaceSensorPropertiesInternal prop : props) {
+ final int sensorId = prop.sensorId;
+ final @BiometricManager.Authenticators.Types int strength =
+ Utils.propertyStrengthToAuthenticatorStrength(prop.sensorStrength);
+ final FaceAuthenticator authenticator = new FaceAuthenticator(
+ mServiceWrapper, sensorId);
+ try {
+ biometricService.registerAuthenticator(sensorId, TYPE_FACE, strength,
+ authenticator);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception when registering sensorId: " + sensorId);
+ }
+ }
}
- providers.addAll(getAidlProviders());
- return providers;
});
}
-
- @Override
- public void addAuthenticatorsRegisteredCallback(
- IFaceAuthenticatorsRegisteredCallback callback) {
- Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- mRegistry.addAllRegisteredCallback(callback);
- }
-
- @Override
- public void registerBiometricStateListener(@NonNull IBiometricStateListener listener) {
- mBiometricStateCallback.registerBiometricStateListener(listener);
- }
}
public FaceService(Context context) {
@@ -632,16 +714,7 @@ public class FaceService extends SystemService {
mServiceWrapper = new FaceServiceWrapper();
mLockoutResetDispatcher = new LockoutResetDispatcher(context);
mLockPatternUtils = new LockPatternUtils(context);
- mBiometricStateCallback = new BiometricStateCallback<>(UserManager.get(context));
- mRegistry = new FaceServiceRegistry(mServiceWrapper,
- () -> IBiometricService.Stub.asInterface(
- ServiceManager.getService(Context.BIOMETRIC_SERVICE)));
- mRegistry.addAllRegisteredCallback(new IFaceAuthenticatorsRegisteredCallback.Stub() {
- @Override
- public void onAllAuthenticatorsRegistered(List<FaceSensorPropertiesInternal> sensors) {
- mBiometricStateCallback.start(mRegistry.getProviders());
- }
- });
+ mServiceProviders = new ArrayList<>();
}
@Override
@@ -679,7 +752,7 @@ public class FaceService extends SystemService {
if (Utils.isVirtualEnabled(getContext())) {
Slog.i(TAG, "Sync virtual enrollments");
final int userId = ActivityManager.getCurrentUser();
- for (ServiceProvider provider : mRegistry.getProviders()) {
+ for (ServiceProvider provider : mServiceProviders) {
for (FaceSensorPropertiesInternal props : provider.getSensorProperties()) {
provider.scheduleInternalCleanup(props.sensorId, userId, null /* callback */,
true /* favorHalEnrollments */);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceServiceRegistry.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceServiceRegistry.java
deleted file mode 100644
index 0f0a81d24473..000000000000
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceServiceRegistry.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.biometrics.sensors.face;
-
-import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.hardware.biometrics.BiometricManager;
-import android.hardware.biometrics.IBiometricService;
-import android.hardware.face.FaceSensorPropertiesInternal;
-import android.hardware.face.IFaceAuthenticatorsRegisteredCallback;
-import android.hardware.face.IFaceService;
-import android.os.RemoteException;
-import android.util.Slog;
-
-import com.android.server.biometrics.Utils;
-import com.android.server.biometrics.sensors.BiometricServiceRegistry;
-
-import java.util.List;
-import java.util.function.Supplier;
-
-/** Registry for {@link IFaceService} providers. */
-public class FaceServiceRegistry extends BiometricServiceRegistry<ServiceProvider,
- FaceSensorPropertiesInternal, IFaceAuthenticatorsRegisteredCallback> {
-
- private static final String TAG = "FaceServiceRegistry";
-
- @NonNull
- private final IFaceService mService;
-
- /** Creates a new registry tied to the given service. */
- public FaceServiceRegistry(@NonNull IFaceService service,
- @Nullable Supplier<IBiometricService> biometricSupplier) {
- super(biometricSupplier);
- mService = service;
- }
-
- @Override
- protected void registerService(@NonNull IBiometricService service,
- @NonNull FaceSensorPropertiesInternal props) {
- @BiometricManager.Authenticators.Types final int strength =
- Utils.propertyStrengthToAuthenticatorStrength(props.sensorStrength);
- try {
- service.registerAuthenticator(props.sensorId, TYPE_FACE, strength,
- new FaceAuthenticator(mService, props.sensorId));
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception when registering sensorId: " + props.sensorId);
- }
- }
-
- @Override
- protected void invokeRegisteredCallback(@NonNull IFaceAuthenticatorsRegisteredCallback callback,
- @NonNull List<FaceSensorPropertiesInternal> allProps) throws RemoteException {
- callback.onAllAuthenticatorsRegistered(allProps);
- }
-}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
index 4efaedbd5530..6f98365332e2 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
@@ -26,13 +26,15 @@ import android.hardware.face.FaceManager;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.face.IFaceServiceReceiver;
import android.os.IBinder;
+import android.util.proto.ProtoOutputStream;
import android.view.Surface;
-import com.android.server.biometrics.sensors.BiometricServiceProvider;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.LockoutTracker;
import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.List;
/**
@@ -54,11 +56,24 @@ import java.util.List;
* to check (e.g. via {@link FaceManager#getSensorPropertiesInternal()}) that the code path isn't
* taken. ServiceProviders will provide a no-op for unsupported operations to fail safely.
*/
-public interface ServiceProvider extends BiometricServiceProvider<FaceSensorPropertiesInternal> {
+public interface ServiceProvider {
+ /**
+ * Checks if the specified sensor is owned by this provider.
+ */
+ boolean containsSensor(int sensorId);
+
+ @NonNull
+ List<FaceSensorPropertiesInternal> getSensorProperties();
+
+ @NonNull
+ FaceSensorPropertiesInternal getSensorProperties(int sensorId);
@NonNull
List<Face> getEnrolledFaces(int sensorId, int userId);
+ @LockoutTracker.LockoutMode
+ int getLockoutModeForUser(int sensorId, int userId);
+
/**
* Requests for the authenticatorId (whose source of truth is in the TEE or equivalent) to be
* invalidated. See {@link com.android.server.biometrics.sensors.InvalidationRequesterClient}
@@ -69,6 +84,10 @@ public interface ServiceProvider extends BiometricServiceProvider<FaceSensorProp
+ " this method");
}
+ long getAuthenticatorId(int sensorId, int userId);
+
+ boolean isHardwareDetected(int sensorId);
+
void scheduleGenerateChallenge(int sensorId, int userId, @NonNull IBinder token,
@NonNull IFaceServiceReceiver receiver, String opPackageName);
@@ -123,6 +142,13 @@ public interface ServiceProvider extends BiometricServiceProvider<FaceSensorProp
void scheduleInternalCleanup(int sensorId, int userId,
@Nullable ClientMonitorCallback callback, boolean favorHalEnrollments);
+ void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto,
+ boolean clearSchedulerBuffer);
+
+ void dumpProtoMetrics(int sensorId, @NonNull FileDescriptor fd);
+
+ void dumpInternal(int sensorId, @NonNull PrintWriter pw);
+
@NonNull
ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
@NonNull String opPackageName);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index 6bff179e8eb7..19d54c84c706 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -285,11 +285,6 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
}
@Override
- public boolean hasEnrollments(int sensorId, int userId) {
- return !getEnrolledFaces(sensorId, userId).isEmpty();
- }
-
- @Override
public void scheduleInvalidateAuthenticatorId(int sensorId, int userId,
@NonNull IInvalidationCallback callback) {
mHandler.post(() -> {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index c0a119ff5f1e..65289122747c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -484,11 +484,6 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
}
@Override
- public boolean hasEnrollments(int sensorId, int userId) {
- return !getEnrolledFaces(sensorId, userId).isEmpty();
- }
-
- @Override
@LockoutTracker.LockoutMode
public int getLockoutModeForUser(int sensorId, int userId) {
return mLockoutTracker.getLockoutModeForUser(userId);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 7e2742edd47a..2ba449ae089e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -17,11 +17,14 @@
package com.android.server.biometrics.sensors.fingerprint;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
+import static android.Manifest.permission.MANAGE_BIOMETRIC;
import static android.Manifest.permission.MANAGE_FINGERPRINT;
+import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT;
import static android.Manifest.permission.TEST_BIOMETRIC;
import static android.Manifest.permission.USE_BIOMETRIC;
import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
import static android.Manifest.permission.USE_FINGERPRINT;
+import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_VENDOR;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_USER_CANCELED;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_VENDOR;
@@ -33,6 +36,8 @@ import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricSensorReceiver;
@@ -60,6 +65,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Process;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
@@ -73,9 +79,11 @@ import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.internal.widget.LockPatternUtils;
+import com.android.server.ServiceThread;
import com.android.server.SystemService;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.log.BiometricContext;
@@ -107,32 +115,74 @@ public class FingerprintService extends SystemService {
protected static final String TAG = "FingerprintService";
+ private final Object mLock = new Object();
private final AppOpsManager mAppOps;
private final LockoutResetDispatcher mLockoutResetDispatcher;
private final GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;
private final LockPatternUtils mLockPatternUtils;
- @NonNull
- private final BiometricContext mBiometricContext;
- @NonNull
- private final Supplier<String[]> mAidlInstanceNameSupplier;
- @NonNull
- private final Function<String, IFingerprint> mIFingerprintProvider;
- @NonNull
- private final BiometricStateCallback<ServiceProvider, FingerprintSensorPropertiesInternal>
- mBiometricStateCallback;
- @NonNull
- private final Handler mHandler;
- @NonNull
- private final FingerprintServiceRegistry mRegistry;
+ @NonNull private final List<ServiceProvider> mServiceProviders;
+ @NonNull private final BiometricStateCallback mBiometricStateCallback;
+ @NonNull private final Handler mHandler;
+ @NonNull private final BiometricContext mBiometricContext;
+ @NonNull private final Supplier<IBiometricService> mBiometricServiceSupplier;
+ @NonNull private final Function<String, IFingerprint> mIFingerprintProvider;
+
+ @GuardedBy("mLock")
+ @NonNull private final RemoteCallbackList<IFingerprintAuthenticatorsRegisteredCallback>
+ mAuthenticatorsRegisteredCallbacks;
+
+ @GuardedBy("mLock")
+ @NonNull private final List<FingerprintSensorPropertiesInternal> mSensorProps;
+
+ /**
+ * Registers BiometricStateListener in list stored by FingerprintService
+ * @param listener new BiometricStateListener being added
+ */
+ public void registerBiometricStateListener(@NonNull IBiometricStateListener listener) {
+ mBiometricStateCallback.registerBiometricStateListener(listener);
+ broadcastCurrentEnrollmentState(listener);
+ }
- /** Receives the incoming binder calls from FingerprintManager. */
- @VisibleForTesting
- final IFingerprintService.Stub mServiceWrapper = new IFingerprintService.Stub() {
+ /**
+ * @param listener if non-null, notifies only this listener. if null, notifies all listeners
+ * in {@link BiometricStateCallback}. This is slightly ugly, but reduces
+ * redundant code.
+ */
+ private void broadcastCurrentEnrollmentState(@Nullable IBiometricStateListener listener) {
+ final UserManager um = UserManager.get(getContext());
+ synchronized (mLock) {
+ // Update the new listener with current state of all sensors
+ for (FingerprintSensorPropertiesInternal prop : mSensorProps) {
+ final ServiceProvider provider = getProviderForSensor(prop.sensorId);
+ for (UserInfo userInfo : um.getAliveUsers()) {
+ final boolean enrolled = !provider
+ .getEnrolledFingerprints(prop.sensorId, userInfo.id).isEmpty();
+
+ // Defer this work and allow the loop to release the lock sooner
+ mHandler.post(() -> {
+ if (listener != null) {
+ mBiometricStateCallback.notifyEnrollmentStateChanged(
+ listener, userInfo.id, prop.sensorId, enrolled);
+ } else {
+ mBiometricStateCallback.notifyAllEnrollmentStateChanged(
+ userInfo.id, prop.sensorId, enrolled);
+ }
+ });
+ }
+ }
+ }
+ }
+
+ /**
+ * Receives the incoming binder calls from FingerprintManager.
+ */
+ private final IFingerprintService.Stub mServiceWrapper = new IFingerprintService.Stub() {
@android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC)
@Override
public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
@NonNull String opPackageName) {
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for createTestSession, sensorId: " + sensorId);
@@ -145,8 +195,9 @@ public class FingerprintService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public byte[] dumpSensorServiceStateProto(int sensorId, boolean clearSchedulerBuffer) {
+
final ProtoOutputStream proto = new ProtoOutputStream();
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider != null) {
provider.dumpProtoState(sensorId, proto, clearSchedulerBuffer);
}
@@ -161,14 +212,16 @@ public class FingerprintService extends SystemService {
!= PackageManager.PERMISSION_GRANTED) {
Utils.checkPermission(getContext(), TEST_BIOMETRIC);
}
- return mRegistry.getAllProperties();
+
+ return FingerprintService.this.getSensorProperties();
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public FingerprintSensorPropertiesInternal getSensorProperties(int sensorId,
@NonNull String opPackageName) {
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "No matching sensor for getSensorProperties, sensorId: " + sensorId
+ ", caller: " + opPackageName);
@@ -181,7 +234,8 @@ public class FingerprintService extends SystemService {
@Override // Binder call
public void generateChallenge(IBinder token, int sensorId, int userId,
IFingerprintServiceReceiver receiver, String opPackageName) {
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "No matching sensor for generateChallenge, sensorId: " + sensorId);
return;
@@ -194,7 +248,8 @@ public class FingerprintService extends SystemService {
@Override // Binder call
public void revokeChallenge(IBinder token, int sensorId, int userId, String opPackageName,
long challenge) {
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "No matching sensor for revokeChallenge, sensorId: " + sensorId);
return;
@@ -209,7 +264,8 @@ public class FingerprintService extends SystemService {
public long enroll(final IBinder token, @NonNull final byte[] hardwareAuthToken,
final int userId, final IFingerprintServiceReceiver receiver,
final String opPackageName, @FingerprintManager.EnrollReason int enrollReason) {
- final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
+
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for enroll");
return -1;
@@ -222,7 +278,8 @@ public class FingerprintService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_FINGERPRINT)
@Override // Binder call
public void cancelEnrollment(final IBinder token, long requestId) {
- final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
+
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for cancelEnrollment");
return;
@@ -282,10 +339,10 @@ public class FingerprintService extends SystemService {
final Pair<Integer, ServiceProvider> provider;
if (sensorId == FingerprintManager.SENSOR_ID_ANY) {
- provider = mRegistry.getSingleProvider();
+ provider = getSingleProvider();
} else {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- provider = new Pair<>(sensorId, mRegistry.getProviderForSensor(sensorId));
+ provider = new Pair<>(sensorId, getProviderForSensor(sensorId));
}
if (provider == null) {
Slog.w(TAG, "Null provider for authenticate");
@@ -317,6 +374,7 @@ public class FingerprintService extends SystemService {
final IFingerprintServiceReceiver receiver,
final String opPackageName,
boolean ignoreEnrollmentState) throws PackageManager.NameNotFoundException {
+
final Context context = getUiContext();
final Context promptContext = context.createPackageContextAsUser(
opPackageName, 0 /* flags */, UserHandle.getUserHandleForUid(uId));
@@ -410,7 +468,7 @@ public class FingerprintService extends SystemService {
return -1;
}
- final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for detectFingerprint");
return -1;
@@ -426,7 +484,8 @@ public class FingerprintService extends SystemService {
public void prepareForAuthentication(int sensorId, IBinder token, long operationId,
int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
long requestId, int cookie, boolean allowBackgroundAuthentication) {
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for prepareForAuthentication");
return;
@@ -442,7 +501,8 @@ public class FingerprintService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_BIOMETRIC)
@Override // Binder call
public void startPreparedClient(int sensorId, int cookie) {
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for startPreparedClient");
return;
@@ -472,7 +532,7 @@ public class FingerprintService extends SystemService {
return;
}
- final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for cancelAuthentication");
return;
@@ -493,7 +553,7 @@ public class FingerprintService extends SystemService {
// For IBiometricsFingerprint2.1, cancelling fingerprint detect is the same as
// cancelling authentication.
- final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for cancelFingerprintDetect");
return;
@@ -506,9 +566,11 @@ public class FingerprintService extends SystemService {
@Override // Binder call
public void cancelAuthenticationFromService(final int sensorId, final IBinder token,
final String opPackageName, final long requestId) {
+
+
Slog.d(TAG, "cancelAuthenticationFromService, sensorId: " + sensorId);
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for cancelAuthenticationFromService");
return;
@@ -521,7 +583,8 @@ public class FingerprintService extends SystemService {
@Override // Binder call
public void remove(final IBinder token, final int fingerId, final int userId,
final IFingerprintServiceReceiver receiver, final String opPackageName) {
- final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
+
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for remove");
return;
@@ -554,7 +617,7 @@ public class FingerprintService extends SystemService {
// This effectively iterates through all sensors, but has to do so by finding all
// sensors under each provider.
- for (ServiceProvider provider : mRegistry.getProviders()) {
+ for (ServiceProvider provider : mServiceProviders) {
List<FingerprintSensorPropertiesInternal> props = provider.getSensorProperties();
for (FingerprintSensorPropertiesInternal prop : props) {
provider.scheduleRemoveAll(prop.sensorId, token, internalReceiver, userId,
@@ -589,7 +652,7 @@ public class FingerprintService extends SystemService {
try {
if (args.length > 1 && "--proto".equals(args[0]) && "--state".equals(args[1])) {
final ProtoOutputStream proto = new ProtoOutputStream(fd);
- for (ServiceProvider provider : mRegistry.getProviders()) {
+ for (ServiceProvider provider : mServiceProviders) {
for (FingerprintSensorPropertiesInternal props
: provider.getSensorProperties()) {
provider.dumpProtoState(props.sensorId, proto, false);
@@ -597,14 +660,14 @@ public class FingerprintService extends SystemService {
}
proto.flush();
} else if (args.length > 0 && "--proto".equals(args[0])) {
- for (ServiceProvider provider : mRegistry.getProviders()) {
+ for (ServiceProvider provider : mServiceProviders) {
for (FingerprintSensorPropertiesInternal props
: provider.getSensorProperties()) {
provider.dumpProtoMetrics(props.sensorId, fd);
}
}
} else {
- for (ServiceProvider provider : mRegistry.getProviders()) {
+ for (ServiceProvider provider : mServiceProviders) {
for (FingerprintSensorPropertiesInternal props
: provider.getSensorProperties()) {
pw.println("Dumping for sensorId: " + props.sensorId
@@ -635,7 +698,7 @@ public class FingerprintService extends SystemService {
final long token = Binder.clearCallingIdentity();
try {
- final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for isHardwareDetectedDeprecated, caller: "
+ opPackageName);
@@ -650,7 +713,8 @@ public class FingerprintService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public boolean isHardwareDetected(int sensorId, String opPackageName) {
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for isHardwareDetected, caller: " + opPackageName);
return false;
@@ -666,7 +730,7 @@ public class FingerprintService extends SystemService {
return;
}
- final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for rename");
return;
@@ -717,7 +781,8 @@ public class FingerprintService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
public boolean hasEnrolledFingerprints(int sensorId, int userId, String opPackageName) {
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for hasEnrolledFingerprints, caller: " + opPackageName);
return false;
@@ -729,7 +794,8 @@ public class FingerprintService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public @LockoutTracker.LockoutMode int getLockoutModeForUser(int sensorId, int userId) {
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for getLockoutModeForUser");
return LockoutTracker.LOCKOUT_NONE;
@@ -741,7 +807,8 @@ public class FingerprintService extends SystemService {
@Override
public void invalidateAuthenticatorId(int sensorId, int userId,
IInvalidationCallback callback) {
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for invalidateAuthenticatorId");
return;
@@ -752,7 +819,8 @@ public class FingerprintService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public long getAuthenticatorId(int sensorId, int userId) {
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for getAuthenticatorId");
return 0;
@@ -764,7 +832,8 @@ public class FingerprintService extends SystemService {
@Override // Binder call
public void resetLockout(IBinder token, int sensorId, int userId,
@Nullable byte[] hardwareAuthToken, String opPackageName) {
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for resetLockout, caller: " + opPackageName);
return;
@@ -795,38 +864,55 @@ public class FingerprintService extends SystemService {
@Override // Binder call
public void registerAuthenticators(
@NonNull List<FingerprintSensorPropertiesInternal> hidlSensors) {
- mRegistry.registerAll(() -> {
- final List<ServiceProvider> providers = new ArrayList<>();
- providers.addAll(getHidlProviders(hidlSensors));
+
+ // Some HAL might not be started before the system service and will cause the code below
+ // to wait, and some of the operations below might take a significant amount of time to
+ // complete (calls to the HALs). To avoid blocking the rest of system server we put
+ // this on a background thread.
+ final ServiceThread thread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND,
+ true /* allowIo */);
+ thread.start();
+ final Handler handler = new Handler(thread.getLooper());
+ handler.post(() -> {
List<String> aidlSensors = new ArrayList<>();
- final String[] instances = mAidlInstanceNameSupplier.get();
+ final String[] instances =
+ ServiceManager.getDeclaredInstances(IFingerprint.DESCRIPTOR);
if (instances != null) {
aidlSensors.addAll(Lists.newArrayList(instances));
}
- providers.addAll(getAidlProviders(
- Utils.filterAvailableHalInstances(getContext(), aidlSensors)));
- return providers;
+ registerAuthenticatorsForService(aidlSensors, hidlSensors);
});
+ thread.quitSafely();
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void addAuthenticatorsRegisteredCallback(
IFingerprintAuthenticatorsRegisteredCallback callback) {
- mRegistry.addAllRegisteredCallback(callback);
- }
+ if (callback == null) {
+ Slog.e(TAG, "addAuthenticatorsRegisteredCallback, callback is null");
+ return;
+ }
- @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
- @Override
- public void registerBiometricStateListener(@NonNull IBiometricStateListener listener) {
- mBiometricStateCallback.registerBiometricStateListener(listener);
+ final boolean registered;
+ final boolean hasSensorProps;
+ synchronized (mLock) {
+ registered = mAuthenticatorsRegisteredCallbacks.register(callback);
+ hasSensorProps = !mSensorProps.isEmpty();
+ }
+ if (registered && hasSensorProps) {
+ broadcastAllAuthenticatorsRegistered();
+ } else if (!registered) {
+ Slog.e(TAG, "addAuthenticatorsRegisteredCallback failed to register callback");
+ }
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void onPointerDown(long requestId, int sensorId, int x, int y,
float minor, float major) {
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "No matching provider for onFingerDown, sensorId: " + sensorId);
return;
@@ -837,7 +923,8 @@ public class FingerprintService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void onPointerUp(long requestId, int sensorId) {
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "No matching provider for onFingerUp, sensorId: " + sensorId);
return;
@@ -848,7 +935,8 @@ public class FingerprintService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void onUiReady(long requestId, int sensorId) {
- final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "No matching provider for onUiReady, sensorId: " + sensorId);
return;
@@ -859,7 +947,8 @@ public class FingerprintService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller) {
- for (ServiceProvider provider : mRegistry.getProviders()) {
+
+ for (ServiceProvider provider : mServiceProviders) {
provider.setUdfpsOverlayController(controller);
}
}
@@ -867,15 +956,22 @@ public class FingerprintService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void setSidefpsController(@NonNull ISidefpsController controller) {
- for (ServiceProvider provider : mRegistry.getProviders()) {
+
+ for (ServiceProvider provider : mServiceProviders) {
provider.setSidefpsController(controller);
}
}
- @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
+ @Override
+ public void registerBiometricStateListener(@NonNull IBiometricStateListener listener) {
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+ FingerprintService.this.registerBiometricStateListener(listener);
+ }
+
@Override
public void onPowerPressed() {
- for (ServiceProvider provider : mRegistry.getProviders()) {
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+ for (ServiceProvider provider : mServiceProviders) {
provider.onPowerPressed();
}
}
@@ -885,7 +981,6 @@ public class FingerprintService extends SystemService {
this(context, BiometricContext.getInstance(context),
() -> IBiometricService.Stub.asInterface(
ServiceManager.getService(Context.BIOMETRIC_SERVICE)),
- () -> ServiceManager.getDeclaredInstances(IFingerprint.DESCRIPTOR),
(fqName) -> IFingerprint.Stub.asInterface(
Binder.allowBlocking(ServiceManager.waitForDeclaredService(fqName))));
}
@@ -893,34 +988,61 @@ public class FingerprintService extends SystemService {
@VisibleForTesting
FingerprintService(Context context,
BiometricContext biometricContext,
- Supplier<IBiometricService> biometricServiceSupplier,
- Supplier<String[]> aidlInstanceNameSupplier,
+ Supplier<IBiometricService> biometricServiceProvider,
Function<String, IFingerprint> fingerprintProvider) {
super(context);
mBiometricContext = biometricContext;
- mAidlInstanceNameSupplier = aidlInstanceNameSupplier;
+ mBiometricServiceSupplier = biometricServiceProvider;
mIFingerprintProvider = fingerprintProvider;
mAppOps = context.getSystemService(AppOpsManager.class);
mGestureAvailabilityDispatcher = new GestureAvailabilityDispatcher();
mLockoutResetDispatcher = new LockoutResetDispatcher(context);
mLockPatternUtils = new LockPatternUtils(context);
- mBiometricStateCallback = new BiometricStateCallback<>(UserManager.get(context));
+ mServiceProviders = new ArrayList<>();
+ mBiometricStateCallback = new BiometricStateCallback();
+ mAuthenticatorsRegisteredCallbacks = new RemoteCallbackList<>();
+ mSensorProps = new ArrayList<>();
mHandler = new Handler(Looper.getMainLooper());
- mRegistry = new FingerprintServiceRegistry(mServiceWrapper, biometricServiceSupplier);
- mRegistry.addAllRegisteredCallback(new IFingerprintAuthenticatorsRegisteredCallback.Stub() {
- @Override
- public void onAllAuthenticatorsRegistered(
- List<FingerprintSensorPropertiesInternal> sensors) {
- mBiometricStateCallback.start(mRegistry.getProviders());
- }
- });
}
- @NonNull
- private List<ServiceProvider> getHidlProviders(
+ @VisibleForTesting
+ void registerAuthenticatorsForService(@NonNull List<String> aidlInstanceNames,
@NonNull List<FingerprintSensorPropertiesInternal> hidlSensors) {
- final List<ServiceProvider> providers = new ArrayList<>();
+ addHidlProviders(hidlSensors);
+ addAidlProviders(Utils.filterAvailableHalInstances(getContext(), aidlInstanceNames));
+
+ final IBiometricService biometricService = mBiometricServiceSupplier.get();
+
+ // Register each sensor individually with BiometricService
+ for (ServiceProvider provider : mServiceProviders) {
+ final List<FingerprintSensorPropertiesInternal> props =
+ provider.getSensorProperties();
+ for (FingerprintSensorPropertiesInternal prop : props) {
+ final int sensorId = prop.sensorId;
+ @BiometricManager.Authenticators.Types final int strength =
+ Utils.propertyStrengthToAuthenticatorStrength(prop.sensorStrength);
+ final FingerprintAuthenticator authenticator = new FingerprintAuthenticator(
+ mServiceWrapper, sensorId);
+ try {
+ biometricService.registerAuthenticator(sensorId, TYPE_FINGERPRINT,
+ strength, authenticator);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception when registering sensorId: " + sensorId);
+ }
+ }
+ }
+
+ synchronized (mLock) {
+ for (ServiceProvider provider : mServiceProviders) {
+ mSensorProps.addAll(provider.getSensorProperties());
+ }
+ }
+ broadcastCurrentEnrollmentState(null); // broadcasts to all listeners
+ broadcastAllAuthenticatorsRegistered();
+ }
+
+ private void addHidlProviders(List<FingerprintSensorPropertiesInternal> hidlSensors) {
for (FingerprintSensorPropertiesInternal hidlSensor : hidlSensors) {
final Fingerprint21 fingerprint21;
if ((Build.IS_USERDEBUG || Build.IS_ENG)
@@ -937,16 +1059,11 @@ public class FingerprintService extends SystemService {
mBiometricStateCallback, hidlSensor, mHandler,
mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
}
- providers.add(fingerprint21);
+ mServiceProviders.add(fingerprint21);
}
-
- return providers;
}
- @NonNull
- private List<ServiceProvider> getAidlProviders(@NonNull List<String> instances) {
- final List<ServiceProvider> providers = new ArrayList<>();
-
+ private void addAidlProviders(List<String> instances) {
for (String instance : instances) {
final String fqName = IFingerprint.DESCRIPTOR + "/" + instance;
final IFingerprint fp = mIFingerprintProvider.apply(fqName);
@@ -958,7 +1075,7 @@ public class FingerprintService extends SystemService {
mLockoutResetDispatcher, mGestureAvailabilityDispatcher,
mBiometricContext);
Slog.i(TAG, "Adding AIDL provider: " + fqName);
- providers.add(provider);
+ mServiceProviders.add(provider);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception in getSensorProps: " + fqName);
}
@@ -966,8 +1083,38 @@ public class FingerprintService extends SystemService {
Slog.e(TAG, "Unable to get declared service: " + fqName);
}
}
+ }
- return providers;
+ // Notifies the callbacks that all of the authenticators have been registered and removes the
+ // invoked callbacks from the callback list.
+ private void broadcastAllAuthenticatorsRegistered() {
+ // Make a local copy of the data so it can be used outside of the synchronized block when
+ // making Binder calls.
+ final List<IFingerprintAuthenticatorsRegisteredCallback> callbacks = new ArrayList<>();
+ final List<FingerprintSensorPropertiesInternal> props;
+ synchronized (mLock) {
+ if (!mSensorProps.isEmpty()) {
+ props = new ArrayList<>(mSensorProps);
+ } else {
+ Slog.e(TAG, "mSensorProps is empty");
+ return;
+ }
+ final int n = mAuthenticatorsRegisteredCallbacks.beginBroadcast();
+ for (int i = 0; i < n; ++i) {
+ final IFingerprintAuthenticatorsRegisteredCallback cb =
+ mAuthenticatorsRegisteredCallbacks.getBroadcastItem(i);
+ callbacks.add(cb);
+ mAuthenticatorsRegisteredCallbacks.unregister(cb);
+ }
+ mAuthenticatorsRegisteredCallbacks.finishBroadcast();
+ }
+ for (IFingerprintAuthenticatorsRegisteredCallback cb : callbacks) {
+ try {
+ cb.onAllAuthenticatorsRegistered(props);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception in onAllAuthenticatorsRegistered", e);
+ }
+ }
}
@Override
@@ -975,9 +1122,51 @@ public class FingerprintService extends SystemService {
publishBinderService(Context.FINGERPRINT_SERVICE, mServiceWrapper);
}
+ @Nullable
+ private ServiceProvider getProviderForSensor(int sensorId) {
+ for (ServiceProvider provider : mServiceProviders) {
+ if (provider.containsSensor(sensorId)) {
+ return provider;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * For devices with only a single provider, returns that provider. If multiple providers,
+ * returns the first one. If no providers, returns null.
+ */
+ @Nullable
+ private Pair<Integer, ServiceProvider> getSingleProvider() {
+ final List<FingerprintSensorPropertiesInternal> properties = getSensorProperties();
+ if (properties.isEmpty()) {
+ Slog.e(TAG, "No providers found");
+ return null;
+ }
+
+ // Theoretically we can just return the first provider, but maybe this is easier to
+ // understand.
+ final int sensorId = properties.get(0).sensorId;
+ for (ServiceProvider provider : mServiceProviders) {
+ if (provider.containsSensor(sensorId)) {
+ return new Pair<>(sensorId, provider);
+ }
+ }
+
+ Slog.e(TAG, "Provider not found");
+ return null;
+ }
+
+ @NonNull
+ private List<FingerprintSensorPropertiesInternal> getSensorProperties() {
+ synchronized (mLock) {
+ return mSensorProps;
+ }
+ }
+
@NonNull
private List<Fingerprint> getEnrolledFingerprintsDeprecated(int userId, String opPackageName) {
- final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for getEnrolledFingerprintsDeprecated, caller: "
+ opPackageName);
@@ -1040,7 +1229,7 @@ public class FingerprintService extends SystemService {
if (Utils.isVirtualEnabled(getContext())) {
Slog.i(TAG, "Sync virtual enrollments");
final int userId = ActivityManager.getCurrentUser();
- for (ServiceProvider provider : mRegistry.getProviders()) {
+ for (ServiceProvider provider : mServiceProviders) {
for (FingerprintSensorPropertiesInternal props : provider.getSensorProperties()) {
provider.scheduleInternalCleanup(props.sensorId, userId, null /* callback */,
true /* favorHalEnrollments */);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceRegistry.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceRegistry.java
deleted file mode 100644
index 33810b764f23..000000000000
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceRegistry.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.biometrics.sensors.fingerprint;
-
-import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.hardware.biometrics.BiometricManager;
-import android.hardware.biometrics.IBiometricService;
-import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
-import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
-import android.hardware.fingerprint.IFingerprintService;
-import android.os.RemoteException;
-import android.util.Slog;
-
-import com.android.server.biometrics.Utils;
-import com.android.server.biometrics.sensors.BiometricServiceRegistry;
-
-import java.util.List;
-import java.util.function.Supplier;
-
-/** Registry for {@link IFingerprintService} providers. */
-public class FingerprintServiceRegistry extends BiometricServiceRegistry<ServiceProvider,
- FingerprintSensorPropertiesInternal, IFingerprintAuthenticatorsRegisteredCallback> {
-
- private static final String TAG = "FingerprintServiceRegistry";
-
- @NonNull
- private final IFingerprintService mService;
-
- /** Creates a new registry tied to the given service. */
- public FingerprintServiceRegistry(@NonNull IFingerprintService service,
- @Nullable Supplier<IBiometricService> biometricSupplier) {
- super(biometricSupplier);
- mService = service;
- }
-
- @Override
- protected void registerService(@NonNull IBiometricService service,
- @NonNull FingerprintSensorPropertiesInternal props) {
- @BiometricManager.Authenticators.Types final int strength =
- Utils.propertyStrengthToAuthenticatorStrength(props.sensorStrength);
- try {
- service.registerAuthenticator(props.sensorId, TYPE_FINGERPRINT, strength,
- new FingerprintAuthenticator(mService, props.sensorId));
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception when registering sensorId: " + props.sensorId);
- }
- }
-
- @Override
- protected void invokeRegisteredCallback(
- @NonNull IFingerprintAuthenticatorsRegisteredCallback callback,
- @NonNull List<FingerprintSensorPropertiesInternal> allProps) throws RemoteException {
- callback.onAllAuthenticatorsRegistered(allProps);
- }
-}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
index 9075e7ec2080..275d7e445a75 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
@@ -28,11 +28,14 @@ import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.hardware.fingerprint.ISidefpsController;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.IBinder;
+import android.util.proto.ProtoOutputStream;
-import com.android.server.biometrics.sensors.BiometricServiceProvider;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.LockoutTracker;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.List;
/**
@@ -56,8 +59,23 @@ import java.util.List;
* fail safely.
*/
@SuppressWarnings("deprecation")
-public interface ServiceProvider extends
- BiometricServiceProvider<FingerprintSensorPropertiesInternal> {
+public interface ServiceProvider {
+ /**
+ * Checks if the specified sensor is owned by this provider.
+ */
+ boolean containsSensor(int sensorId);
+
+ @NonNull
+ List<FingerprintSensorPropertiesInternal> getSensorProperties();
+
+ /**
+ * Returns the internal properties of the specified sensor, if owned by this provider.
+ *
+ * @param sensorId The ID of a fingerprint sensor, or -1 for any sensor.
+ * @return An object representing the internal properties of the specified sensor.
+ */
+ @Nullable
+ FingerprintSensorPropertiesInternal getSensorProperties(int sensorId);
void scheduleResetLockout(int sensorId, int userId, @Nullable byte[] hardwareAuthToken);
@@ -108,11 +126,16 @@ public interface ServiceProvider extends
void scheduleInternalCleanup(int sensorId, int userId,
@Nullable ClientMonitorCallback callback, boolean favorHalEnrollments);
+ boolean isHardwareDetected(int sensorId);
+
void rename(int sensorId, int fingerId, int userId, @NonNull String name);
@NonNull
List<Fingerprint> getEnrolledFingerprints(int sensorId, int userId);
+ @LockoutTracker.LockoutMode
+ int getLockoutModeForUser(int sensorId, int userId);
+
/**
* Requests for the authenticatorId (whose source of truth is in the TEE or equivalent) to
* be invalidated. See {@link com.android.server.biometrics.sensors.InvalidationRequesterClient}
@@ -120,6 +143,7 @@ public interface ServiceProvider extends
void scheduleInvalidateAuthenticatorId(int sensorId, int userId,
@NonNull IInvalidationCallback callback);
+ long getAuthenticatorId(int sensorId, int userId);
void onPointerDown(long requestId, int sensorId, int x, int y, float minor, float major);
@@ -137,6 +161,13 @@ public interface ServiceProvider extends
*/
void setSidefpsController(@NonNull ISidefpsController controller);
+ void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto,
+ boolean clearSchedulerBuffer);
+
+ void dumpProtoMetrics(int sensorId, @NonNull FileDescriptor fd);
+
+ void dumpInternal(int sensorId, @NonNull PrintWriter pw);
+
@NonNull
ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
@NonNull String opPackageName);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index 3fe6332fcaa0..2dc005206b42 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -565,11 +565,6 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
}
@Override
- public boolean hasEnrollments(int sensorId, int userId) {
- return !getEnrolledFingerprints(sensorId, userId).isEmpty();
- }
-
- @Override
public void scheduleInvalidateAuthenticatorId(int sensorId, int userId,
@NonNull IInvalidationCallback callback) {
mHandler.post(() -> {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index 0e6df8e0df77..ed482f013869 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -789,11 +789,6 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
}
@Override
- public boolean hasEnrollments(int sensorId, int userId) {
- return !getEnrolledFingerprints(sensorId, userId).isEmpty();
- }
-
- @Override
@LockoutTracker.LockoutMode public int getLockoutModeForUser(int sensorId, int userId) {
return mLockoutTracker.getLockoutModeForUser(userId);
}
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 05d32d1d9023..6145a91cf7cd 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -1008,8 +1008,9 @@ class AutomaticBrightnessController {
final String packageName = info.topActivity.getPackageName();
// If the app didn't change, there's nothing to do. Otherwise, we have to
// update the category and re-apply the brightness correction.
- if (mForegroundAppPackageName != null
- && mForegroundAppPackageName.equals(packageName)) {
+ String currentForegroundAppPackageName = mForegroundAppPackageName;
+ if (currentForegroundAppPackageName != null
+ && currentForegroundAppPackageName.equals(packageName)) {
return;
}
mPendingForegroundAppPackageName = packageName;
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 7b60345caf87..4e0489a5c4bc 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -218,6 +218,7 @@ public final class DreamManagerService extends SystemService {
}, pw, "", 200);
}
+ /** Whether a real dream is occurring. */
private boolean isDreamingInternal() {
synchronized (mLock) {
return mCurrentDreamToken != null && !mCurrentDreamIsPreview
@@ -225,6 +226,13 @@ public final class DreamManagerService extends SystemService {
}
}
+ /** Whether a real dream, or a dream preview is occurring. */
+ private boolean isDreamingOrInPreviewInternal() {
+ synchronized (mLock) {
+ return mCurrentDreamToken != null && !mCurrentDreamIsWaking;
+ }
+ }
+
protected void requestStartDreamFromShell() {
requestDreamInternal();
}
@@ -695,6 +703,19 @@ public final class DreamManagerService extends SystemService {
}
@Override // Binder call
+ public boolean isDreamingOrInPreview() {
+ checkPermission(android.Manifest.permission.READ_DREAM_STATE);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return isDreamingOrInPreviewInternal();
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+
+ @Override // Binder call
public void dream() {
checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 2070c2b31236..e03b423bf83e 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -5170,7 +5170,8 @@ public class NotificationManagerService extends SystemService {
extras,
mRankingHelper.findExtractor(ValidateNotificationPeople.class),
MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
- MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
+ MATCHES_CALL_FILTER_TIMEOUT_AFFINITY,
+ Binder.getCallingUid());
}
@Override
diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java
index 7d7f3a96595c..c0bc474cd8fa 100644
--- a/services/core/java/com/android/server/notification/ZenLog.java
+++ b/services/core/java/com/android/server/notification/ZenLog.java
@@ -66,6 +66,8 @@ public class ZenLog {
private static final int TYPE_SET_NOTIFICATION_POLICY = 16;
private static final int TYPE_SET_CONSOLIDATED_ZEN_POLICY = 17;
private static final int TYPE_MATCHES_CALL_FILTER = 18;
+ private static final int TYPE_RECORD_CALLER = 19;
+ private static final int TYPE_CHECK_REPEAT_CALLER = 20;
private static int sNext;
private static int sSize;
@@ -167,11 +169,28 @@ public class ZenLog {
+ hintsToString(newHints) + ",listeners=" + listenerCount);
}
- /*
+ /**
* Trace calls to matchesCallFilter with the result of the call and the reason for the result.
*/
- public static void traceMatchesCallFilter(boolean result, String reason) {
- append(TYPE_MATCHES_CALL_FILTER, "result=" + result + ", reason=" + reason);
+ public static void traceMatchesCallFilter(boolean result, String reason, int callingUid) {
+ append(TYPE_MATCHES_CALL_FILTER, "result=" + result + ", reason=" + reason
+ + ", calling uid=" + callingUid);
+ }
+
+ /**
+ * Trace what information is available about an incoming call when it's recorded
+ */
+ public static void traceRecordCaller(boolean hasPhone, boolean hasUri) {
+ append(TYPE_RECORD_CALLER, "has phone number=" + hasPhone + ", has uri=" + hasUri);
+ }
+
+ /**
+ * Trace what information was provided about a caller when checking whether it is from a repeat
+ * caller
+ */
+ public static void traceCheckRepeatCaller(boolean found, boolean hasPhone, boolean hasUri) {
+ append(TYPE_CHECK_REPEAT_CALLER, "res=" + found + ", given phone number=" + hasPhone
+ + ", given uri=" + hasUri);
}
private static String subscribeResult(IConditionProvider provider, RemoteException e) {
@@ -198,6 +217,8 @@ public class ZenLog {
case TYPE_SET_NOTIFICATION_POLICY: return "set_notification_policy";
case TYPE_SET_CONSOLIDATED_ZEN_POLICY: return "set_consolidated_policy";
case TYPE_MATCHES_CALL_FILTER: return "matches_call_filter";
+ case TYPE_RECORD_CALLER: return "record_caller";
+ case TYPE_CHECK_REPEAT_CALLER: return "check_repeat_caller";
default: return "unknown";
}
}
diff --git a/services/core/java/com/android/server/notification/ZenModeFiltering.java b/services/core/java/com/android/server/notification/ZenModeFiltering.java
index b0d40efed690..7e36aed81d4a 100644
--- a/services/core/java/com/android/server/notification/ZenModeFiltering.java
+++ b/services/core/java/com/android/server/notification/ZenModeFiltering.java
@@ -101,23 +101,24 @@ public class ZenModeFiltering {
*/
public static boolean matchesCallFilter(Context context, int zen, NotificationManager.Policy
consolidatedPolicy, UserHandle userHandle, Bundle extras,
- ValidateNotificationPeople validator, int contactsTimeoutMs, float timeoutAffinity) {
+ ValidateNotificationPeople validator, int contactsTimeoutMs, float timeoutAffinity,
+ int callingUid) {
if (zen == Global.ZEN_MODE_NO_INTERRUPTIONS) {
- ZenLog.traceMatchesCallFilter(false, "no interruptions");
+ ZenLog.traceMatchesCallFilter(false, "no interruptions", callingUid);
return false; // nothing gets through
}
if (zen == Global.ZEN_MODE_ALARMS) {
- ZenLog.traceMatchesCallFilter(false, "alarms only");
+ ZenLog.traceMatchesCallFilter(false, "alarms only", callingUid);
return false; // not an alarm
}
if (zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {
if (consolidatedPolicy.allowRepeatCallers()
&& REPEAT_CALLERS.isRepeat(context, extras, null)) {
- ZenLog.traceMatchesCallFilter(true, "repeat caller");
+ ZenLog.traceMatchesCallFilter(true, "repeat caller", callingUid);
return true;
}
if (!consolidatedPolicy.allowCalls()) {
- ZenLog.traceMatchesCallFilter(false, "calls not allowed");
+ ZenLog.traceMatchesCallFilter(false, "calls not allowed", callingUid);
return false; // no other calls get through
}
if (validator != null) {
@@ -125,11 +126,12 @@ public class ZenModeFiltering {
contactsTimeoutMs, timeoutAffinity);
boolean match =
audienceMatches(consolidatedPolicy.allowCallsFrom(), contactAffinity);
- ZenLog.traceMatchesCallFilter(match, "contact affinity " + contactAffinity);
+ ZenLog.traceMatchesCallFilter(match, "contact affinity " + contactAffinity,
+ callingUid);
return match;
}
}
- ZenLog.traceMatchesCallFilter(true, "no restrictions");
+ ZenLog.traceMatchesCallFilter(true, "no restrictions", callingUid);
return true;
}
@@ -419,6 +421,7 @@ public class ZenModeFiltering {
private synchronized void recordCallers(String[] people, ArraySet<String> phoneNumbers,
long now) {
+ boolean recorded = false, hasTel = false, hasOther = false;
for (int i = 0; i < people.length; i++) {
String person = people[i];
if (person == null) continue;
@@ -427,10 +430,16 @@ public class ZenModeFiltering {
// while ideally we should not need to decode this, sometimes we have seen tel
// numbers given in an encoded format
String tel = Uri.decode(uri.getSchemeSpecificPart());
- if (tel != null) mTelCalls.put(tel, now);
+ if (tel != null) {
+ mTelCalls.put(tel, now);
+ recorded = true;
+ hasTel = true;
+ }
} else {
// for non-tel calls, store the entire string, uri-component and all
mOtherCalls.put(person, now);
+ recorded = true;
+ hasOther = true;
}
}
@@ -438,9 +447,16 @@ public class ZenModeFiltering {
// provided; these are in the format of just a phone number string
if (phoneNumbers != null) {
for (String num : phoneNumbers) {
- if (num != null) mTelCalls.put(num, now);
+ if (num != null) {
+ mTelCalls.put(num, now);
+ recorded = true;
+ hasTel = true;
+ }
}
}
+ if (recorded) {
+ ZenLog.traceRecordCaller(hasTel, hasOther);
+ }
}
// helper function to check mTelCalls array for a number, and also check its decoded
@@ -468,6 +484,8 @@ public class ZenModeFiltering {
// previously recorded phone call.
private synchronized boolean checkCallers(Context context, String[] people,
ArraySet<String> phoneNumbers) {
+ boolean found = false, checkedTel = false, checkedOther = false;
+
// get the default country code for checking telephone numbers
final String defaultCountryCode =
context.getSystemService(TelephonyManager.class).getNetworkCountryIso();
@@ -477,12 +495,14 @@ public class ZenModeFiltering {
final Uri uri = Uri.parse(person);
if ("tel".equals(uri.getScheme())) {
String number = uri.getSchemeSpecificPart();
+ checkedTel = true;
if (checkForNumber(number, defaultCountryCode)) {
- return true;
+ found = true;
}
} else {
+ checkedOther = true;
if (mOtherCalls.containsKey(person)) {
- return true;
+ found = true;
}
}
}
@@ -490,14 +510,16 @@ public class ZenModeFiltering {
// also check any passed-in phone numbers
if (phoneNumbers != null) {
for (String num : phoneNumbers) {
+ checkedTel = true;
if (checkForNumber(num, defaultCountryCode)) {
- return true;
+ found = true;
}
}
}
// no matches
- return false;
+ ZenLog.traceCheckRepeatCaller(found, checkedTel, checkedOther);
+ return found;
}
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 6135fe8acbed..d42667951608 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -177,10 +177,12 @@ public class ZenModeHelper {
}
public boolean matchesCallFilter(UserHandle userHandle, Bundle extras,
- ValidateNotificationPeople validator, int contactsTimeoutMs, float timeoutAffinity) {
+ ValidateNotificationPeople validator, int contactsTimeoutMs, float timeoutAffinity,
+ int callingUid) {
synchronized (mConfig) {
return ZenModeFiltering.matchesCallFilter(mContext, mZenMode, mConsolidatedPolicy,
- userHandle, extras, validator, contactsTimeoutMs, timeoutAffinity);
+ userHandle, extras, validator, contactsTimeoutMs, timeoutAffinity,
+ callingUid);
}
}
diff --git a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
index b05e44f9e625..da76738fa025 100644
--- a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
+++ b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
@@ -306,7 +306,7 @@ final class OverlayManagerShellCommand extends ShellCommand {
} else {
final String resourceName = getNextArgRequired();
final String typeStr = getNextArgRequired();
- final String strData = getNextArgRequired();
+ final String strData = String.join(" ", peekRemainingArgs());
addOverlayValue(overlayBuilder, resourceName, typeStr, strData);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e9637ec30302..99c95d56083a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -7062,7 +7062,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mResolveActivity.processName = pkg.getProcessName();
mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS
- | ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
+ | ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS
+ | ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES;
mResolveActivity.theme = 0;
mResolveActivity.exported = true;
mResolveActivity.enabled = true;
@@ -7095,7 +7096,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER;
mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS
- | ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
+ | ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY
+ | ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES;
mResolveActivity.theme = R.style.Theme_Material_Dialog_Alert;
mResolveActivity.exported = true;
mResolveActivity.enabled = true;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index c64e5255c78c..d11adc13795d 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -5640,7 +5640,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
ProtoLog.v(WM_DEBUG_ADD_REMOVE, "notifyAppResumed: wasStopped=%b %s",
wasStopped, this);
mAppStopped = false;
- // Allow the window to turn the screen on once the app is resumed again.
+ // Allow the window to turn the screen on once the app is started and resumed.
if (mAtmService.getActivityStartController().isInExecution()) {
setCurrentLaunchCanTurnScreenOn(true);
}
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 77d6097a9c69..8f18064b4723 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -94,6 +94,7 @@ public class ActivityStartController {
boolean mCheckedForSetup = false;
+ /** Whether an {@link ActivityStarter} is currently executing (starting an Activity). */
private boolean mInExecution = false;
/**
@@ -129,7 +130,7 @@ public class ActivityStartController {
return mFactory.obtain().setIntent(intent).setReason(reason);
}
- void onExecutionStarted(ActivityStarter starter) {
+ void onExecutionStarted() {
mInExecution = true;
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index abedd96d1cde..619d693068d4 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1267,7 +1267,7 @@ class ActivityStarter {
}
private void onExecutionStarted() {
- mController.onExecutionStarted(this);
+ mController.onExecutionStarted();
}
private boolean isHomeApp(int uid, @Nullable String packageName) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index cae722ece7c7..e23380088dc4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2623,27 +2623,32 @@ public class WindowManagerService extends IWindowManager.Stub
transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
}
- String reason = null;
- if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) {
- reason = "applyAnimation";
- focusMayChange = true;
- win.mAnimatingExit = true;
- } else if (win.mDisplayContent.okToAnimate() && win.isExitAnimationRunningSelfOrParent()) {
- // Currently in a hide animation... turn this into
- // an exit.
- win.mAnimatingExit = true;
- } else if (win.mDisplayContent.okToAnimate()
- && win.mDisplayContent.mWallpaperController.isWallpaperTarget(win)
- && win.mAttrs.type != TYPE_NOTIFICATION_SHADE) {
- reason = "isWallpaperTarget";
- // If the wallpaper is currently behind this app window, we need to change both of them
- // inside of a transaction to avoid artifacts.
- // For NotificationShade, sysui is in charge of running window animation and it updates
- // the client view visibility only after both NotificationShade and the wallpaper are
- // hidden. So we don't need to care about exit animation, but can destroy its surface
- // immediately.
- win.mAnimatingExit = true;
- } else {
+ if (win.isWinVisibleLw() && win.mDisplayContent.okToAnimate()) {
+ String reason = null;
+ if (winAnimator.applyAnimationLocked(transit, false)) {
+ reason = "applyAnimation";
+ focusMayChange = true;
+ win.mAnimatingExit = true;
+ } else if (win.isExitAnimationRunningSelfOrParent()) {
+ reason = "animating";
+ win.mAnimatingExit = true;
+ } else if (win.mDisplayContent.mWallpaperController.isWallpaperTarget(win)
+ && win.mAttrs.type != TYPE_NOTIFICATION_SHADE) {
+ reason = "isWallpaperTarget";
+ // If the wallpaper is currently behind this app window, they should be updated
+ // in a transaction to avoid artifacts.
+ // For NotificationShade, sysui is in charge of running window animation and it
+ // updates the client view visibility only after both NotificationShade and the
+ // wallpaper are hidden. So the exit animation is not needed and can destroy its
+ // surface immediately.
+ win.mAnimatingExit = true;
+ }
+ if (reason != null) {
+ ProtoLog.d(WM_DEBUG_ANIM,
+ "Set animatingExit: reason=startExitingAnimation/%s win=%s", reason, win);
+ }
+ }
+ if (!win.mAnimatingExit) {
boolean stopped = win.mActivityRecord == null || win.mActivityRecord.mAppStopped;
// We set mDestroying=true so ActivityRecord#notifyAppStopped in-to destroy surfaces
// will later actually destroy the surface if we do not do so here. Normally we leave
@@ -2651,10 +2656,6 @@ public class WindowManagerService extends IWindowManager.Stub
win.mDestroying = true;
win.destroySurface(false, stopped);
}
- if (reason != null) {
- ProtoLog.d(WM_DEBUG_ANIM, "Set animatingExit: reason=startExitingAnimation/%s win=%s",
- reason, win);
- }
if (mAccessibilityController.hasCallbacks()) {
mAccessibilityController.onWindowTransition(win, transit);
}
diff --git a/services/people/java/com/android/server/people/data/ConversationInfo.java b/services/people/java/com/android/server/people/data/ConversationInfo.java
index 16c4c29a798e..6ead44a8cd1b 100644
--- a/services/people/java/com/android/server/people/data/ConversationInfo.java
+++ b/services/people/java/com/android/server/people/data/ConversationInfo.java
@@ -26,6 +26,7 @@ import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutInfo.ShortcutFlags;
import android.net.Uri;
import android.text.TextUtils;
+import android.util.Log;
import android.util.Slog;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoOutputStream;
@@ -37,6 +38,7 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
+import java.io.EOFException;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -50,6 +52,11 @@ import java.util.Objects;
* Represents a conversation that is provided by the app based on {@link ShortcutInfo}.
*/
public class ConversationInfo {
+ private static final boolean DEBUG = false;
+
+ // Schema version for the backup payload. Must be incremented whenever fields are added in
+ // backup payload.
+ private static final int VERSION = 1;
private static final String TAG = ConversationInfo.class.getSimpleName();
@@ -100,6 +107,8 @@ public class ConversationInfo {
private long mLastEventTimestamp;
+ private long mCreationTimestamp;
+
@ShortcutFlags
private int mShortcutFlags;
@@ -116,6 +125,7 @@ public class ConversationInfo {
mNotificationChannelId = builder.mNotificationChannelId;
mParentNotificationChannelId = builder.mParentNotificationChannelId;
mLastEventTimestamp = builder.mLastEventTimestamp;
+ mCreationTimestamp = builder.mCreationTimestamp;
mShortcutFlags = builder.mShortcutFlags;
mConversationFlags = builder.mConversationFlags;
mCurrStatuses = builder.mCurrStatuses;
@@ -170,6 +180,13 @@ public class ConversationInfo {
return mLastEventTimestamp;
}
+ /**
+ * Timestamp of the creation of the conversationInfo.
+ */
+ long getCreationTimestamp() {
+ return mCreationTimestamp;
+ }
+
/** Whether the shortcut for this conversation is set long-lived by the app. */
public boolean isShortcutLongLived() {
return hasShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED);
@@ -241,6 +258,7 @@ public class ConversationInfo {
&& Objects.equals(mNotificationChannelId, other.mNotificationChannelId)
&& Objects.equals(mParentNotificationChannelId, other.mParentNotificationChannelId)
&& Objects.equals(mLastEventTimestamp, other.mLastEventTimestamp)
+ && mCreationTimestamp == other.mCreationTimestamp
&& mShortcutFlags == other.mShortcutFlags
&& mConversationFlags == other.mConversationFlags
&& Objects.equals(mCurrStatuses, other.mCurrStatuses);
@@ -250,7 +268,7 @@ public class ConversationInfo {
public int hashCode() {
return Objects.hash(mShortcutId, mLocusId, mContactUri, mContactPhoneNumber,
mNotificationChannelId, mParentNotificationChannelId, mLastEventTimestamp,
- mShortcutFlags, mConversationFlags, mCurrStatuses);
+ mCreationTimestamp, mShortcutFlags, mConversationFlags, mCurrStatuses);
}
@Override
@@ -264,6 +282,7 @@ public class ConversationInfo {
sb.append(", notificationChannelId=").append(mNotificationChannelId);
sb.append(", parentNotificationChannelId=").append(mParentNotificationChannelId);
sb.append(", lastEventTimestamp=").append(mLastEventTimestamp);
+ sb.append(", creationTimestamp=").append(mCreationTimestamp);
sb.append(", statuses=").append(mCurrStatuses);
sb.append(", shortcutFlags=0x").append(Integer.toHexString(mShortcutFlags));
sb.append(" [");
@@ -329,6 +348,7 @@ public class ConversationInfo {
mParentNotificationChannelId);
}
protoOutputStream.write(ConversationInfoProto.LAST_EVENT_TIMESTAMP, mLastEventTimestamp);
+ protoOutputStream.write(ConversationInfoProto.CREATION_TIMESTAMP, mCreationTimestamp);
protoOutputStream.write(ConversationInfoProto.SHORTCUT_FLAGS, mShortcutFlags);
protoOutputStream.write(ConversationInfoProto.CONVERSATION_FLAGS, mConversationFlags);
if (mContactPhoneNumber != null) {
@@ -352,6 +372,8 @@ public class ConversationInfo {
out.writeUTF(mContactPhoneNumber != null ? mContactPhoneNumber : "");
out.writeUTF(mParentNotificationChannelId != null ? mParentNotificationChannelId : "");
out.writeLong(mLastEventTimestamp);
+ out.writeInt(VERSION);
+ out.writeLong(mCreationTimestamp);
// ConversationStatus is a transient object and not persisted
} catch (IOException e) {
Slog.e(TAG, "Failed to write fields to backup payload.", e);
@@ -399,6 +421,9 @@ public class ConversationInfo {
builder.setLastEventTimestamp(protoInputStream.readLong(
ConversationInfoProto.LAST_EVENT_TIMESTAMP));
break;
+ case (int) ConversationInfoProto.CREATION_TIMESTAMP:
+ builder.setCreationTimestamp(protoInputStream.readLong(
+ ConversationInfoProto.CREATION_TIMESTAMP));
case (int) ConversationInfoProto.SHORTCUT_FLAGS:
builder.setShortcutFlags(protoInputStream.readInt(
ConversationInfoProto.SHORTCUT_FLAGS));
@@ -448,6 +473,10 @@ public class ConversationInfo {
builder.setParentNotificationChannelId(parentNotificationChannelId);
}
builder.setLastEventTimestamp(in.readLong());
+ int payloadVersion = maybeReadVersion(in);
+ if (payloadVersion == 1) {
+ builder.setCreationTimestamp(in.readLong());
+ }
} catch (IOException e) {
Slog.e(TAG, "Failed to read conversation info fields from backup payload.", e);
return null;
@@ -455,6 +484,16 @@ public class ConversationInfo {
return builder.build();
}
+ private static int maybeReadVersion(DataInputStream in) throws IOException {
+ try {
+ return in.readInt();
+ } catch (EOFException eofException) {
+ // EOF is expected if using old backup payload protocol.
+ if (DEBUG) Log.d(TAG, "Eof reached for data stream, missing version number");
+ return 0;
+ }
+ }
+
/**
* Builder class for {@link ConversationInfo} objects.
*/
@@ -479,6 +518,8 @@ public class ConversationInfo {
private long mLastEventTimestamp;
+ private long mCreationTimestamp;
+
@ShortcutFlags
private int mShortcutFlags;
@@ -502,6 +543,7 @@ public class ConversationInfo {
mNotificationChannelId = conversationInfo.mNotificationChannelId;
mParentNotificationChannelId = conversationInfo.mParentNotificationChannelId;
mLastEventTimestamp = conversationInfo.mLastEventTimestamp;
+ mCreationTimestamp = conversationInfo.mCreationTimestamp;
mShortcutFlags = conversationInfo.mShortcutFlags;
mConversationFlags = conversationInfo.mConversationFlags;
mCurrStatuses = conversationInfo.mCurrStatuses;
@@ -542,6 +584,11 @@ public class ConversationInfo {
return this;
}
+ Builder setCreationTimestamp(long creationTimestamp) {
+ mCreationTimestamp = creationTimestamp;
+ return this;
+ }
+
Builder setShortcutFlags(@ShortcutFlags int shortcutFlags) {
mShortcutFlags = shortcutFlags;
return this;
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index d305fc5d7dc4..693f3a0cf8a0 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -816,10 +816,18 @@ public class DataManager {
}
private boolean isCachedRecentConversation(ConversationInfo conversationInfo) {
+ return isEligibleForCleanUp(conversationInfo)
+ && conversationInfo.getLastEventTimestamp() > 0L;
+ }
+
+ /**
+ * Conversations that are cached and not customized are eligible for clean-up, even if they
+ * don't have an associated notification event with them.
+ */
+ private boolean isEligibleForCleanUp(ConversationInfo conversationInfo) {
return conversationInfo.isShortcutCachedForNotification()
&& Objects.equals(conversationInfo.getNotificationChannelId(),
- conversationInfo.getParentNotificationChannelId())
- && conversationInfo.getLastEventTimestamp() > 0L;
+ conversationInfo.getParentNotificationChannelId());
}
private boolean hasActiveNotifications(String packageName, @UserIdInt int userId,
@@ -842,14 +850,14 @@ public class DataManager {
}
// pair of <package name, conversation info>
List<Pair<String, ConversationInfo>> cachedConvos = new ArrayList<>();
- userData.forAllPackages(packageData ->
+ userData.forAllPackages(packageData -> {
packageData.forAllConversations(conversationInfo -> {
- if (isCachedRecentConversation(conversationInfo)) {
+ if (isEligibleForCleanUp(conversationInfo)) {
cachedConvos.add(
Pair.create(packageData.getPackageName(), conversationInfo));
}
- })
- );
+ });
+ });
if (cachedConvos.size() <= targetCachedCount) {
return;
}
@@ -858,7 +866,9 @@ public class DataManager {
PriorityQueue<Pair<String, ConversationInfo>> maxHeap = new PriorityQueue<>(
numToUncache + 1,
Comparator.comparingLong((Pair<String, ConversationInfo> pair) ->
- pair.second.getLastEventTimestamp()).reversed());
+ Math.max(
+ pair.second.getLastEventTimestamp(),
+ pair.second.getCreationTimestamp())).reversed());
for (Pair<String, ConversationInfo> cached : cachedConvos) {
if (hasActiveNotifications(cached.first, userId, cached.second.getShortcutId())) {
continue;
@@ -893,7 +903,7 @@ public class DataManager {
}
ConversationInfo.Builder builder = oldConversationInfo != null
? new ConversationInfo.Builder(oldConversationInfo)
- : new ConversationInfo.Builder();
+ : new ConversationInfo.Builder().setCreationTimestamp(System.currentTimeMillis());
builder.setShortcutId(shortcutInfo.getId());
builder.setLocusId(shortcutInfo.getLocusId());
@@ -1326,7 +1336,8 @@ public class DataManager {
}
}
- private void updateConversationStoreThenNotifyListeners(ConversationStore cs,
+ @VisibleForTesting
+ void updateConversationStoreThenNotifyListeners(ConversationStore cs,
ConversationInfo modifiedConv,
String packageName, int userId) {
cs.addOrUpdate(modifiedConv);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/FaceServiceRegistryTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/FaceServiceRegistryTest.java
deleted file mode 100644
index 8cd58abcdf0f..000000000000
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/FaceServiceRegistryTest.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.biometrics.sensors.face;
-
-import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
-import static android.hardware.biometrics.BiometricManager.Authenticators.BIOMETRIC_STRONG;
-import static android.hardware.biometrics.BiometricManager.Authenticators.BIOMETRIC_WEAK;
-import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG;
-import static android.hardware.biometrics.SensorProperties.STRENGTH_WEAK;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.hardware.biometrics.IBiometricService;
-import android.hardware.face.FaceSensorProperties;
-import android.hardware.face.FaceSensorPropertiesInternal;
-import android.hardware.face.IFaceAuthenticatorsRegisteredCallback;
-import android.hardware.face.IFaceService;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@Presubmit
-@SmallTest
-public class FaceServiceRegistryTest {
-
- private static final int SENSOR_ID_1 = 1;
- private static final int SENSOR_ID_2 = 2;
-
- @Rule
- public final MockitoRule mockito = MockitoJUnit.rule();
-
- @Mock
- private IBiometricService mBiometricService;
- @Mock
- private IFaceService mFaceService;
- @Mock
- private ServiceProvider mProvider1;
- @Mock
- private ServiceProvider mProvider2;
- @Captor
- private ArgumentCaptor<Integer> mIdCaptor;
- @Captor
- private ArgumentCaptor<Integer> mStrengthCaptor;
-
- private FaceSensorPropertiesInternal mProvider1Props;
- private FaceSensorPropertiesInternal mProvider2Props;
- private FaceServiceRegistry mRegistry;
-
- @Before
- public void setup() {
- mProvider1Props = new FaceSensorPropertiesInternal(SENSOR_ID_1,
- STRENGTH_WEAK, 5 /* maxEnrollmentsPerUser */,
- List.of(), FaceSensorProperties.TYPE_RGB,
- true /* supportsFace Detection */,
- true /* supportsSelfIllumination */,
- false /* resetLockoutRequiresHardwareAuthToken */);
- mProvider2Props = new FaceSensorPropertiesInternal(SENSOR_ID_2,
- STRENGTH_STRONG, 5 /* maxEnrollmentsPerUser */,
- List.of(), FaceSensorProperties.TYPE_IR,
- true /* supportsFace Detection */,
- true /* supportsSelfIllumination */,
- false /* resetLockoutRequiresHardwareAuthToken */);
-
- when(mProvider1.getSensorProperties()).thenReturn(List.of(mProvider1Props));
- when(mProvider1.containsSensor(eq(SENSOR_ID_1))).thenReturn(true);
- when(mProvider2.getSensorProperties()).thenReturn(List.of(mProvider2Props));
- when(mProvider2.containsSensor(eq(SENSOR_ID_2))).thenReturn(true);
- mRegistry = new FaceServiceRegistry(mFaceService, () -> mBiometricService);
- }
-
- @Test
- public void registersAllProviders() throws Exception {
- mRegistry.registerAllInBackground(() -> List.of(mProvider1, mProvider2));
-
- assertThat(mRegistry.getProviders()).containsExactly(mProvider1, mProvider2);
- assertThat(mRegistry.getAllProperties()).containsExactly(mProvider1Props, mProvider2Props);
- verify(mBiometricService, times(2)).registerAuthenticator(
- mIdCaptor.capture(), eq(TYPE_FACE), mStrengthCaptor.capture(), any());
- assertThat(mIdCaptor.getAllValues()).containsExactly(SENSOR_ID_1, SENSOR_ID_2);
- assertThat(mStrengthCaptor.getAllValues())
- .containsExactly(BIOMETRIC_WEAK, BIOMETRIC_STRONG);
- }
-
- @Test
- public void getsProviderById() {
- mRegistry.registerAllInBackground(() -> List.of(mProvider1, mProvider2));
-
- assertThat(mRegistry.getProviderForSensor(SENSOR_ID_1)).isSameInstanceAs(mProvider1);
- assertThat(mRegistry.getProviderForSensor(SENSOR_ID_2)).isSameInstanceAs(mProvider2);
- assertThat(mRegistry.getProviderForSensor(500)).isNull();
- }
-
- @Test
- public void getsSingleProvider() {
- mRegistry.registerAllInBackground(() -> List.of(mProvider1));
-
- assertThat(mRegistry.getSingleProvider().second).isSameInstanceAs(mProvider1);
- assertThat(mRegistry.getProviders()).containsExactly(mProvider1);
- assertThat(mRegistry.getProviderForSensor(SENSOR_ID_1)).isSameInstanceAs(mProvider1);
- }
-
- @Test
- public void registersListenerBeforeAllRegistered() {
- final List<FaceSensorPropertiesInternal> all = new ArrayList<>();
- mRegistry.addAllRegisteredCallback(new IFaceAuthenticatorsRegisteredCallback.Stub() {
- @Override
- public void onAllAuthenticatorsRegistered(
- List<FaceSensorPropertiesInternal> sensors) {
- all.addAll(sensors);
- }
- });
-
- mRegistry.registerAllInBackground(() -> List.of(mProvider1, mProvider2));
-
- assertThat(all).containsExactly(mProvider1Props, mProvider2Props);
- }
-
- @Test
- public void registersListenerAfterAllRegistered() {
- mRegistry.registerAllInBackground(() -> List.of(mProvider1, mProvider2));
-
- final List<FaceSensorPropertiesInternal> all = new ArrayList<>();
- mRegistry.addAllRegisteredCallback(new IFaceAuthenticatorsRegisteredCallback.Stub() {
- @Override
- public void onAllAuthenticatorsRegistered(
- List<FaceSensorPropertiesInternal> sensors) {
- all.addAll(sensors);
- }
- });
-
- assertThat(all).containsExactly(mProvider1Props, mProvider2Props);
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/BiometricStateCallbackTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/BiometricStateCallbackTest.java
index 0e30782eaece..5f88c99b1d1e 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/BiometricStateCallbackTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/BiometricStateCallbackTest.java
@@ -16,8 +16,6 @@
package com.android.server.biometrics.sensors.fingerprint;
-import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG;
-
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -26,70 +24,35 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.content.pm.UserInfo;
import android.hardware.biometrics.BiometricStateListener;
-import android.hardware.biometrics.SensorPropertiesInternal;
-import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
import com.android.server.biometrics.sensors.AuthenticationClient;
-import com.android.server.biometrics.sensors.BiometricServiceProvider;
import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.EnrollClient;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-import java.util.List;
+import org.mockito.MockitoAnnotations;
@Presubmit
@SmallTest
public class BiometricStateCallbackTest {
- private static final int USER_ID = 10;
- private static final int SENSOR_ID = 2;
-
- @Rule
- public final MockitoRule mockito = MockitoJUnit.rule();
-
- private BiometricStateCallback<FakeProvider, SensorPropertiesInternal> mCallback;
+ private BiometricStateCallback mCallback;
@Mock
- private UserManager mUserManager;
- @Mock
- private BiometricStateListener mBiometricStateListener;
- @Mock
- private FakeProvider mFakeProvider;
-
- private SensorPropertiesInternal mFakeProviderProps;
+ BiometricStateListener mBiometricStateListener;
@Before
public void setup() {
- mFakeProviderProps = new SensorPropertiesInternal(SENSOR_ID, STRENGTH_STRONG,
- 5 /* maxEnrollmentsPerUser */, List.of(),
- false /* resetLockoutRequiresHardwareAuthToken */,
- false /* resetLockoutRequiresChallenge */);
- when(mFakeProvider.getSensorProperties()).thenReturn(List.of(mFakeProviderProps));
- when(mFakeProvider.getSensorProperties(eq(SENSOR_ID))).thenReturn(mFakeProviderProps);
- when(mFakeProvider.hasEnrollments(eq(SENSOR_ID), eq(USER_ID))).thenReturn(true);
- when(mUserManager.getAliveUsers()).thenReturn(
- List.of(new UserInfo(USER_ID, "name", 0)));
-
- mCallback = new BiometricStateCallback<>(mUserManager);
- mCallback.registerBiometricStateListener(mBiometricStateListener);
- }
-
- @Test
- public void startNotifiesEnrollments() {
- mCallback.start(List.of(mFakeProvider));
+ MockitoAnnotations.initMocks(this);
- verify(mBiometricStateListener).onEnrollmentsChanged(eq(USER_ID), eq(SENSOR_ID), eq(true));
+ mCallback = new BiometricStateCallback();
+ mCallback.registerBiometricStateListener(mBiometricStateListener);
}
@Test
@@ -139,6 +102,4 @@ public class BiometricStateCallbackTest {
verify(mBiometricStateListener, never()).onEnrollmentsChanged(anyInt(), anyInt(),
anyBoolean());
}
-
- private interface FakeProvider extends BiometricServiceProvider<SensorPropertiesInternal> {}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceRegistryTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceRegistryTest.java
deleted file mode 100644
index 67d94a8f02d8..000000000000
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceRegistryTest.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.biometrics.sensors.fingerprint;
-
-import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
-import static android.hardware.biometrics.BiometricManager.Authenticators.BIOMETRIC_STRONG;
-import static android.hardware.biometrics.BiometricManager.Authenticators.BIOMETRIC_WEAK;
-import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG;
-import static android.hardware.biometrics.SensorProperties.STRENGTH_WEAK;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.hardware.biometrics.IBiometricService;
-import android.hardware.fingerprint.FingerprintSensorProperties;
-import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
-import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
-import android.hardware.fingerprint.IFingerprintService;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@Presubmit
-@SmallTest
-public class FingerprintServiceRegistryTest {
-
- private static final int SENSOR_ID_1 = 1;
- private static final int SENSOR_ID_2 = 2;
-
- @Rule
- public final MockitoRule mockito = MockitoJUnit.rule();
-
- @Mock
- private IBiometricService mBiometricService;
- @Mock
- private IFingerprintService mFingerprintService;
- @Mock
- private ServiceProvider mProvider1;
- @Mock
- private ServiceProvider mProvider2;
- @Captor
- private ArgumentCaptor<Integer> mIdCaptor;
- @Captor
- private ArgumentCaptor<Integer> mStrengthCaptor;
-
- private FingerprintSensorPropertiesInternal mProvider1Props;
- private FingerprintSensorPropertiesInternal mProvider2Props;
- private FingerprintServiceRegistry mRegistry;
-
- @Before
- public void setup() {
- mProvider1Props = new FingerprintSensorPropertiesInternal(SENSOR_ID_1,
- STRENGTH_WEAK, 5 /* maxEnrollmentsPerUser */,
- List.of(), FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
- false /* resetLockoutRequiresHardwareAuthToken */);
- mProvider2Props = new FingerprintSensorPropertiesInternal(SENSOR_ID_2,
- STRENGTH_STRONG, 5 /* maxEnrollmentsPerUser */,
- List.of(), FingerprintSensorProperties.TYPE_UNKNOWN,
- false /* resetLockoutRequiresHardwareAuthToken */);
-
- when(mProvider1.getSensorProperties()).thenReturn(List.of(mProvider1Props));
- when(mProvider1.containsSensor(eq(SENSOR_ID_1))).thenReturn(true);
- when(mProvider2.getSensorProperties()).thenReturn(List.of(mProvider2Props));
- when(mProvider2.containsSensor(eq(SENSOR_ID_2))).thenReturn(true);
- mRegistry = new FingerprintServiceRegistry(mFingerprintService, () -> mBiometricService);
- }
-
- @Test
- public void registersAllProviders() throws Exception {
- mRegistry.registerAllInBackground(() -> List.of(mProvider1, mProvider2));
-
- assertThat(mRegistry.getProviders()).containsExactly(mProvider1, mProvider2);
- assertThat(mRegistry.getAllProperties()).containsExactly(mProvider1Props, mProvider2Props);
- verify(mBiometricService, times(2)).registerAuthenticator(
- mIdCaptor.capture(), eq(TYPE_FINGERPRINT), mStrengthCaptor.capture(), any());
- assertThat(mIdCaptor.getAllValues()).containsExactly(SENSOR_ID_1, SENSOR_ID_2);
- assertThat(mStrengthCaptor.getAllValues())
- .containsExactly(BIOMETRIC_WEAK, BIOMETRIC_STRONG);
- }
-
- @Test
- public void getsProviderById() {
- mRegistry.registerAllInBackground(() -> List.of(mProvider1, mProvider2));
-
- assertThat(mRegistry.getProviderForSensor(SENSOR_ID_1)).isSameInstanceAs(mProvider1);
- assertThat(mRegistry.getProviderForSensor(SENSOR_ID_2)).isSameInstanceAs(mProvider2);
- assertThat(mRegistry.getProviderForSensor(500)).isNull();
- }
-
- @Test
- public void getsSingleProvider() {
- mRegistry.registerAllInBackground(() -> List.of(mProvider1));
-
- assertThat(mRegistry.getSingleProvider().second).isSameInstanceAs(mProvider1);
- assertThat(mRegistry.getProviders()).containsExactly(mProvider1);
- assertThat(mRegistry.getProviderForSensor(SENSOR_ID_1)).isSameInstanceAs(mProvider1);
- }
-
- @Test
- public void registersListenerBeforeAllRegistered() {
- final List<FingerprintSensorPropertiesInternal> all = new ArrayList<>();
- mRegistry.addAllRegisteredCallback(new IFingerprintAuthenticatorsRegisteredCallback.Stub() {
- @Override
- public void onAllAuthenticatorsRegistered(
- List<FingerprintSensorPropertiesInternal> sensors) {
- all.addAll(sensors);
- }
- });
-
- mRegistry.registerAllInBackground(() -> List.of(mProvider1, mProvider2));
-
- assertThat(all).containsExactly(mProvider1Props, mProvider2Props);
- }
-
- @Test
- public void registersListenerAfterAllRegistered() {
- mRegistry.registerAllInBackground(() -> List.of(mProvider1, mProvider2));
-
- final List<FingerprintSensorPropertiesInternal> all = new ArrayList<>();
- mRegistry.addAllRegisteredCallback(new IFingerprintAuthenticatorsRegisteredCallback.Stub() {
- @Override
- public void onAllAuthenticatorsRegistered(
- List<FingerprintSensorPropertiesInternal> sensors) {
- all.addAll(sensors);
- }
- });
-
- assertThat(all).containsExactly(mProvider1Props, mProvider2Props);
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java
index a4048a27dfb5..ca3677e3b5ff 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java
@@ -32,8 +32,7 @@ import android.hardware.biometrics.fingerprint.FingerprintSensorType;
import android.hardware.biometrics.fingerprint.IFingerprint;
import android.hardware.biometrics.fingerprint.SensorLocation;
import android.hardware.biometrics.fingerprint.SensorProps;
-import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
-import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
+import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.provider.Settings;
import android.testing.TestableContext;
@@ -53,8 +52,6 @@ import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
@Presubmit
@SmallTest
@@ -97,12 +94,9 @@ public class FingerprintServiceTest {
mContext.getTestablePermissions().setPermission(
USE_BIOMETRIC_INTERNAL, PackageManager.PERMISSION_GRANTED);
- }
- private void initServiceWith(String... aidlInstances) {
mService = new FingerprintService(mContext, mBiometricContext,
() -> mIBiometricService,
- () -> aidlInstances,
(fqName) -> {
if (fqName.endsWith(NAME_DEFAULT)) return mIFingerprintDefault;
if (fqName.endsWith(NAME_VIRTUAL)) return mIFingerprintVirtual;
@@ -111,50 +105,29 @@ public class FingerprintServiceTest {
}
@Test
- public void registerAuthenticators_defaultOnly() throws Exception {
- initServiceWith(NAME_DEFAULT, NAME_VIRTUAL);
-
- mService.mServiceWrapper.registerAuthenticators(List.of());
- waitForRegistration();
+ public void registerAuthenticators_defaultOnly() throws RemoteException {
+ mService.registerAuthenticatorsForService(List.of(NAME_DEFAULT, NAME_VIRTUAL), List.of());
verify(mIBiometricService).registerAuthenticator(eq(ID_DEFAULT), anyInt(), anyInt(), any());
}
@Test
- public void registerAuthenticators_virtualOnly() throws Exception {
- initServiceWith(NAME_DEFAULT, NAME_VIRTUAL);
+ public void registerAuthenticators_virtualOnly() throws RemoteException {
Settings.Secure.putInt(mSettingsRule.mockContentResolver(mContext),
Settings.Secure.BIOMETRIC_VIRTUAL_ENABLED, 1);
- mService.mServiceWrapper.registerAuthenticators(List.of());
- waitForRegistration();
+ mService.registerAuthenticatorsForService(List.of(NAME_DEFAULT, NAME_VIRTUAL), List.of());
verify(mIBiometricService).registerAuthenticator(eq(ID_VIRTUAL), anyInt(), anyInt(), any());
}
@Test
- public void registerAuthenticators_virtualAlwaysWhenNoOther() throws Exception {
- initServiceWith(NAME_VIRTUAL);
-
- mService.mServiceWrapper.registerAuthenticators(List.of());
- waitForRegistration();
+ public void registerAuthenticators_virtualAlwaysWhenNoOther() throws RemoteException {
+ mService.registerAuthenticatorsForService(List.of(NAME_VIRTUAL), List.of());
verify(mIBiometricService).registerAuthenticator(eq(ID_VIRTUAL), anyInt(), anyInt(), any());
}
- private void waitForRegistration() throws Exception {
- final CountDownLatch latch = new CountDownLatch(1);
- mService.mServiceWrapper.addAuthenticatorsRegisteredCallback(
- new IFingerprintAuthenticatorsRegisteredCallback.Stub() {
- @Override
- public void onAllAuthenticatorsRegistered(
- List<FingerprintSensorPropertiesInternal> sensors) {
- latch.countDown();
- }
- });
- latch.await(5, TimeUnit.SECONDS);
- }
-
private static SensorProps createProps(int id, byte strength, byte type) {
final SensorProps props = new SensorProps();
props.commonProps = new CommonProps();
diff --git a/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java b/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java
index 8139310a4c3d..c90064eaa810 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java
@@ -58,6 +58,7 @@ public final class ConversationInfoTest {
.setNotificationChannelId(NOTIFICATION_CHANNEL_ID)
.setParentNotificationChannelId(PARENT_NOTIFICATION_CHANNEL_ID)
.setLastEventTimestamp(100L)
+ .setCreationTimestamp(200L)
.setShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED
| ShortcutInfo.FLAG_CACHED_NOTIFICATIONS)
.setImportant(true)
@@ -79,6 +80,7 @@ public final class ConversationInfoTest {
assertEquals(PARENT_NOTIFICATION_CHANNEL_ID,
conversationInfo.getParentNotificationChannelId());
assertEquals(100L, conversationInfo.getLastEventTimestamp());
+ assertEquals(200L, conversationInfo.getCreationTimestamp());
assertTrue(conversationInfo.isShortcutLongLived());
assertTrue(conversationInfo.isShortcutCachedForNotification());
assertTrue(conversationInfo.isImportant());
@@ -105,6 +107,7 @@ public final class ConversationInfoTest {
assertNull(conversationInfo.getNotificationChannelId());
assertNull(conversationInfo.getParentNotificationChannelId());
assertEquals(0L, conversationInfo.getLastEventTimestamp());
+ assertEquals(0L, conversationInfo.getCreationTimestamp());
assertFalse(conversationInfo.isShortcutLongLived());
assertFalse(conversationInfo.isShortcutCachedForNotification());
assertFalse(conversationInfo.isImportant());
@@ -131,6 +134,7 @@ public final class ConversationInfoTest {
.setNotificationChannelId(NOTIFICATION_CHANNEL_ID)
.setParentNotificationChannelId(PARENT_NOTIFICATION_CHANNEL_ID)
.setLastEventTimestamp(100L)
+ .setCreationTimestamp(200L)
.setShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED)
.setImportant(true)
.setNotificationSilenced(true)
@@ -154,6 +158,7 @@ public final class ConversationInfoTest {
assertEquals(NOTIFICATION_CHANNEL_ID, destination.getNotificationChannelId());
assertEquals(PARENT_NOTIFICATION_CHANNEL_ID, destination.getParentNotificationChannelId());
assertEquals(100L, destination.getLastEventTimestamp());
+ assertEquals(200L, destination.getCreationTimestamp());
assertTrue(destination.isShortcutLongLived());
assertFalse(destination.isImportant());
assertTrue(destination.isNotificationSilenced());
@@ -164,4 +169,105 @@ public final class ConversationInfoTest {
assertThat(destination.getStatuses()).contains(cs);
assertThat(destination.getStatuses()).contains(cs2);
}
+
+ @Test
+ public void testBuildFromAnotherConversation_identicalConversation() {
+ ConversationStatus cs = new ConversationStatus.Builder("id", ACTIVITY_ANNIVERSARY).build();
+ ConversationStatus cs2 = new ConversationStatus.Builder("id2", ACTIVITY_GAME).build();
+
+ ConversationInfo source = new ConversationInfo.Builder()
+ .setShortcutId(SHORTCUT_ID)
+ .setLocusId(LOCUS_ID)
+ .setContactUri(CONTACT_URI)
+ .setContactPhoneNumber(PHONE_NUMBER)
+ .setNotificationChannelId(NOTIFICATION_CHANNEL_ID)
+ .setParentNotificationChannelId(PARENT_NOTIFICATION_CHANNEL_ID)
+ .setLastEventTimestamp(100L)
+ .setCreationTimestamp(200L)
+ .setShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED)
+ .setImportant(true)
+ .setNotificationSilenced(true)
+ .setBubbled(true)
+ .setPersonImportant(true)
+ .setPersonBot(true)
+ .setContactStarred(true)
+ .addOrUpdateStatus(cs)
+ .addOrUpdateStatus(cs2)
+ .build();
+
+ ConversationInfo destination = new ConversationInfo.Builder(source).build();
+
+ assertEquals(SHORTCUT_ID, destination.getShortcutId());
+ assertEquals(LOCUS_ID, destination.getLocusId());
+ assertEquals(CONTACT_URI, destination.getContactUri());
+ assertEquals(PHONE_NUMBER, destination.getContactPhoneNumber());
+ assertEquals(NOTIFICATION_CHANNEL_ID, destination.getNotificationChannelId());
+ assertEquals(PARENT_NOTIFICATION_CHANNEL_ID, destination.getParentNotificationChannelId());
+ assertEquals(100L, destination.getLastEventTimestamp());
+ assertEquals(200L, destination.getCreationTimestamp());
+ assertTrue(destination.isShortcutLongLived());
+ assertTrue(destination.isImportant());
+ assertTrue(destination.isNotificationSilenced());
+ assertTrue(destination.isBubbled());
+ assertTrue(destination.isPersonImportant());
+ assertTrue(destination.isPersonBot());
+ assertTrue(destination.isContactStarred());
+ assertThat(destination.getStatuses()).contains(cs);
+ assertThat(destination.getStatuses()).contains(cs2);
+ // Also check equals() implementation
+ assertTrue(source.equals(destination));
+ assertTrue(destination.equals(source));
+ }
+
+ @Test
+ public void testBuildFromBackupPayload() {
+ ConversationStatus cs = new ConversationStatus.Builder("id", ACTIVITY_ANNIVERSARY).build();
+ ConversationStatus cs2 = new ConversationStatus.Builder("id2", ACTIVITY_GAME).build();
+
+ ConversationInfo conversationInfo = new ConversationInfo.Builder()
+ .setShortcutId(SHORTCUT_ID)
+ .setLocusId(LOCUS_ID)
+ .setContactUri(CONTACT_URI)
+ .setContactPhoneNumber(PHONE_NUMBER)
+ .setNotificationChannelId(NOTIFICATION_CHANNEL_ID)
+ .setParentNotificationChannelId(PARENT_NOTIFICATION_CHANNEL_ID)
+ .setLastEventTimestamp(100L)
+ .setCreationTimestamp(200L)
+ .setShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED
+ | ShortcutInfo.FLAG_CACHED_NOTIFICATIONS)
+ .setImportant(true)
+ .setNotificationSilenced(true)
+ .setBubbled(true)
+ .setDemoted(true)
+ .setPersonImportant(true)
+ .setPersonBot(true)
+ .setContactStarred(true)
+ .addOrUpdateStatus(cs)
+ .addOrUpdateStatus(cs2)
+ .build();
+
+ ConversationInfo conversationInfoFromBackup =
+ ConversationInfo.readFromBackupPayload(conversationInfo.getBackupPayload());
+
+ assertEquals(SHORTCUT_ID, conversationInfoFromBackup.getShortcutId());
+ assertEquals(LOCUS_ID, conversationInfoFromBackup.getLocusId());
+ assertEquals(CONTACT_URI, conversationInfoFromBackup.getContactUri());
+ assertEquals(PHONE_NUMBER, conversationInfoFromBackup.getContactPhoneNumber());
+ assertEquals(
+ NOTIFICATION_CHANNEL_ID, conversationInfoFromBackup.getNotificationChannelId());
+ assertEquals(PARENT_NOTIFICATION_CHANNEL_ID,
+ conversationInfoFromBackup.getParentNotificationChannelId());
+ assertEquals(100L, conversationInfoFromBackup.getLastEventTimestamp());
+ assertEquals(200L, conversationInfoFromBackup.getCreationTimestamp());
+ assertTrue(conversationInfoFromBackup.isShortcutLongLived());
+ assertTrue(conversationInfoFromBackup.isShortcutCachedForNotification());
+ assertTrue(conversationInfoFromBackup.isImportant());
+ assertTrue(conversationInfoFromBackup.isNotificationSilenced());
+ assertTrue(conversationInfoFromBackup.isBubbled());
+ assertTrue(conversationInfoFromBackup.isDemoted());
+ assertTrue(conversationInfoFromBackup.isPersonImportant());
+ assertTrue(conversationInfoFromBackup.isPersonBot());
+ assertTrue(conversationInfoFromBackup.isContactStarred());
+ // ConversationStatus is a transient object and not persisted
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index 2a4896a7b041..66c3f0730404 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -291,7 +291,8 @@ public final class DataManagerTest {
mShortcutChangeCallbackCaptor.capture());
mShortcutChangeCallback = mShortcutChangeCallbackCaptor.getValue();
- verify(mContext, times(2)).registerReceiver(any(), any());
+ verify(mContext, times(1)).registerReceiver(any(), any());
+ verify(mContext, times(1)).registerReceiver(any(), any(), anyInt());
}
@After
@@ -1163,6 +1164,76 @@ public final class DataManagerTest {
}
@Test
+ public void testUncacheOldestCachedShortcut_missingNotificationEvents() {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+ for (int i = 0; i < DataManager.MAX_CACHED_RECENT_SHORTCUTS + 1; i++) {
+ String shortcutId = TEST_SHORTCUT_ID + i;
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, shortcutId,
+ buildPerson());
+ shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+ mShortcutChangeCallback.onShortcutsAddedOrUpdated(
+ TEST_PKG_NAME,
+ Collections.singletonList(shortcut),
+ UserHandle.of(USER_ID_PRIMARY));
+ mLooper.dispatchAll();
+ }
+
+ // Only the shortcut #0 is uncached, all the others are not.
+ verify(mShortcutServiceInternal).uncacheShortcuts(
+ anyInt(), any(), eq(TEST_PKG_NAME),
+ eq(Collections.singletonList(TEST_SHORTCUT_ID + 0)), eq(USER_ID_PRIMARY),
+ eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
+ for (int i = 1; i < DataManager.MAX_CACHED_RECENT_SHORTCUTS + 1; i++) {
+ verify(mShortcutServiceInternal, never()).uncacheShortcuts(
+ anyInt(), anyString(), anyString(),
+ eq(Collections.singletonList(TEST_SHORTCUT_ID + i)), anyInt(),
+ eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
+ }
+ }
+
+ @Test
+ public void testUncacheOldestCachedShortcut_legacyConversation() {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+ // Add an extra conversation with a legacy type (no creationTime)
+ ConversationStore conversationStore = mDataManager
+ .getUserDataForTesting(USER_ID_PRIMARY)
+ .getOrCreatePackageData(TEST_PKG_NAME)
+ .getConversationStore();
+ ConversationInfo.Builder builder = new ConversationInfo.Builder();
+ builder.setShortcutId(TEST_SHORTCUT_ID + 0);
+ builder.setShortcutFlags(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+ mDataManager.updateConversationStoreThenNotifyListeners(
+ conversationStore,
+ builder.build(),
+ TEST_PKG_NAME, USER_ID_PRIMARY);
+ for (int i = 1; i < DataManager.MAX_CACHED_RECENT_SHORTCUTS + 1; i++) {
+ String shortcutId = TEST_SHORTCUT_ID + i;
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, shortcutId,
+ buildPerson());
+ shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+ mShortcutChangeCallback.onShortcutsAddedOrUpdated(
+ TEST_PKG_NAME,
+ Collections.singletonList(shortcut),
+ UserHandle.of(USER_ID_PRIMARY));
+ mLooper.dispatchAll();
+ }
+
+ // Only the shortcut #0 is uncached, all the others are not.
+ verify(mShortcutServiceInternal).uncacheShortcuts(
+ anyInt(), any(), eq(TEST_PKG_NAME),
+ eq(Collections.singletonList(TEST_SHORTCUT_ID + 0)), eq(USER_ID_PRIMARY),
+ eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
+ for (int i = 1; i < DataManager.MAX_CACHED_RECENT_SHORTCUTS + 1; i++) {
+ verify(mShortcutServiceInternal, never()).uncacheShortcuts(
+ anyInt(), anyString(), anyString(),
+ eq(Collections.singletonList(TEST_SHORTCUT_ID + i)), anyInt(),
+ eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
+ }
+ }
+
+ @Test
public void testBackupAndRestoration()
throws IntentFilter.MalformedMimeTypeException {
mDataManager.onUserUnlocked(USER_ID_PRIMARY);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
index 8ac729e29424..c7905a0e8056 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
@@ -8,7 +8,7 @@
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distriZenbuted on an "AS IS" BASIS,
+ * 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.
@@ -397,10 +397,10 @@ public class ZenModeFilteringTest extends UiServiceTestCase {
Bundle inputWrong = makeExtrasBundleWithPeople(new String[]{"mailto:nope"});
assertTrue(ZenModeFiltering.matchesCallFilter(mContext, ZEN_MODE_IMPORTANT_INTERRUPTIONS,
policy, UserHandle.SYSTEM,
- inputMatches, null, 0, 0));
+ inputMatches, null, 0, 0, 0));
assertFalse(ZenModeFiltering.matchesCallFilter(mContext, ZEN_MODE_IMPORTANT_INTERRUPTIONS,
policy, UserHandle.SYSTEM,
- inputWrong, null, 0, 0));
+ inputWrong, null, 0, 0, 0));
}
@Test
@@ -428,19 +428,19 @@ public class ZenModeFilteringTest extends UiServiceTestCase {
assertTrue("identical numbers should match",
ZenModeFiltering.matchesCallFilter(mContext, ZEN_MODE_IMPORTANT_INTERRUPTIONS,
policy, UserHandle.SYSTEM,
- identical, null, 0, 0));
+ identical, null, 0, 0, 0));
assertTrue("equivalent but non-identical numbers should match",
ZenModeFiltering.matchesCallFilter(mContext, ZEN_MODE_IMPORTANT_INTERRUPTIONS,
policy, UserHandle.SYSTEM,
- same, null, 0, 0));
+ same, null, 0, 0, 0));
assertFalse("non-equivalent numbers should not match",
ZenModeFiltering.matchesCallFilter(mContext, ZEN_MODE_IMPORTANT_INTERRUPTIONS,
policy, UserHandle.SYSTEM,
- different, null, 0, 0));
+ different, null, 0, 0, 0));
assertFalse("non-tel strings should not match",
ZenModeFiltering.matchesCallFilter(mContext, ZEN_MODE_IMPORTANT_INTERRUPTIONS,
policy, UserHandle.SYSTEM,
- garbage, null, 0, 0));
+ garbage, null, 0, 0, 0));
}
@Test
@@ -469,23 +469,23 @@ public class ZenModeFilteringTest extends UiServiceTestCase {
assertTrue("same number 1 should match",
ZenModeFiltering.matchesCallFilter(mContext, ZEN_MODE_IMPORTANT_INTERRUPTIONS,
policy, UserHandle.SYSTEM,
- same1, null, 0, 0));
+ same1, null, 0, 0, 0));
assertTrue("same number 2 should match",
ZenModeFiltering.matchesCallFilter(mContext, ZEN_MODE_IMPORTANT_INTERRUPTIONS,
policy, UserHandle.SYSTEM,
- same2, null, 0, 0));
+ same2, null, 0, 0, 0));
assertTrue("same number 3 should match",
ZenModeFiltering.matchesCallFilter(mContext, ZEN_MODE_IMPORTANT_INTERRUPTIONS,
policy, UserHandle.SYSTEM,
- same3, null, 0, 0));
+ same3, null, 0, 0, 0));
assertFalse("different number 1 should not match",
ZenModeFiltering.matchesCallFilter(mContext, ZEN_MODE_IMPORTANT_INTERRUPTIONS,
policy, UserHandle.SYSTEM,
- different1, null, 0, 0));
+ different1, null, 0, 0, 0));
assertFalse("different number 2 should not match",
ZenModeFiltering.matchesCallFilter(mContext, ZEN_MODE_IMPORTANT_INTERRUPTIONS,
policy, UserHandle.SYSTEM,
- different2, null, 0, 0));
+ different2, null, 0, 0, 0));
}
@Test
@@ -516,14 +516,14 @@ public class ZenModeFilteringTest extends UiServiceTestCase {
assertTrue("contact number 1 should match",
ZenModeFiltering.matchesCallFilter(mContext, ZEN_MODE_IMPORTANT_INTERRUPTIONS,
policy, UserHandle.SYSTEM,
- tel1, null, 0, 0));
+ tel1, null, 0, 0, 0));
assertTrue("contact number 2 should match",
ZenModeFiltering.matchesCallFilter(mContext, ZEN_MODE_IMPORTANT_INTERRUPTIONS,
policy, UserHandle.SYSTEM,
- tel2, null, 0, 0));
+ tel2, null, 0, 0, 0));
assertFalse("different number should not match",
ZenModeFiltering.matchesCallFilter(mContext, ZEN_MODE_IMPORTANT_INTERRUPTIONS,
policy, UserHandle.SYSTEM,
- different, null, 0, 0));
+ different, null, 0, 0, 0));
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 05cc0cf14081..46b4b76dc12f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -24,6 +24,7 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
@@ -41,6 +42,7 @@ import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -52,16 +54,20 @@ import static org.mockito.Mockito.when;
import android.graphics.Rect;
import android.os.Binder;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
+import android.util.MergedConfiguration;
import android.view.IWindowSessionCallback;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.InsetsVisibilities;
+import android.view.SurfaceControl;
import android.view.View;
import android.view.WindowManager;
+import android.window.ClientWindowFrames;
import android.window.WindowContainerToken;
import androidx.test.filters.SmallTest;
@@ -166,6 +172,32 @@ public class WindowManagerServiceTests extends WindowTestsBase {
}
@Test
+ public void testRelayoutExitingWindow() {
+ final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, "appWin");
+ final WindowSurfaceController surfaceController = mock(WindowSurfaceController.class);
+ doReturn(true).when(surfaceController).hasSurface();
+ spyOn(win);
+ doReturn(true).when(win).isExitAnimationRunningSelfOrParent();
+ win.mWinAnimator.mSurfaceController = surfaceController;
+ win.mViewVisibility = View.VISIBLE;
+ win.mHasSurface = true;
+ win.mActivityRecord.mAppStopped = true;
+ win.mActivityRecord.mVisibleRequested = false;
+ win.mActivityRecord.setVisible(false);
+ mWm.mWindowMap.put(win.mClient.asBinder(), win);
+ final int w = 100;
+ final int h = 200;
+ mWm.relayoutWindow(win.mSession, win.mClient, win.mAttrs, w, h, View.GONE, 0, 0, 0,
+ new ClientWindowFrames(), new MergedConfiguration(), new SurfaceControl(),
+ new InsetsState(), new InsetsSourceControl[0], new Bundle());
+ // Because the window is already invisible, it doesn't need to apply exiting animation
+ // and WMS#tryStartExitingAnimation() will destroy the surface directly.
+ assertFalse(win.mAnimatingExit);
+ assertFalse(win.mHasSurface);
+ assertNull(win.mWinAnimator.mSurfaceController);
+ }
+
+ @Test
public void testMoveWindowTokenToDisplay_NullToken_DoNothing() {
mWm.moveWindowTokenToDisplay(null, mDisplayContent.getDisplayId());
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 5ad4edf71075..4af8cde4364c 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1175,14 +1175,55 @@ public class CarrierConfigManager {
"carrier_data_call_permanent_failure_strings";
/**
- * Default APN types that are metered by the carrier
- * @hide
+ * A string array indicating the default APN types that are metered by the carrier.
+ *
+ * The string in the array is the name of the APN type. For example, "default" for
+ * {@link ApnSetting#TYPE_DEFAULT}, "mms" for {@link ApnSetting#TYPE_MMS}, etc.
+ *
+ * The default value is {@code {"default", "mms", "dun", "supl"}}.
+ *
+ * @see ApnSetting#TYPE_DEFAULT
+ * @see ApnSetting#TYPE_MMS
+ * @see ApnSetting#TYPE_SUPL
+ * @see ApnSetting#TYPE_DUN
+ * @see ApnSetting#TYPE_HIPRI
+ * @see ApnSetting#TYPE_FOTA
+ * @see ApnSetting#TYPE_IMS
+ * @see ApnSetting#TYPE_CBS
+ * @see ApnSetting#TYPE_IA
+ * @see ApnSetting#TYPE_EMERGENCY
+ * @see ApnSetting#TYPE_MCX
+ * @see ApnSetting#TYPE_XCAP
+ * @see ApnSetting#TYPE_BIP
+ * @see ApnSetting#TYPE_VSIM
+ * @see ApnSetting#TYPE_ENTERPRISE
*/
public static final String KEY_CARRIER_METERED_APN_TYPES_STRINGS =
"carrier_metered_apn_types_strings";
+
/**
- * Default APN types that are roaming-metered by the carrier
- * @hide
+ * A string array indicating the default APN types that are roaming-metered by the carrier.
+ *
+ * The string in the array is the name of the APN type. For example, "default" for
+ * {@link ApnSetting#TYPE_DEFAULT}, "mms" for {@link ApnSetting#TYPE_MMS}, etc.
+ *
+ * The default value is {@code {"default", "mms", "dun", "supl"}}.
+ *
+ * @see ApnSetting#TYPE_DEFAULT
+ * @see ApnSetting#TYPE_MMS
+ * @see ApnSetting#TYPE_SUPL
+ * @see ApnSetting#TYPE_DUN
+ * @see ApnSetting#TYPE_HIPRI
+ * @see ApnSetting#TYPE_FOTA
+ * @see ApnSetting#TYPE_IMS
+ * @see ApnSetting#TYPE_CBS
+ * @see ApnSetting#TYPE_IA
+ * @see ApnSetting#TYPE_EMERGENCY
+ * @see ApnSetting#TYPE_MCX
+ * @see ApnSetting#TYPE_XCAP
+ * @see ApnSetting#TYPE_BIP
+ * @see ApnSetting#TYPE_VSIM
+ * @see ApnSetting#TYPE_ENTERPRISE
*/
public static final String KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS =
"carrier_metered_roaming_apn_types_strings";
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index d5b4434a136c..c9a63c654a40 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -16444,7 +16444,12 @@ public class TelephonyManager {
* the appropriate callback method on the callback object and passes the current (updated)
* values.
* <p>
- *
+ * Note: Be aware of the permission requirements stated on the {@link TelephonyCallback}
+ * listeners you implement. Your application must be granted these permissions in order to
+ * register a {@link TelephonyCallback} which requires them; a {@link SecurityException} will be
+ * thrown if you do not hold the required permissions for all {@link TelephonyCallback}
+ * listeners you implement.
+ * <p>
* If this TelephonyManager object has been created with {@link #createForSubscriptionId},
* applies to the given subId. Otherwise, applies to
* {@link SubscriptionManager#getDefaultSubscriptionId()}. To register events for multiple