Merge "Remove sleep_timeout setting from backup"
diff --git a/Android.bp b/Android.bp
index 4d2e5e1..db0f0ea 100644
--- a/Android.bp
+++ b/Android.bp
@@ -104,6 +104,7 @@
"core/java/android/app/timedetector/ITimeDetectorService.aidl",
"core/java/android/app/timezone/ICallback.aidl",
"core/java/android/app/timezone/IRulesManager.aidl",
+ "core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl",
"core/java/android/app/usage/ICacheQuotaService.aidl",
"core/java/android/app/usage/IStorageStatsManager.aidl",
"core/java/android/app/usage/IUsageStatsManager.aidl",
@@ -148,12 +149,14 @@
"core/java/android/hardware/IConsumerIrService.aidl",
"core/java/android/hardware/ISerialManager.aidl",
"core/java/android/hardware/biometrics/IBiometricPromptReceiver.aidl",
+ "core/java/android/hardware/biometrics/IBiometricServiceLockoutResetCallback.aidl",
"core/java/android/hardware/display/IDisplayManager.aidl",
"core/java/android/hardware/display/IDisplayManagerCallback.aidl",
"core/java/android/hardware/display/IVirtualDisplayCallback.aidl",
"core/java/android/hardware/fingerprint/IFingerprintClientActiveCallback.aidl",
+ "core/java/android/hardware/face/IFaceService.aidl",
+ "core/java/android/hardware/face/IFaceServiceReceiver.aidl",
"core/java/android/hardware/fingerprint/IFingerprintService.aidl",
- "core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl",
"core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl",
"core/java/android/hardware/hdmi/IHdmiControlCallback.aidl",
"core/java/android/hardware/hdmi/IHdmiControlService.aidl",
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java
index dfbabeb..a283e06 100644
--- a/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java
@@ -47,8 +47,7 @@
public void testCreateRenderNodeNoName() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
- RenderNode node = RenderNode.create(null, null);
- node.destroy();
+ RenderNode.create(null, null);
}
}
@@ -56,8 +55,7 @@
public void testCreateRenderNode() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
- RenderNode node = RenderNode.create("LinearLayout", null);
- node.destroy();
+ RenderNode.create("LinearLayout", null);
}
}
diff --git a/api/current.txt b/api/current.txt
index 41211f6..20e62c0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10137,6 +10137,7 @@
field public static final int FLAG_ACTIVITY_SINGLE_TOP = 536870912; // 0x20000000
field public static final int FLAG_ACTIVITY_TASK_ON_HOME = 16384; // 0x4000
field public static final int FLAG_DEBUG_LOG_RESOLUTION = 8; // 0x8
+ field public static final int FLAG_DIRECT_BOOT_AUTO = 256; // 0x100
field public static final int FLAG_EXCLUDE_STOPPED_PACKAGES = 16; // 0x10
field public static final int FLAG_FROM_BACKGROUND = 4; // 0x4
field public static final int FLAG_GRANT_PERSISTABLE_URI_PERMISSION = 64; // 0x40
@@ -11388,6 +11389,7 @@
field public static final int INSTALL_REASON_USER = 4; // 0x4
field public static final int MATCH_ALL = 131072; // 0x20000
field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
+ field public static final int MATCH_DIRECT_BOOT_AUTO = 268435456; // 0x10000000
field public static final int MATCH_DIRECT_BOOT_AWARE = 524288; // 0x80000
field public static final int MATCH_DIRECT_BOOT_UNAWARE = 262144; // 0x40000
field public static final int MATCH_DISABLED_COMPONENTS = 512; // 0x200
@@ -33207,6 +33209,7 @@
method public android.os.StrictMode.VmPolicy.Builder detectCleartextNetwork();
method public android.os.StrictMode.VmPolicy.Builder detectContentUriWithoutPermission();
method public android.os.StrictMode.VmPolicy.Builder detectFileUriExposure();
+ method public android.os.StrictMode.VmPolicy.Builder detectImplicitDirectBoot();
method public android.os.StrictMode.VmPolicy.Builder detectLeakedClosableObjects();
method public android.os.StrictMode.VmPolicy.Builder detectLeakedRegistrationObjects();
method public android.os.StrictMode.VmPolicy.Builder detectLeakedSqlLiteObjects();
@@ -33620,6 +33623,9 @@
public final class FileUriExposedViolation extends android.os.strictmode.Violation {
}
+ public final class ImplicitDirectBootViolation extends android.os.strictmode.Violation {
+ }
+
public class InstanceCountViolation extends android.os.strictmode.Violation {
method public long getNumberOfInstances();
}
@@ -70166,7 +70172,7 @@
public final class Pattern implements java.io.Serializable {
method public java.util.function.Predicate<java.lang.String> asPredicate();
method public static java.util.regex.Pattern compile(java.lang.String);
- method public static java.util.regex.Pattern compile(java.lang.String, int) throws java.util.regex.PatternSyntaxException;
+ method public static java.util.regex.Pattern compile(java.lang.String, int);
method public int flags();
method public java.util.regex.Matcher matcher(java.lang.CharSequence);
method public static boolean matches(java.lang.String, java.lang.CharSequence);
diff --git a/api/system-current.txt b/api/system-current.txt
index 143b46d4..049a9d2 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1202,6 +1202,9 @@
}
public class PermissionGroupInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
+ field public int backgroundRequestDetailResourceId;
+ field public int backgroundRequestResourceId;
+ field public int requestDetailResourceId;
field public int requestRes;
}
@@ -1209,6 +1212,7 @@
field public static final int FLAG_REMOVED = 2; // 0x2
field public static final int PROTECTION_FLAG_OEM = 16384; // 0x4000
field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
+ field public java.lang.String backgroundPermission;
field public int requestRes;
}
@@ -3923,6 +3927,7 @@
method public void readFromParcel(android.os.Parcel);
method public int sectionCount();
method public void setAll(boolean);
+ method public void setPrivacyPolicy(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.os.IncidentReportArgs> CREATOR;
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 6e3c768..b08ae0e 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -276,6 +276,7 @@
public class PermissionInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
field public static final int PROTECTION_FLAG_VENDOR_PRIVILEGED = 32768; // 0x8000
+ field public java.lang.String backgroundPermission;
}
public final class ShortcutInfo implements android.os.Parcelable {
@@ -654,6 +655,7 @@
method public void readFromParcel(android.os.Parcel);
method public int sectionCount();
method public void setAll(boolean);
+ method public void setPrivacyPolicy(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.os.IncidentReportArgs> CREATOR;
}
@@ -681,22 +683,6 @@
public final class StrictMode {
method public static void setViolationLogger(android.os.StrictMode.ViolationLogger);
- field public static final int DETECT_CUSTOM = 8; // 0x8
- field public static final int DETECT_DISK_READ = 2; // 0x2
- field public static final int DETECT_DISK_WRITE = 1; // 0x1
- field public static final int DETECT_NETWORK = 4; // 0x4
- field public static final int DETECT_RESOURCE_MISMATCH = 16; // 0x10
- field public static final int DETECT_UNBUFFERED_IO = 32; // 0x20
- field public static final int DETECT_VM_ACTIVITY_LEAKS = 1024; // 0x400
- field public static final int DETECT_VM_CLEARTEXT_NETWORK = 16384; // 0x4000
- field public static final int DETECT_VM_CLOSABLE_LEAKS = 512; // 0x200
- field public static final int DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION = 32768; // 0x8000
- field public static final int DETECT_VM_CURSOR_LEAKS = 256; // 0x100
- field public static final int DETECT_VM_FILE_URI_EXPOSURE = 8192; // 0x2000
- field public static final int DETECT_VM_INSTANCE_LEAKS = 2048; // 0x800
- field public static final int DETECT_VM_NON_SDK_API_USAGE = 1073741824; // 0x40000000
- field public static final int DETECT_VM_REGISTRATION_LEAKS = 4096; // 0x1000
- field public static final int DETECT_VM_UNTAGGED_SOCKET = -2147483648; // 0x80000000
}
public static final class StrictMode.ViolationInfo implements android.os.Parcelable {
@@ -704,9 +690,8 @@
ctor public StrictMode.ViolationInfo(android.os.Parcel, boolean);
method public int describeContents();
method public void dump(android.util.Printer, java.lang.String);
- method public int getPolicyMask();
method public java.lang.String getStackTrace();
- method public int getViolationBit();
+ method public java.lang.Class<? extends android.os.strictmode.Violation> getViolationClass();
method public java.lang.String getViolationDetails();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.os.StrictMode.ViolationInfo> CREATOR;
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk
index 453fb72..6943dab 100644
--- a/cmds/bootanimation/Android.mk
+++ b/cmds/bootanimation/Android.mk
@@ -27,7 +27,9 @@
LOCAL_SHARED_LIBRARIES += \
libandroidthings \
+ libandroidthings_protos \
libchrome \
+ libprotobuf-cpp-lite \
LOCAL_STATIC_LIBRARIES += \
libjsoncpp
diff --git a/cmds/bootanimation/iot/Android.mk b/cmds/bootanimation/iot/Android.mk
index 8b475d3..3d288e4 100644
--- a/cmds/bootanimation/iot/Android.mk
+++ b/cmds/bootanimation/iot/Android.mk
@@ -25,9 +25,11 @@
LOCAL_SHARED_LIBRARIES := \
libandroidthings \
+ libandroidthings_protos \
libbase \
libchrome \
liblog \
+ libprotobuf-cpp-lite \
LOCAL_STATIC_LIBRARIES += \
libjsoncpp
diff --git a/cmds/bootanimation/iot/BootParameters.cpp b/cmds/bootanimation/iot/BootParameters.cpp
index 2cf1c19..30a9b28 100644
--- a/cmds/bootanimation/iot/BootParameters.cpp
+++ b/cmds/bootanimation/iot/BootParameters.cpp
@@ -22,10 +22,13 @@
#include <fcntl.h>
#include <android-base/file.h>
+#include <json/json.h>
#include <utils/Log.h>
using android::base::ReadFileToString;
using android::base::RemoveFileIfExists;
+using android::base::WriteStringToFile;
+using Json::ArrayIndex;
using Json::Reader;
using Json::Value;
@@ -33,23 +36,34 @@
namespace {
-// Keys for supporting a silent boot and user-defined BootAction parameters.
-constexpr const char *kKeySilentBoot = "silent_boot";
-constexpr const char* kKeyParams = "params";
+// Keys for deprecated parameters. Devices that OTA from N to O and that used
+// the hidden BootParameters API will store these in the JSON blob. To support
+// the transition from N to O, these keys are mapped to the new parameters.
+constexpr const char *kKeyLegacyVolume = "volume";
+constexpr const char *kKeyLegacyAnimationsDisabled = "boot_animation_disabled";
+constexpr const char *kKeyLegacyParamNames = "param_names";
+constexpr const char *kKeyLegacyParamValues = "param_values";
-constexpr const char* kNextBootFile = "/data/misc/bootanimation/next_boot.json";
-constexpr const char* kLastBootFile = "/data/misc/bootanimation/last_boot.json";
+constexpr const char *kNextBootFile = "/data/misc/bootanimation/next_boot.proto";
+constexpr const char *kLastBootFile = "/data/misc/bootanimation/last_boot.proto";
-void swapBootConfigs() {
- // rename() will fail if next_boot.json doesn't exist, so delete
- // last_boot.json manually first.
+constexpr const char *kLegacyNextBootFile = "/data/misc/bootanimation/next_boot.json";
+constexpr const char *kLegacyLastBootFile = "/data/misc/bootanimation/last_boot.json";
+
+void removeLegacyFiles() {
std::string err;
- if (!RemoveFileIfExists(kLastBootFile, &err))
- ALOGE("Unable to delete last boot file: %s", err.c_str());
+ if (!RemoveFileIfExists(kLegacyLastBootFile, &err)) {
+ ALOGW("Unable to delete %s: %s", kLegacyLastBootFile, err.c_str());
+ }
- if (rename(kNextBootFile, kLastBootFile) && errno != ENOENT)
- ALOGE("Unable to swap boot files: %s", strerror(errno));
+ err.clear();
+ if (!RemoveFileIfExists(kLegacyNextBootFile, &err)) {
+ ALOGW("Unable to delete %s: %s", kLegacyNextBootFile, err.c_str());
+ }
+}
+void createNextBootFile() {
+ errno = 0;
int fd = open(kNextBootFile, O_CREAT, DEFFILEMODE);
if (fd == -1) {
ALOGE("Unable to create next boot file: %s", strerror(errno));
@@ -64,54 +78,120 @@
} // namespace
+// Renames the 'next' boot file to the 'last' file and reads its contents.
+bool BootParameters::swapAndLoadBootConfigContents(const char *lastBootFile,
+ const char *nextBootFile,
+ std::string *contents) {
+ if (!ReadFileToString(nextBootFile, contents)) {
+ RemoveFileIfExists(lastBootFile);
+ return false;
+ }
+
+ errno = 0;
+ if (rename(nextBootFile, lastBootFile) && errno != ENOENT)
+ ALOGE("Unable to swap boot files: %s", strerror(errno));
+
+ return true;
+}
+
BootParameters::BootParameters() {
- swapBootConfigs();
loadParameters();
}
-void BootParameters::loadParameters() {
- std::string contents;
- if (!ReadFileToString(kLastBootFile, &contents)) {
- if (errno != ENOENT)
- ALOGE("Unable to read from %s: %s", kLastBootFile, strerror(errno));
+// Saves the boot parameters state to disk so the framework can read it.
+void BootParameters::storeParameters() {
+ errno = 0;
+ if (!WriteStringToFile(mProto.SerializeAsString(), kLastBootFile)) {
+ ALOGE("Failed to write boot parameters to %s: %s", kLastBootFile, strerror(errno));
+ }
+ // WriteStringToFile sets the file permissions to 0666, but these are not
+ // honored by the system.
+ errno = 0;
+ if (chmod(kLastBootFile, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) {
+ ALOGE("Failed to set permissions for %s: %s", kLastBootFile, strerror(errno));
+ }
+}
+
+// Load the boot parameters from disk, try the old location and format if the
+// file does not exist. Note:
+// - Parse errors result in defaults being used (a normal boot).
+// - Legacy boot parameters default to a silent boot.
+void BootParameters::loadParameters() {
+ // Precedence is given to the new file format (.proto).
+ std::string contents;
+ if (swapAndLoadBootConfigContents(kLastBootFile, kNextBootFile, &contents)) {
+ parseBootParameters(contents);
+ } else if (swapAndLoadBootConfigContents(kLegacyLastBootFile, kLegacyNextBootFile, &contents)) {
+ parseLegacyBootParameters(contents);
+ storeParameters();
+ removeLegacyFiles();
+ }
+
+ createNextBootFile();
+}
+
+void BootParameters::parseBootParameters(const std::string &contents) {
+ if (!mProto.ParseFromString(contents)) {
+ ALOGW("Failed to parse parameters from %s", kLastBootFile);
return;
}
- loadParameters(contents);
+ loadStateFromProto();
}
-// If the boot parameters -
-// - File is missing, we assume a normal, non-silent boot.
-// - Are well-formed, initially assume a normal, non-silent boot and parse.
-void BootParameters::loadParameters(const std::string& raw_json) {
- if (!Reader().parse(raw_json, mJson)) {
- return;
- }
-
- parseBootParameters();
-}
-
-void BootParameters::parseBootParameters() {
- // A missing key returns a safe, missing value.
- // Ignore invalid or missing JSON parameters.
- Value &jsonValue = mJson[kKeySilentBoot];
- if (jsonValue.isBool()) {
- mIsSilentBoot = jsonValue.asBool();
+// Parses the JSON in the proto.
+void BootParameters::parseLegacyBootParameters(const std::string &contents) {
+ Value json;
+ if (!Reader().parse(contents, json)) {
+ ALOGW("Failed to parse parameters from %s", kLegacyLastBootFile);
+ return;
}
- jsonValue = mJson[kKeyParams];
- if (jsonValue.isObject()) {
- // getMemberNames returns a copy of the keys which must be stored.
- mKeys = jsonValue.getMemberNames();
- for (auto &key : mKeys) {
- Value &value = jsonValue[key];
- if (value.isString()) {
- mParameters.push_back(
- {.key = key.c_str(), .value = value.asCString()});
+ int volume = 0;
+ bool bootAnimationDisabled = true;
+
+ Value &jsonValue = json[kKeyLegacyVolume];
+ if (jsonValue.isIntegral()) {
+ volume = jsonValue.asInt();
+ }
+
+ jsonValue = json[kKeyLegacyAnimationsDisabled];
+ if (jsonValue.isIntegral()) {
+ bootAnimationDisabled = jsonValue.asInt() == 1;
+ }
+
+ // Assume a silent boot unless all of the following are true -
+ // 1. The volume is neither 0 nor -1000 (the legacy default value).
+ // 2. The boot animations are explicitly enabled.
+ // Note: brightness was never used.
+ mProto.set_silent_boot((volume == 0) || (volume == -1000) || bootAnimationDisabled);
+
+ Value &keys = json[kKeyLegacyParamNames];
+ Value &values = json[kKeyLegacyParamValues];
+ if (keys.isArray() && values.isArray() && (keys.size() == values.size())) {
+ for (ArrayIndex i = 0; i < keys.size(); ++i) {
+ auto &key = keys[i];
+ auto &value = values[i];
+ if (key.isString() && value.isString()) {
+ auto userParameter = mProto.add_user_parameter();
+ userParameter->set_key(key.asString());
+ userParameter->set_value(value.asString());
}
}
}
+
+ loadStateFromProto();
+}
+
+void BootParameters::loadStateFromProto() {
+ // A missing key returns a safe, default value.
+ // Ignore invalid or missing parameters.
+ mIsSilentBoot = mProto.silent_boot();
+
+ for (const auto ¶m : mProto.user_parameter()) {
+ mParameters.push_back({.key = param.key().c_str(), .value = param.value().c_str()});
+ }
}
} // namespace android
diff --git a/cmds/bootanimation/iot/BootParameters.h b/cmds/bootanimation/iot/BootParameters.h
index 49c34dd..cbd1ca6 100644
--- a/cmds/bootanimation/iot/BootParameters.h
+++ b/cmds/bootanimation/iot/BootParameters.h
@@ -22,7 +22,7 @@
#include <vector>
#include <boot_action/boot_action.h> // libandroidthings native API.
-#include <json/json.h>
+#include <boot_parameters.pb.h>
namespace android {
@@ -39,22 +39,33 @@
// Returns the additional boot parameters that were set on reboot.
const std::vector<ABootActionParameter>& getParameters() const { return mParameters; }
- // Exposed for testing. Updates the parameters with new JSON values.
- void loadParameters(const std::string& raw_json);
-private:
+ // Exposed for testing. Sets the parameters to the serialized proto.
+ void parseBootParameters(const std::string &contents);
+
+ // For devices that OTA from N to O.
+ // Exposed for testing. Sets the parameters to the raw JSON.
+ void parseLegacyBootParameters(const std::string &contents);
+
+ // Exposed for testing. Loads the contents from |nextBootFile| and replaces
+ // |lastBootFile| with |nextBootFile|.
+ static bool swapAndLoadBootConfigContents(const char *lastBootFile, const char *nextBootFile,
+ std::string *contents);
+
+ private:
void loadParameters();
- void parseBootParameters();
+ // Replaces the legacy JSON blob with the updated version, allowing the
+ // framework to read it.
+ void storeParameters();
+
+ void loadStateFromProto();
bool mIsSilentBoot = false;
std::vector<ABootActionParameter> mParameters;
- // Store parsed JSON because mParameters makes a shallow copy.
- Json::Value mJson;
-
- // Store parameter keys because mParameters makes a shallow copy.
- Json::Value::Members mKeys;
+ // Store the proto because mParameters makes a shallow copy.
+ android::things::proto::BootParameters mProto;
};
} // namespace android
diff --git a/cmds/bootanimation/iot/BootParameters_test.cpp b/cmds/bootanimation/iot/BootParameters_test.cpp
index 27d7d6f..d55bce6 100644
--- a/cmds/bootanimation/iot/BootParameters_test.cpp
+++ b/cmds/bootanimation/iot/BootParameters_test.cpp
@@ -16,6 +16,13 @@
#include "BootParameters.h"
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <android-base/file.h>
+#include <android-base/test_utils.h>
+#include <boot_parameters.pb.h>
#include <gtest/gtest.h>
namespace android {
@@ -23,50 +30,51 @@
namespace {
TEST(BootParametersTest, TestNoBootParametersIsNotSilent) {
- BootParameters boot_parameters = BootParameters();
- boot_parameters.loadParameters("");
+ android::things::proto::BootParameters proto;
- ASSERT_FALSE(boot_parameters.isSilentBoot());
- ASSERT_EQ(0u, boot_parameters.getParameters().size());
+ BootParameters bootParameters = BootParameters();
+ bootParameters.parseBootParameters(proto.SerializeAsString());
+
+ ASSERT_FALSE(bootParameters.isSilentBoot());
+ ASSERT_EQ(0u, bootParameters.getParameters().size());
}
TEST(BootParametersTest, TestParseIsSilent) {
- BootParameters boot_parameters = BootParameters();
- boot_parameters.loadParameters(R"(
- {
- "silent_boot":true,
- "params":{}
- }
- )");
+ android::things::proto::BootParameters proto;
+ proto.set_silent_boot(true);
- ASSERT_TRUE(boot_parameters.isSilentBoot());
+ BootParameters bootParameters = BootParameters();
+ bootParameters.parseBootParameters(proto.SerializeAsString());
+
+ ASSERT_TRUE(bootParameters.isSilentBoot());
}
TEST(BootParametersTest, TestParseIsNotSilent) {
- BootParameters boot_parameters = BootParameters();
- boot_parameters.loadParameters(R"(
- {
- "silent_boot":false,
- "params":{}
- }
- )");
+ android::things::proto::BootParameters proto;
+ proto.set_silent_boot(false);
- ASSERT_FALSE(boot_parameters.isSilentBoot());
+ BootParameters bootParameters = BootParameters();
+ bootParameters.parseBootParameters(proto.SerializeAsString());
+
+ ASSERT_FALSE(bootParameters.isSilentBoot());
}
TEST(BootParametersTest, TestParseBootParameters) {
- BootParameters boot_parameters = BootParameters();
- boot_parameters.loadParameters(R"(
- {
- "silent_boot":false,
- "params":{
- "key1":"value1",
- "key2":"value2"
- }
- }
- )");
+ android::things::proto::BootParameters proto;
+ proto.set_silent_boot(false);
- auto ¶meters = boot_parameters.getParameters();
+ auto userParameter = proto.add_user_parameter();
+ userParameter->set_key("key1");
+ userParameter->set_value("value1");
+
+ userParameter = proto.add_user_parameter();
+ userParameter->set_key("key2");
+ userParameter->set_value("value2");
+
+ BootParameters bootParameters = BootParameters();
+ bootParameters.parseBootParameters(proto.SerializeAsString());
+
+ auto ¶meters = bootParameters.getParameters();
ASSERT_EQ(2u, parameters.size());
ASSERT_STREQ(parameters[0].key, "key1");
ASSERT_STREQ(parameters[0].value, "value1");
@@ -74,35 +82,182 @@
ASSERT_STREQ(parameters[1].value, "value2");
}
-TEST(BootParametersTest, TestParseMissingParametersIsNotSilent) {
- BootParameters boot_parameters = BootParameters();
- boot_parameters.loadParameters(R"(
+TEST(BootParametersTest, TestParseLegacyDisableBootAnimationIsSilent) {
+ BootParameters bootParameters = BootParameters();
+ bootParameters.parseLegacyBootParameters(R"(
{
- "params":{}
+ "brightness":200,
+ "volume":100,
+ "boot_animation_disabled":1,
+ "param_names":[],
+ "param_values":[]
}
)");
- ASSERT_FALSE(boot_parameters.isSilentBoot());
+ ASSERT_TRUE(bootParameters.isSilentBoot());
}
-TEST(BootParametersTest, TestParseMalformedParametersAreSkipped) {
- BootParameters boot_parameters = BootParameters();
- boot_parameters.loadParameters(R"(
+TEST(BootParametersTest, TestParseLegacyZeroVolumeIsSilent) {
+ BootParameters bootParameters = BootParameters();
+ bootParameters.parseLegacyBootParameters(R"(
{
- "silent_boot":false,
- "params":{
- "key1":123,
- "key2":"value2"
- }
+ "brightness":200,
+ "volume":0,
+ "boot_animation_disabled":0,
+ "param_names":[],
+ "param_values":[]
}
)");
- auto ¶meters = boot_parameters.getParameters();
+ ASSERT_TRUE(bootParameters.isSilentBoot());
+}
+
+TEST(BootParametersTest, TestParseLegacyDefaultVolumeIsSilent) {
+ BootParameters bootParameters = BootParameters();
+ bootParameters.parseLegacyBootParameters(R"(
+ {
+ "brightness":200,
+ "volume":-1000,
+ "boot_animation_disabled":0,
+ "param_names":[],
+ "param_values":[]
+ }
+ )");
+
+ ASSERT_TRUE(bootParameters.isSilentBoot());
+}
+
+TEST(BootParametersTest, TestParseLegacyNotSilent) {
+ BootParameters bootParameters = BootParameters();
+ bootParameters.parseLegacyBootParameters(R"(
+ {
+ "brightness":200,
+ "volume":500,
+ "boot_animation_disabled":0,
+ "param_names":[],
+ "param_values":[]
+ }
+ )");
+
+ ASSERT_FALSE(bootParameters.isSilentBoot());
+}
+
+TEST(BootParametersTest, TestParseLegacyParameters) {
+ BootParameters bootParameters = BootParameters();
+ bootParameters.parseLegacyBootParameters(R"(
+ {
+ "brightness":200,
+ "volume":100,
+ "boot_animation_disabled":1,
+ "param_names":["key1", "key2"],
+ "param_values":["value1", "value2"]
+ }
+ )");
+
+ auto parameters = bootParameters.getParameters();
+ ASSERT_EQ(2u, parameters.size());
+ ASSERT_STREQ(parameters[0].key, "key1");
+ ASSERT_STREQ(parameters[0].value, "value1");
+ ASSERT_STREQ(parameters[1].key, "key2");
+ ASSERT_STREQ(parameters[1].value, "value2");
+}
+
+TEST(BootParametersTest, TestParseLegacyZeroParameters) {
+ BootParameters bootParameters = BootParameters();
+ bootParameters.parseLegacyBootParameters(R"(
+ {
+ "brightness":200,
+ "volume":100,
+ "boot_animation_disabled":1,
+ "param_names":[],
+ "param_values":[]
+ }
+ )");
+
+ ASSERT_EQ(0u, bootParameters.getParameters().size());
+}
+
+TEST(BootParametersTest, TestMalformedLegacyParametersAreSkipped) {
+ BootParameters bootParameters = BootParameters();
+ bootParameters.parseLegacyBootParameters(R"(
+ {
+ "brightness":500,
+ "volume":500,
+ "boot_animation_disabled":0,
+ "param_names":["key1", "key2"],
+ "param_values":[1, "value2"]
+ }
+ )");
+
+ auto parameters = bootParameters.getParameters();
ASSERT_EQ(1u, parameters.size());
ASSERT_STREQ(parameters[0].key, "key2");
ASSERT_STREQ(parameters[0].value, "value2");
}
+TEST(BootParametersTest, TestLegacyUnequalParameterSizesAreSkipped) {
+ BootParameters bootParameters = BootParameters();
+ bootParameters.parseLegacyBootParameters(R"(
+ {
+ "brightness":500,
+ "volume":500,
+ "boot_animation_disabled":0,
+ "param_names":["key1", "key2"],
+ "param_values":["value1"]
+ }
+ )");
+
+ ASSERT_EQ(0u, bootParameters.getParameters().size());
+}
+
+TEST(BootParametersTest, TestMissingLegacyBootParametersIsSilent) {
+ BootParameters bootParameters = BootParameters();
+ bootParameters.parseLegacyBootParameters(R"(
+ {
+ "brightness":500
+ }
+ )");
+
+ EXPECT_TRUE(bootParameters.isSilentBoot());
+ ASSERT_EQ(0u, bootParameters.getParameters().size());
+}
+
+TEST(BootParametersTest, TestLastFileIsRemovedOnError) {
+ TemporaryFile lastFile;
+ TemporaryDir tempDir;
+ std::string nonExistentFilePath(std::string(tempDir.path) + "/nonexistent");
+ std::string contents;
+
+ BootParameters::swapAndLoadBootConfigContents(lastFile.path, nonExistentFilePath.c_str(),
+ &contents);
+
+ struct stat buf;
+ ASSERT_EQ(-1, lstat(lastFile.path, &buf));
+ ASSERT_TRUE(contents.empty());
+}
+
+TEST(BootParametersTest, TestNextFileIsRemovedLastFileExistsOnSuccess) {
+ TemporaryFile lastFile;
+ TemporaryFile nextFile;
+
+ base::WriteStringToFile("foo", nextFile.path);
+
+ std::string contents;
+ // Expected side effects:
+ // - |next_file| is moved to |last_file|
+ // - |contents| is the contents of |next_file| before being moved.
+ BootParameters::swapAndLoadBootConfigContents(lastFile.path, nextFile.path, &contents);
+
+ struct stat buf;
+ ASSERT_EQ(0, lstat(lastFile.path, &buf));
+ ASSERT_EQ(-1, lstat(nextFile.path, &buf));
+ ASSERT_EQ(contents, "foo");
+
+ contents.clear();
+ ASSERT_TRUE(base::ReadFileToString(lastFile.path, &contents));
+ ASSERT_EQ(contents, "foo");
+}
+
} // namespace
} // namespace android
diff --git a/cmds/dpm/src/com/android/commands/dpm/Dpm.java b/cmds/dpm/src/com/android/commands/dpm/Dpm.java
index 7c1a555..376b13c 100644
--- a/cmds/dpm/src/com/android/commands/dpm/Dpm.java
+++ b/cmds/dpm/src/com/android/commands/dpm/Dpm.java
@@ -46,6 +46,7 @@
private static final String COMMAND_SET_PROFILE_OWNER = "set-profile-owner";
private static final String COMMAND_REMOVE_ACTIVE_ADMIN = "remove-active-admin";
private static final String COMMAND_CLEAR_FREEZE_PERIOD_RECORD = "clear-freeze-period-record";
+ private static final String COMMAND_FORCE_NETWORK_LOGS = "force-network-logs";
private static final String COMMAND_FORCE_SECURITY_LOGS = "force-security-logs";
private IDevicePolicyManager mDevicePolicyManager;
@@ -84,6 +85,9 @@
"feature development to prevent triggering restriction on setting freeze " +
"periods.\n" +
"\n" +
+ "dpm " + COMMAND_FORCE_NETWORK_LOGS + ": makes all network logs available to " +
+ "the DPC and triggers DeviceAdminReceiver.onNetworkLogsAvailable() if needed.\n" +
+ "\n" +
"dpm " + COMMAND_FORCE_SECURITY_LOGS + ": makes all security logs available to " +
"the DPC and triggers DeviceAdminReceiver.onSecurityLogsAvailable() if needed.");
}
@@ -114,6 +118,9 @@
case COMMAND_CLEAR_FREEZE_PERIOD_RECORD:
runClearFreezePeriodRecord();
break;
+ case COMMAND_FORCE_NETWORK_LOGS:
+ runForceNetworkLogs();
+ break;
case COMMAND_FORCE_SECURITY_LOGS:
runForceSecurityLogs();
break;
@@ -122,6 +129,18 @@
}
}
+ private void runForceNetworkLogs() throws RemoteException, InterruptedException {
+ while (true) {
+ final long toWait = mDevicePolicyManager.forceNetworkLogs();
+ if (toWait == 0) {
+ break;
+ }
+ System.out.println("We have to wait for " + toWait + " milliseconds...");
+ Thread.sleep(toWait);
+ }
+ System.out.println("Success");
+ }
+
private void runForceSecurityLogs() throws RemoteException, InterruptedException {
while (true) {
final long toWait = mDevicePolicyManager.forceSecurityLogs();
diff --git a/cmds/incident_helper/src/main.cpp b/cmds/incident_helper/src/main.cpp
index 418dc3f..5b6ac7a 100644
--- a/cmds/incident_helper/src/main.cpp
+++ b/cmds/incident_helper/src/main.cpp
@@ -73,7 +73,8 @@
case 2006:
return new BatteryTypeParser();
default:
- return NULL;
+ // Return no op parser when no specific ones are implemented.
+ return new NoopParser();
}
}
diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp
index e305b54..e92cf94 100644
--- a/cmds/incidentd/src/IncidentService.cpp
+++ b/cmds/incidentd/src/IncidentService.cpp
@@ -314,6 +314,19 @@
mThrottler->dump(out);
return NO_ERROR;
}
+ if (!args[0].compare(String8("section"))) {
+ int id = atoi(args[1]);
+ int idx = 0;
+ while (SECTION_LIST[idx] != NULL) {
+ const Section* section = SECTION_LIST[idx];
+ if (section->id == id) {
+ fprintf(out, "Section[%d] %s\n", id, section->name.string());
+ break;
+ }
+ idx++;
+ }
+ return NO_ERROR;
+ }
}
return cmd_help(out);
}
@@ -321,8 +334,9 @@
status_t IncidentService::cmd_help(FILE* out) {
fprintf(out, "usage: adb shell cmd incident privacy print <section_id>\n");
fprintf(out, "usage: adb shell cmd incident privacy parse <section_id> < proto.txt\n");
- fprintf(out, " Prints/parses for the section id.\n");
- fprintf(out, "\n");
+ fprintf(out, " Prints/parses for the section id.\n\n");
+ fprintf(out, "usage: adb shell cmd incident section <section_id>\n");
+ fprintf(out, " Prints section id and its name.\n\n");
fprintf(out, "usage: adb shell cmd incident throttler\n");
fprintf(out, " Prints the current throttler state\n");
return NO_ERROR;
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 0b5e358..1c20bff 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -71,7 +71,7 @@
src/guardrail/StatsdStats.cpp \
src/socket/StatsSocketListener.cpp
-# TODO: Once statsd is using a blueprint file, migrate to the proper filegroups.
+# TODO(b/110563449): Once statsd is using a blueprint file, migrate to the proper filegroups.
statsd_common_src += \
../../../../system/extras/perfprofd/binder_interface/aidl/android/os/IPerfProfd.aidl \
src/perfprofd/perfprofd_config.proto
diff --git a/cmds/statsd/src/FieldValue.h b/cmds/statsd/src/FieldValue.h
index 02c49b9..b1d6ab3 100644
--- a/cmds/statsd/src/FieldValue.h
+++ b/cmds/statsd/src/FieldValue.h
@@ -212,7 +212,7 @@
* the result is equal to the Matcher Field. That's a bit wise AND operation + check if 2 ints are
* equal. Nothing can beat the performance of this matching algorithm.
*
- * TODO: ADD EXAMPLE HERE.
+ * TODO(b/110561213): ADD EXAMPLE HERE.
*/
struct Matcher {
Matcher(const Field& matcher, int32_t mask) : mMatcher(matcher), mMask(mask){};
diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp
index 7103034..af8b3af 100644
--- a/cmds/statsd/src/HashableDimensionKey.cpp
+++ b/cmds/statsd/src/HashableDimensionKey.cpp
@@ -65,8 +65,6 @@
for (const auto& value : values) {
for (size_t i = 0; i < matcherFields.size(); ++i) {
const auto& matcher = matcherFields[i];
- // TODO: potential optimization here to break early because all fields are naturally
- // sorted.
if (value.mField.matches(matcher)) {
output->addValue(value);
output->mutableValue(num_matches)->mField.setTag(value.mField.getTag());
@@ -196,4 +194,4 @@
} // namespace statsd
} // namespace os
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index ae44ee9..1119eb3 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -440,7 +440,6 @@
if (argCount == 2) {
// Automatically pick the UID
uid = IPCThreadState::self()->getCallingUid();
- // TODO: What if this isn't a binder call? Should we fail?
name.assign(args[1].c_str(), args[1].size());
good = true;
} else if (argCount == 3) {
@@ -493,7 +492,6 @@
if (argCount == 3) {
// Automatically pick the UID
uid = IPCThreadState::self()->getCallingUid();
- // TODO: What if this isn't a binder call? Should we fail?
name.assign(args[2].c_str(), args[2].size());
good = true;
} else if (argCount == 4) {
@@ -578,7 +576,6 @@
if (argCount == 2) {
// Automatically pick the UID
uid = IPCThreadState::self()->getCallingUid();
- // TODO: What if this isn't a binder call? Should we fail?
name.assign(args[1].c_str(), args[1].size());
good = true;
} else if (argCount == 3) {
@@ -604,7 +601,6 @@
vector<uint8_t> data;
mProcessor->onDumpReport(ConfigKey(uid, StrToInt64(name)), getElapsedRealtimeNs(),
false /* include_current_bucket*/, ADB_DUMP, &data);
- // TODO: print the returned StatsLogReport to file instead of printing to logcat.
if (proto) {
for (size_t i = 0; i < data.size(); i ++) {
fprintf(out, "%c", data[i]);
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 0a11f7c..ed90050 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -49,7 +49,6 @@
virtual ~StatsService();
/** The anomaly alarm registered with AlarmManager won't be updated by less than this. */
- // TODO: Consider making this configurable. And choose a good number.
const uint32_t MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS = 5;
virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
diff --git a/cmds/statsd/src/anomaly/AlarmMonitor.cpp b/cmds/statsd/src/anomaly/AlarmMonitor.cpp
index 78f0c2b..bc36dad 100644
--- a/cmds/statsd/src/anomaly/AlarmMonitor.cpp
+++ b/cmds/statsd/src/anomaly/AlarmMonitor.cpp
@@ -60,7 +60,7 @@
ALOGW("Asked to add a 0-time alarm.");
return;
}
- // TODO: Ensure that refractory period is respected.
+ // TODO(b/110563466): Ensure that refractory period is respected.
VLOG("Adding alarm with time %u", alarm->timestampSec);
mPq.push(alarm);
if (mRegisteredAlarmTimeSec < 1 ||
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index f32efee..ee111cd 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -208,7 +208,8 @@
}
void AnomalyTracker::declareAnomaly(const int64_t& timestampNs, const MetricDimensionKey& key) {
- // TODO: Why receive timestamp? RefractoryPeriod should always be based on real time right now.
+ // TODO(b/110563466): Why receive timestamp? RefractoryPeriod should always be based on
+ // real time right now.
if (isInRefractoryPeriod(timestampNs, key)) {
VLOG("Skipping anomaly declaration since within refractory period");
return;
@@ -216,7 +217,8 @@
if (mAlert.has_refractory_period_secs()) {
mRefractoryPeriodEndsSec[key] = ((timestampNs + NS_PER_SEC - 1) / NS_PER_SEC) // round up
+ mAlert.refractory_period_secs();
- // TODO: If we had access to the bucket_size_millis, consider calling resetStorage()
+ // TODO(b/110563466): If we had access to the bucket_size_millis, consider
+ // calling resetStorage()
// if (mAlert.refractory_period_secs() > mNumOfPastBuckets * bucketSizeNs) {resetStorage();}
}
@@ -230,7 +232,7 @@
StatsdStats::getInstance().noteAnomalyDeclared(mConfigKey, mAlert.id());
- // TODO: This should also take in the const MetricDimensionKey& key?
+ // TODO(b/110564268): This should also take in the const MetricDimensionKey& key?
android::util::stats_write(android::util::ANOMALY_DETECTED, mConfigKey.GetUid(),
mConfigKey.GetId(), mAlert.id());
}
diff --git a/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp b/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
index 3741202..ae97d7a 100644
--- a/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
+++ b/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
@@ -54,7 +54,7 @@
ResourceHealthManagerPuller::ResourceHealthManagerPuller(int tagId) : StatsPuller(tagId) {
}
-// TODO: add other health atoms (eg. Temperature).
+// TODO(b/110565992): add other health atoms (eg. Temperature).
bool ResourceHealthManagerPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
if (!getHealthHal()) {
ALOGE("Health Hal not loaded");
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index 764366f..038cb95 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -103,7 +103,6 @@
{android::util::CPU_TIME_PER_UID_FREQ, {6000, 10000}},
};
-// TODO: add stats for pulled atoms.
StatsdStats::StatsdStats() {
mPushedAtomStats.resize(android::util::kMaxPushedAtomId + 1);
mStartTimeSec = getWallClockSec();
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 74541d3..9fb2cd8 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -86,7 +86,6 @@
static StatsdStats& getInstance();
~StatsdStats(){};
- // TODO: set different limit if the device is low ram.
const static int kDimensionKeySizeSoftLimit = 500;
const static int kDimensionKeySizeHardLimit = 800;
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 4e4f146..04d34f3 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -273,7 +273,7 @@
}
int64_t LogEvent::GetLong(size_t key, status_t* err) const {
- // TODO: encapsulate the magical operations all in Field struct as a static function.
+ // TODO(b/110561208): encapsulate the magical operations in Field struct as static functions
int field = getSimpleField(key);
for (const auto& value : mValues) {
if (value.mField.getField() == field) {
diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp
index 6aa68da..2f15d0f 100644
--- a/cmds/statsd/src/main.cpp
+++ b/cmds/statsd/src/main.cpp
@@ -82,7 +82,6 @@
if (err != NO_ERROR) {
return err;
}
- // TODO: Do we need to tweak thread priority?
err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (err != NO_ERROR) {
pthread_attr_destroy(&attr);
diff --git a/cmds/statsd/src/matchers/LogMatchingTracker.h b/cmds/statsd/src/matchers/LogMatchingTracker.h
index 4f30a04..88ab4e6 100644
--- a/cmds/statsd/src/matchers/LogMatchingTracker.h
+++ b/cmds/statsd/src/matchers/LogMatchingTracker.h
@@ -86,8 +86,6 @@
// The collection of the event tag ids that this LogMatchingTracker cares. So we can quickly
// return kNotMatched when we receive an event with an id not in the list. This is especially
// useful when we have a complex CombinationLogMatcherTracker.
- // TODO: Consider use an array instead of stl set. In reality, the number of the tag ids a
- // LogMatchingTracker cares is only a few.
std::set<int> mAtomIds;
};
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 43f53e0..a894782 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -68,7 +68,6 @@
const sp<ConditionWizard>& wizard,
const int64_t startTimeNs)
: MetricProducer(metric.id(), key, startTimeNs, conditionIndex, wizard) {
- // TODO: evaluate initial conditions. and set mConditionMet.
if (metric.has_bucket()) {
mBucketSizeNs =
TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket()) * 1000000;
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index 139c083..520d5de 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -40,7 +40,6 @@
class CountMetricProducer : public MetricProducer {
public:
- // TODO: Pass in the start time from MetricsManager, it should be consistent for all metrics.
CountMetricProducer(const ConfigKey& key, const CountMetric& countMetric,
const int conditionIndex, const sp<ConditionWizard>& wizard,
const int64_t startTimeNs);
@@ -80,7 +79,6 @@
void flushCurrentBucketLocked(const int64_t& eventTimeNs) override;
- // TODO: Add a lock to mPastBuckets.
std::unordered_map<MetricDimensionKey, std::vector<CountBucket>> mPastBuckets;
// The current bucket (may be a partial bucket).
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 62237bc..a19eb0b 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -76,9 +76,6 @@
mStopAllIndex(stopAllIndex),
mNested(nesting),
mContainANYPositionInInternalDimensions(false) {
- // TODO: The following boiler plate code appears in all MetricProducers, but we can't abstract
- // them in the base class, because the proto generated CountMetric, and DurationMetric are
- // not related. Maybe we should add a template in the future??
if (metric.has_bucket()) {
mBucketSizeNs =
TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket()) * 1000000;
@@ -434,8 +431,6 @@
VLOG("Metric %lld onConditionChanged", (long long)mMetricId);
mCondition = conditionMet;
flushIfNeededLocked(eventTime);
- // TODO: need to populate the condition change time from the event which triggers the condition
- // change, instead of using current time.
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
for (auto& pair : whatIt.second) {
pair.second->onConditionChanged(conditionMet, eventTime);
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 88e455a..c496b12 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -115,7 +115,6 @@
ConditionState mUnSlicedPartCondition;
// Save the past buckets and we can clear when the StatsLogReport is dumped.
- // TODO: Add a lock to mPastBuckets.
std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>> mPastBuckets;
// The duration trackers in the current bucket.
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index 62d1105..7f7aa37 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -33,7 +33,6 @@
class EventMetricProducer : public MetricProducer {
public:
- // TODO: Pass in the start time from MetricsManager, it should be consistent for all metrics.
EventMetricProducer(const ConfigKey& key, const EventMetric& eventMetric,
const int conditionIndex, const sp<ConditionWizard>& wizard,
const int64_t startTimeNs);
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index d75bb10..a779410 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -101,7 +101,6 @@
translateFieldMatcher(metric.gauge_fields_filter().fields(), &mFieldMatchers);
}
- // TODO: use UidMap if uid->pkg_name is required
if (metric.has_dimensions_in_what()) {
translateFieldMatcher(metric.dimensions_in_what(), &mDimensionsInWhat);
mContainANYPositionInDimensionsInWhat = HasPositionANY(metric.dimensions_in_what());
@@ -299,7 +298,6 @@
protoOutput->end(protoToken);
mPastBuckets.clear();
- // TODO: Clear mDimensionKeyMap once the report is dumped.
}
void GaugeMetricProducer::pullLocked(const int64_t timestampNs) {
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index 62ec27eb..89b1f41 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -122,7 +122,6 @@
const int mPullTagId;
// Save the past buckets and we can clear when the StatsLogReport is dumped.
- // TODO: Add a lock to mPastBuckets.
std::unordered_map<MetricDimensionKey, std::vector<GaugeBucket>> mPastBuckets;
// The current partial bucket.
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 213f9ab..0e5ef4d 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -238,7 +238,6 @@
if (event.GetTagId() == android::util::APP_BREADCRUMB_REPORTED) {
// Check that app breadcrumb reported fields are valid.
- // TODO: Find a way to make these checks easier to maintain.
status_t err = NO_ERROR;
// Uid is 3rd from last field and must match the caller's uid,
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index ef8b6cc..f5e953a 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -89,7 +89,6 @@
? StatsdStats::kAtomDimensionKeySizeLimitMap.at(pullTagId).second
: StatsdStats::kDimensionKeySizeHardLimit),
mUseAbsoluteValueOnReset(metric.use_absolute_value_on_reset()) {
- // TODO: valuemetric for pushed events may need unlimited bucket length
int64_t bucketSizeMills = 0;
if (metric.has_bucket()) {
bucketSizeMills = TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket());
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 75f3113..943d6dc 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -144,7 +144,6 @@
std::unordered_map<MetricDimensionKey, int64_t> mCurrentFullBucket;
// Save the past buckets and we can clear when the StatsLogReport is dumped.
- // TODO: Add a lock to mPastBuckets.
std::unordered_map<MetricDimensionKey, std::vector<ValueBucket>> mPastBuckets;
// Pairs of (elapsed start, elapsed end) denoting buckets that were skipped.
diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
index 149b318..ccb1d43 100644
--- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
@@ -44,7 +44,6 @@
int64_t lastStartTime;
// existing duration in current bucket.
int64_t lastDuration;
- // TODO: Optimize the way we track sliced condition in duration metrics.
// cache the HashableDimensionKeys we need to query the condition for this duration event.
ConditionKey conditionKeys;
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
index b833dfc..956383a 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
@@ -326,7 +326,6 @@
int64_t OringDurationTracker::predictAnomalyTimestampNs(
const DurationAnomalyTracker& anomalyTracker, const int64_t eventTimestampNs) const {
- // TODO: Unit-test this and see if it can be done more efficiently (e.g. use int32).
// The anomaly threshold.
const int64_t thresholdNs = anomalyTracker.getAnomalyThreshold();
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index deb9893..e03edb3 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -103,7 +103,6 @@
}
allConditionTrackers[condition_it->second]->setSliced(true);
allConditionTrackers[it->second]->setSliced(true);
- // TODO: We need to verify the link is valid.
}
conditionIndex = condition_it->second;
@@ -169,7 +168,6 @@
bool isStateTracker(const SimplePredicate& simplePredicate, vector<Matcher>* primaryKeys) {
// 1. must not have "stop". must have "dimension"
if (!simplePredicate.has_stop() && simplePredicate.has_dimensions()) {
- // TODO: need to check the start atom matcher too.
auto it = android::util::AtomsInfo::kStateAtomsFieldOptions.find(
simplePredicate.dimensions().field());
// 2. must be based on a state atom.
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index 514eec7..91f2030 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -146,7 +146,6 @@
void getListenerListCopyLocked(std::vector<wp<PackageInfoListener>>* output);
- // TODO: Use shared_mutex for improved read-locking if a library can be found in Android.
mutable mutex mMutex;
mutable mutex mIsolatedMutex;
diff --git a/cmds/statsd/src/perfprofd/perfprofd_config.proto b/cmds/statsd/src/perfprofd/perfprofd_config.proto
index 2e3305f..c8be247 120000
--- a/cmds/statsd/src/perfprofd/perfprofd_config.proto
+++ b/cmds/statsd/src/perfprofd/perfprofd_config.proto
@@ -1 +1 @@
-../../../../../../system/extras/perfprofd/binder_interface/perfprofd_config.proto
\ No newline at end of file
+../../../../../../system/extras/perfprofd/perfprofd_config.proto
\ No newline at end of file
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index 1f81812..3ebc8a4 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -57,7 +57,7 @@
}
// When index ends before hitting 3, file name is corrupted. We
// intentionally put -1 at index 0 to indicate the error to caller.
- // TODO: consider removing files with unexpected name format.
+ // TODO(b/110563137): consider removing files with unexpected name format.
if (index < 3) {
result[0] = -1;
}
diff --git a/cmds/statsd/tests/FieldValue_test.cpp b/cmds/statsd/tests/FieldValue_test.cpp
index c253bc1..a9305ac 100644
--- a/cmds/statsd/tests/FieldValue_test.cpp
+++ b/cmds/statsd/tests/FieldValue_test.cpp
@@ -312,7 +312,8 @@
dim.addValue(FieldValue(field4, value4));
SubscriberReporter::getStatsDimensionsValue(dim);
- // TODO: can't test anything here because SubscriberReport class doesn't have any read api.
+ // TODO(b/110562792): can't test anything here because StatsDimensionsValue class doesn't
+ // have any read api.
}
TEST(AtomMatcherTest, TestWriteDimensionToProto) {
@@ -483,4 +484,4 @@
} // namespace android
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
\ No newline at end of file
+#endif
diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp
index 4de9986..8fbb58a 100644
--- a/cmds/statsd/tests/MetricsManager_test.cpp
+++ b/cmds/statsd/tests/MetricsManager_test.cpp
@@ -39,8 +39,6 @@
#ifdef __ANDROID__
-// TODO: ADD MORE TEST CASES.
-
const ConfigKey kConfigKey(0, 12345);
const long timeBaseSec = 1000;
diff --git a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
index 11aaab0..cc8894b 100644
--- a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
@@ -99,7 +99,6 @@
// If we want to test multiple dump data, we must do it in separate tests, because in the e2e tests,
// we should use the real API which will clear the data after dump data is called.
-// TODO: better refactor the code so that the tests are not so verbose.
TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks1) {
auto config = CreateStatsdConfig();
uint64_t bucketStartTimeNs = 10000000000;
diff --git a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
index 3a15466..d2fd95c 100644
--- a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
@@ -54,8 +54,8 @@
eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
- // TODO: get the report and check the content after the ProtoOutputStream change is done.
- // eventProducer.onDumpReport();
+ // TODO(b/110561136): get the report and check the content after the ProtoOutputStream change
+ // is done eventProducer.onDumpReport();
}
TEST(EventMetricProducerTest, TestEventsWithNonSlicedCondition) {
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index c7e72f9..19c9f77 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -59,8 +59,6 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- // TODO: pending refactor of StatsPullerManager
- // For now we still need this so that it doesn't do real pulling.
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index d93b46f..5195f01 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -60,8 +60,6 @@
metric.mutable_value_field()->add_child()->set_field(2);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- // TODO: pending refactor of StatsPullerManager
- // For now we still need this so that it doesn't do real pulling.
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index cc17ea8..0941d39 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -137,6 +137,7 @@
Landroid/app/ActivityManager$StackInfo;->visible:Z
Landroid/app/ActivityManager$TaskDescription;->getBackgroundColor()I
Landroid/app/ActivityManager$TaskDescription;->getInMemoryIcon()Landroid/graphics/Bitmap;
+Landroid/app/ActivityManager$TaskDescription;->setIcon(Landroid/graphics/Bitmap;)V
Landroid/app/ActivityManager$TaskSnapshot;->getContentInsets()Landroid/graphics/Rect;
Landroid/app/ActivityManager$TaskSnapshot;->getOrientation()I
Landroid/app/ActivityManager$TaskSnapshot;->getScale()F
@@ -1217,6 +1218,7 @@
Landroid/bluetooth/IBluetooth$Stub;-><init>()V
Landroid/bluetooth/IBluetooth$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetooth;
Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_enable:I
+Landroid/bluetooth/IBluetooth;->fetchRemoteUuids(Landroid/bluetooth/BluetoothDevice;)Z
Landroid/bluetooth/IBluetooth;->getAddress()Ljava/lang/String;
Landroid/bluetooth/IBluetooth;->getRemoteAlias(Landroid/bluetooth/BluetoothDevice;)Ljava/lang/String;
Landroid/bluetooth/IBluetooth;->isEnabled()Z
@@ -1491,6 +1493,7 @@
Landroid/content/pm/IPackageManager$Stub$Proxy;->getAppOpPermissionPackages(Ljava/lang/String;)[Ljava/lang/String;
Landroid/content/pm/IPackageManager$Stub$Proxy;->getInstalledPackages(II)Landroid/content/pm/ParceledListSlice;
Landroid/content/pm/IPackageManager$Stub$Proxy;->getInstallLocation()I
+Landroid/content/pm/IPackageManager$Stub$Proxy;->getLastChosenActivity(Landroid/content/Intent;Ljava/lang/String;I)Landroid/content/pm/ResolveInfo;
Landroid/content/pm/IPackageManager$Stub$Proxy;->getPackageInfo(Ljava/lang/String;II)Landroid/content/pm/PackageInfo;
Landroid/content/pm/IPackageManager$Stub$Proxy;->getPackagesForUid(I)[Ljava/lang/String;
Landroid/content/pm/IPackageManager$Stub$Proxy;->getSystemSharedLibraryNames()[Ljava/lang/String;
@@ -1721,6 +1724,7 @@
Landroid/content/pm/PackageParser;->collectCertificates(Landroid/content/pm/PackageParser$Package;Ljava/io/File;Z)V
Landroid/content/pm/PackageParser;->collectCertificates(Landroid/content/pm/PackageParser$Package;Z)V
Landroid/content/pm/PackageParser;->generateActivityInfo(Landroid/content/pm/PackageParser$Activity;ILandroid/content/pm/PackageUserState;I)Landroid/content/pm/ActivityInfo;
+Landroid/content/pm/PackageParser;->generateApplicationInfo(Landroid/content/pm/PackageParser$Package;ILandroid/content/pm/PackageUserState;)Landroid/content/pm/ApplicationInfo;
Landroid/content/pm/PackageParser;->generateApplicationInfo(Landroid/content/pm/PackageParser$Package;ILandroid/content/pm/PackageUserState;I)Landroid/content/pm/ApplicationInfo;
Landroid/content/pm/PackageParser;->generateInstrumentationInfo(Landroid/content/pm/PackageParser$Instrumentation;I)Landroid/content/pm/InstrumentationInfo;
Landroid/content/pm/PackageParser;->generatePackageInfo(Landroid/content/pm/PackageParser$Package;[IIJJLjava/util/Set;Landroid/content/pm/PackageUserState;)Landroid/content/pm/PackageInfo;
@@ -1732,6 +1736,7 @@
Landroid/content/pm/PackageParser;->mCallback:Landroid/content/pm/PackageParser$Callback;
Landroid/content/pm/PackageParser;->NEW_PERMISSIONS:[Landroid/content/pm/PackageParser$NewPermissionInfo;
Landroid/content/pm/PackageParser;->parseBaseApk(Ljava/lang/String;Landroid/content/res/Resources;Landroid/content/res/XmlResourceParser;I[Ljava/lang/String;)Landroid/content/pm/PackageParser$Package;
+Landroid/content/pm/PackageParser;->parseBaseApplication(Landroid/content/pm/PackageParser$Package;Landroid/content/res/Resources;Landroid/content/res/XmlResourceParser;I[Ljava/lang/String;)Z
Landroid/content/pm/PackageParser;->parseMonolithicPackage(Ljava/io/File;I)Landroid/content/pm/PackageParser$Package;
Landroid/content/pm/PackageParser;->parsePackage(Ljava/io/File;I)Landroid/content/pm/PackageParser$Package;
Landroid/content/pm/PackageParser;->parsePackage(Ljava/io/File;IZ)Landroid/content/pm/PackageParser$Package;
@@ -1815,6 +1820,7 @@
Landroid/content/res/AssetManager;->setConfiguration(IILjava/lang/String;IIIIIIIIIIIIIII)V
Landroid/content/res/AssetManager;->sSystem:Landroid/content/res/AssetManager;
Landroid/content/res/ColorStateList$ColorStateListFactory;-><init>(Landroid/content/res/ColorStateList;)V
+Landroid/content/res/ColorStateList;-><init>()V
Landroid/content/res/ColorStateList;->canApplyTheme()Z
Landroid/content/res/ColorStateList;->getColors()[I
Landroid/content/res/ColorStateList;->getStates()[[I
@@ -1877,6 +1883,7 @@
Landroid/content/res/Resources;->updateSystemConfiguration(Landroid/content/res/Configuration;Landroid/util/DisplayMetrics;Landroid/content/res/CompatibilityInfo;)V
Landroid/content/res/ResourcesImpl;-><init>(Landroid/content/res/AssetManager;Landroid/util/DisplayMetrics;Landroid/content/res/Configuration;Landroid/view/DisplayAdjustments;)V
Landroid/content/res/ResourcesImpl;->getAssets()Landroid/content/res/AssetManager;
+Landroid/content/res/ResourcesImpl;->getDisplayMetrics()Landroid/util/DisplayMetrics;
Landroid/content/res/ResourcesImpl;->getValue(ILandroid/util/TypedValue;Z)V
Landroid/content/res/ResourcesImpl;->mAccessLock:Ljava/lang/Object;
Landroid/content/res/ResourcesImpl;->mAnimatorCache:Landroid/content/res/ConfigurationBoundResourceCache;
@@ -2132,6 +2139,7 @@
Landroid/graphics/CanvasProperty;->createPaint(Landroid/graphics/Paint;)Landroid/graphics/CanvasProperty;
Landroid/graphics/ColorMatrixColorFilter;->mMatrix:Landroid/graphics/ColorMatrix;
Landroid/graphics/ColorMatrixColorFilter;->setColorMatrix(Landroid/graphics/ColorMatrix;)V
+Landroid/graphics/ColorMatrixColorFilter;->setColorMatrixArray([F)V
Landroid/graphics/drawable/AnimatedImageDrawable;->onAnimationEnd()V
Landroid/graphics/drawable/AnimatedRotateDrawable;->setFramesCount(I)V
Landroid/graphics/drawable/AnimatedRotateDrawable;->setFramesDuration(I)V
@@ -2485,8 +2493,6 @@
Landroid/hardware/display/WifiDisplayStatus;->mActiveDisplay:Landroid/hardware/display/WifiDisplay;
Landroid/hardware/display/WifiDisplayStatus;->mDisplays:[Landroid/hardware/display/WifiDisplay;
Landroid/hardware/display/WifiDisplayStatus;->SCAN_STATE_NOT_SCANNING:I
-Landroid/hardware/fingerprint/Fingerprint;->getFingerId()I
-Landroid/hardware/fingerprint/Fingerprint;->getName()Ljava/lang/CharSequence;
Landroid/hardware/fingerprint/FingerprintManager$AuthenticationResult;->getFingerprint()Landroid/hardware/fingerprint/Fingerprint;
Landroid/hardware/fingerprint/FingerprintManager;->getAuthenticatorId()J
Landroid/hardware/fingerprint/FingerprintManager;->getEnrolledFingerprints()Ljava/util/List;
@@ -4139,6 +4145,7 @@
Landroid/os/SELinux;->restoreconRecursive(Ljava/io/File;)Z
Landroid/os/ServiceManager;-><init>()V
Landroid/os/ServiceManager;->addService(Ljava/lang/String;Landroid/os/IBinder;)V
+Landroid/os/ServiceManager;->addService(Ljava/lang/String;Landroid/os/IBinder;Z)V
Landroid/os/ServiceManager;->addService(Ljava/lang/String;Landroid/os/IBinder;ZI)V
Landroid/os/ServiceManager;->checkService(Ljava/lang/String;)Landroid/os/IBinder;
Landroid/os/ServiceManager;->getIServiceManager()Landroid/os/IServiceManager;
@@ -4223,6 +4230,7 @@
Landroid/os/storage/VolumeInfo;->getDiskId()Ljava/lang/String;
Landroid/os/storage/VolumeInfo;->getEnvironmentForState(I)Ljava/lang/String;
Landroid/os/storage/VolumeInfo;->getFsUuid()Ljava/lang/String;
+Landroid/os/storage/VolumeInfo;->getInternalPath()Ljava/io/File;
Landroid/os/storage/VolumeInfo;->getInternalPathForUser(I)Ljava/io/File;
Landroid/os/storage/VolumeInfo;->getMountUserId()I
Landroid/os/storage/VolumeInfo;->getPath()Ljava/io/File;
@@ -4258,6 +4266,7 @@
Landroid/os/StrictMode;->sLastVmViolationTime:Ljava/util/HashMap;
Landroid/os/StrictMode;->sWindowManager:Landroid/util/Singleton;
Landroid/os/StrictMode;->violationsBeingTimed:Ljava/lang/ThreadLocal;
+Landroid/os/SystemClock;-><init>()V
Landroid/os/SystemClock;->currentThreadTimeMicro()J
Landroid/os/SystemClock;->currentTimeMicro()J
Landroid/os/SystemProperties;-><init>()V
@@ -4342,6 +4351,7 @@
Landroid/os/UserManager;->getUserStartRealtime()J
Landroid/os/UserManager;->getUserUnlockRealtime()J
Landroid/os/UserManager;->hasBaseUserRestriction(Ljava/lang/String;Landroid/os/UserHandle;)Z
+Landroid/os/UserManager;->isDeviceInDemoMode(Landroid/content/Context;)Z
Landroid/os/UserManager;->isGuestUser(I)Z
Landroid/os/UserManager;->isLinkedUser()Z
Landroid/os/UserManager;->isUserAdmin(I)Z
@@ -4547,6 +4557,7 @@
Landroid/provider/Settings$Global;->ZEN_MODE_IMPORTANT_INTERRUPTIONS:I
Landroid/provider/Settings$Global;->ZEN_MODE_NO_INTERRUPTIONS:I
Landroid/provider/Settings$Global;->ZEN_MODE_OFF:I
+Landroid/provider/Settings$NameValueCache;->getStringForUser(Landroid/content/ContentResolver;Ljava/lang/String;I)Ljava/lang/String;
Landroid/provider/Settings$NameValueCache;->mProviderHolder:Landroid/provider/Settings$ContentProviderHolder;
Landroid/provider/Settings$Secure;->ACCESSIBILITY_AUTOCLICK_ENABLED:Ljava/lang/String;
Landroid/provider/Settings$Secure;->ACCESSIBILITY_CAPTIONING_TYPEFACE:Ljava/lang/String;
@@ -4585,10 +4596,12 @@
Landroid/provider/Settings$Secure;->SETTINGS_TO_BACKUP:[Ljava/lang/String;
Landroid/provider/Settings$Secure;->SMS_DEFAULT_APPLICATION:Ljava/lang/String;
Landroid/provider/Settings$Secure;->sNameValueCache:Landroid/provider/Settings$NameValueCache;
+Landroid/provider/Settings$Secure;->sProviderHolder:Landroid/provider/Settings$ContentProviderHolder;
Landroid/provider/Settings$Secure;->VOICE_RECOGNITION_SERVICE:Ljava/lang/String;
Landroid/provider/Settings$System;->AIRPLANE_MODE_TOGGLEABLE_RADIOS:Ljava/lang/String;
Landroid/provider/Settings$System;->CAR_DOCK_SOUND:Ljava/lang/String;
Landroid/provider/Settings$System;->CAR_UNDOCK_SOUND:Ljava/lang/String;
+Landroid/provider/Settings$System;->CLONE_TO_MANAGED_PROFILE:Ljava/util/Set;
Landroid/provider/Settings$System;->DESK_DOCK_SOUND:Ljava/lang/String;
Landroid/provider/Settings$System;->DESK_UNDOCK_SOUND:Ljava/lang/String;
Landroid/provider/Settings$System;->DOCK_SOUNDS_ENABLED:Ljava/lang/String;
@@ -4600,6 +4613,9 @@
Landroid/provider/Settings$System;->LOCKSCREEN_SOUNDS_ENABLED:Ljava/lang/String;
Landroid/provider/Settings$System;->LOCK_SOUND:Ljava/lang/String;
Landroid/provider/Settings$System;->MASTER_MONO:Ljava/lang/String;
+Landroid/provider/Settings$System;->MOVED_TO_GLOBAL:Ljava/util/HashSet;
+Landroid/provider/Settings$System;->MOVED_TO_SECURE:Ljava/util/HashSet;
+Landroid/provider/Settings$System;->MOVED_TO_SECURE_THEN_GLOBAL:Ljava/util/HashSet;
Landroid/provider/Settings$System;->NOTIFICATION_LIGHT_PULSE:Ljava/lang/String;
Landroid/provider/Settings$System;->POINTER_LOCATION:Ljava/lang/String;
Landroid/provider/Settings$System;->POINTER_SPEED:Ljava/lang/String;
@@ -4614,6 +4630,7 @@
Landroid/provider/Settings$System;->sProviderHolder:Landroid/provider/Settings$ContentProviderHolder;
Landroid/provider/Settings$System;->TTY_MODE:Ljava/lang/String;
Landroid/provider/Settings$System;->UNLOCK_SOUND:Ljava/lang/String;
+Landroid/provider/Settings$System;->VALIDATORS:Ljava/util/Map;
Landroid/provider/Settings$System;->VIBRATE_IN_SILENT:Ljava/lang/String;
Landroid/provider/Settings;->ACTION_TRUSTED_CREDENTIALS_USER:Ljava/lang/String;
Landroid/provider/Settings;->ACTION_USER_DICTIONARY_INSERT:Ljava/lang/String;
@@ -5357,6 +5374,7 @@
Landroid/telephony/ServiceState;->mCdmaRoamingIndicator:I
Landroid/telephony/ServiceState;->mCssIndicator:Z
Landroid/telephony/ServiceState;->mIsManualNetworkSelection:Z
+Landroid/telephony/ServiceState;->mIsUsingCarrierAggregation:Z
Landroid/telephony/ServiceState;->mNetworkId:I
Landroid/telephony/ServiceState;->mSystemId:I
Landroid/telephony/ServiceState;->newFromBundle(Landroid/os/Bundle;)Landroid/telephony/ServiceState;
@@ -5720,6 +5738,7 @@
Landroid/transition/Scene;->setCurrentScene(Landroid/view/View;Landroid/transition/Scene;)V
Landroid/transition/Transition;->cancel()V
Landroid/transition/Transition;->end()V
+Landroid/transition/Transition;->getRunningAnimators()Landroid/util/ArrayMap;
Landroid/transition/TransitionManager;->getRunningTransitions()Landroid/util/ArrayMap;
Landroid/transition/TransitionManager;->sPendingTransitions:Ljava/util/ArrayList;
Landroid/transition/TransitionManager;->sRunningTransitions:Ljava/lang/ThreadLocal;
@@ -6166,6 +6185,7 @@
Landroid/view/SurfaceControl;->HIDDEN:I
Landroid/view/SurfaceControl;->hide()V
Landroid/view/SurfaceControl;->openTransaction()V
+Landroid/view/SurfaceControl;->screenshot(Landroid/graphics/Rect;III)Landroid/graphics/Bitmap;
Landroid/view/SurfaceControl;->screenshot(Landroid/graphics/Rect;IIIIZI)Landroid/graphics/Bitmap;
Landroid/view/SurfaceControl;->screenshot(Landroid/os/IBinder;Landroid/view/Surface;Landroid/graphics/Rect;IIIIZZ)V
Landroid/view/SurfaceControl;->setDisplayLayerStack(Landroid/os/IBinder;I)V
@@ -6959,6 +6979,7 @@
Landroid/widget/ListView;->fillSpecific(II)Landroid/view/View;
Landroid/widget/ListView;->fillUp(II)Landroid/view/View;
Landroid/widget/ListView;->getHeightForPosition(I)I
+Landroid/widget/ListView;->isDirectChildHeaderOrFooter(Landroid/view/View;)Z
Landroid/widget/ListView;->makeAndAddView(IIZIZ)Landroid/view/View;
Landroid/widget/ListView;->mAreAllItemsSelectable:Z
Landroid/widget/ListView;->mDivider:Landroid/graphics/drawable/Drawable;
@@ -7507,6 +7528,7 @@
Lcom/android/internal/appwidget/IAppWidgetService;->bindAppWidgetId(Ljava/lang/String;IILandroid/content/ComponentName;Landroid/os/Bundle;)Z
Lcom/android/internal/appwidget/IAppWidgetService;->bindRemoteViewsService(Ljava/lang/String;ILandroid/content/Intent;Landroid/app/IApplicationThread;Landroid/os/IBinder;Landroid/app/IServiceConnection;I)Z
Lcom/android/internal/appwidget/IAppWidgetService;->getAppWidgetIds(Landroid/content/ComponentName;)[I
+Lcom/android/internal/appwidget/IAppWidgetService;->getAppWidgetViews(Ljava/lang/String;I)Landroid/widget/RemoteViews;
Lcom/android/internal/backup/IBackupTransport$Stub;-><init>()V
Lcom/android/internal/backup/IBackupTransport$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/backup/IBackupTransport;
Lcom/android/internal/backup/IBackupTransport;->clearBackupData(Landroid/content/pm/PackageInfo;)I
@@ -7723,6 +7745,9 @@
Lcom/android/internal/R$attr;->text:I
Lcom/android/internal/R$attr;->title:I
Lcom/android/internal/R$attr;->webViewStyle:I
+Lcom/android/internal/R$bool;-><init>()V
+Lcom/android/internal/R$bool;->config_automatic_brightness_available:I
+Lcom/android/internal/R$bool;->config_intrusiveNotificationLed:I
Lcom/android/internal/R$bool;->config_mms_content_disposition_support:I
Lcom/android/internal/R$bool;->config_showNavigationBar:I
Lcom/android/internal/R$dimen;-><init>()V
@@ -8146,6 +8171,8 @@
Lcom/android/internal/R$styleable;->Window:[I
Lcom/android/internal/R$styleable;->WindowAnimation:[I
Lcom/android/internal/R$styleable;->Window_windowActionBarFullscreenDecorLayout:I
+Lcom/android/internal/R$styleable;->Window_windowBackground:I
+Lcom/android/internal/R$styleable;->Window_windowFullscreen:I
Lcom/android/internal/R$styleable;->Window_windowIsFloating:I
Lcom/android/internal/R$styleable;->Window_windowIsTranslucent:I
Lcom/android/internal/R$styleable;->Window_windowShowWallpaper:I
@@ -8215,6 +8242,7 @@
Lcom/android/internal/telephony/IPhoneStateListener;->onSignalStrengthChanged(I)V
Lcom/android/internal/telephony/IPhoneStateListener;->onSignalStrengthsChanged(Landroid/telephony/SignalStrength;)V
Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;->getDeviceId(Ljava/lang/String;)Ljava/lang/String;
Lcom/android/internal/telephony/IPhoneSubInfo$Stub;-><init>()V
Lcom/android/internal/telephony/IPhoneSubInfo$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IPhoneSubInfo;
Lcom/android/internal/telephony/IPhoneSubInfo$Stub;->TRANSACTION_getDeviceId:I
@@ -8400,6 +8428,8 @@
Lcom/android/internal/view/menu/MenuBuilder;->addMenuPresenter(Lcom/android/internal/view/menu/MenuPresenter;Landroid/content/Context;)V
Lcom/android/internal/view/menu/MenuBuilder;->collapseItemActionView(Lcom/android/internal/view/menu/MenuItemImpl;)Z
Lcom/android/internal/view/menu/MenuBuilder;->getContext()Landroid/content/Context;
+Lcom/android/internal/view/menu/MenuBuilder;->getHeaderIcon()Landroid/graphics/drawable/Drawable;
+Lcom/android/internal/view/menu/MenuBuilder;->getHeaderTitle()Ljava/lang/CharSequence;
Lcom/android/internal/view/menu/MenuBuilder;->getNonActionItems()Ljava/util/ArrayList;
Lcom/android/internal/view/menu/MenuBuilder;->getRootMenu()Lcom/android/internal/view/menu/MenuBuilder;
Lcom/android/internal/view/menu/MenuBuilder;->getVisibleItems()Ljava/util/ArrayList;
@@ -8417,11 +8447,14 @@
Lcom/android/internal/view/menu/MenuItemImpl;->requestsActionButton()Z
Lcom/android/internal/view/menu/MenuItemImpl;->requiresActionButton()Z
Lcom/android/internal/view/menu/MenuItemImpl;->setActionViewExpanded(Z)V
+Lcom/android/internal/view/menu/MenuItemImpl;->setExclusiveCheckable(Z)V
Lcom/android/internal/view/menu/MenuItemImpl;->setMenuInfo(Landroid/view/ContextMenu$ContextMenuInfo;)V
Lcom/android/internal/view/menu/MenuPopupHelper;-><init>(Landroid/content/Context;Lcom/android/internal/view/menu/MenuBuilder;)V
Lcom/android/internal/view/menu/MenuPopupHelper;-><init>(Landroid/content/Context;Lcom/android/internal/view/menu/MenuBuilder;Landroid/view/View;)V
Lcom/android/internal/view/menu/MenuPopupHelper;->dismiss()V
+Lcom/android/internal/view/menu/MenuPopupHelper;->getPopup()Lcom/android/internal/view/menu/MenuPopup;
Lcom/android/internal/view/menu/MenuPopupHelper;->mForceShowIcon:Z
+Lcom/android/internal/view/menu/MenuPopupHelper;->setAnchorView(Landroid/view/View;)V
Lcom/android/internal/view/menu/MenuPopupHelper;->setForceShowIcon(Z)V
Lcom/android/internal/view/menu/MenuPopupHelper;->setGravity(I)V
Lcom/android/internal/view/menu/MenuPopupHelper;->show()V
@@ -8751,6 +8784,7 @@
Ljava/lang/reflect/Field;->getOffset()I
Ljava/lang/reflect/Parameter;-><init>(Ljava/lang/String;ILjava/lang/reflect/Executable;I)V
Ljava/lang/reflect/Proxy;->invoke(Ljava/lang/reflect/Proxy;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;
+Ljava/lang/Runtime;-><init>()V
Ljava/lang/Runtime;->load(Ljava/lang/String;Ljava/lang/ClassLoader;)V
Ljava/lang/Runtime;->loadLibrary(Ljava/lang/String;Ljava/lang/ClassLoader;)V
Ljava/lang/Runtime;->loadLibrary0(Ljava/lang/ClassLoader;Ljava/lang/String;)V
@@ -9119,6 +9153,7 @@
Lorg/xml/sax/helpers/NamespaceSupport;->contexts:[Lorg/xml/sax/helpers/NamespaceSupport$Context;
Lorg/xml/sax/helpers/NamespaceSupport;->currentContext:Lorg/xml/sax/helpers/NamespaceSupport$Context;
Lorg/xml/sax/helpers/NamespaceSupport;->EMPTY_ENUMERATION:Ljava/util/Enumeration;
+Lorg/xml/sax/helpers/NamespaceSupport;->namespaceDeclUris:Z
Lorg/xml/sax/helpers/ParserAdapter;->attAdapter:Lorg/xml/sax/helpers/ParserAdapter$AttributeListAdapter;
Lorg/xml/sax/helpers/ParserAdapter;->atts:Lorg/xml/sax/helpers/AttributesImpl;
Lorg/xml/sax/helpers/ParserAdapter;->checkNotParsing(Ljava/lang/String;Ljava/lang/String;)V
@@ -9138,6 +9173,7 @@
Lorg/xml/sax/helpers/ParserAdapter;->reportError(Ljava/lang/String;)V
Lorg/xml/sax/helpers/ParserAdapter;->setup(Lorg/xml/sax/Parser;)V
Lorg/xml/sax/helpers/ParserAdapter;->setupParser()V
+Lorg/xml/sax/helpers/ParserAdapter;->uris:Z
Lorg/xml/sax/helpers/XMLFilterImpl;->contentHandler:Lorg/xml/sax/ContentHandler;
Lorg/xml/sax/helpers/XMLFilterImpl;->dtdHandler:Lorg/xml/sax/DTDHandler;
Lorg/xml/sax/helpers/XMLFilterImpl;->entityResolver:Lorg/xml/sax/EntityResolver;
diff --git a/config/hiddenapi-p-light-greylist.txt b/config/hiddenapi-p-light-greylist.txt
index 7f3c93a..e360879 100644
--- a/config/hiddenapi-p-light-greylist.txt
+++ b/config/hiddenapi-p-light-greylist.txt
@@ -1626,8 +1626,6 @@
Landroid/hardware/display/IDisplayManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/display/IDisplayManager;
Landroid/hardware/display/WifiDisplayStatus;->mActiveDisplay:Landroid/hardware/display/WifiDisplay;
Landroid/hardware/display/WifiDisplayStatus;->mDisplays:[Landroid/hardware/display/WifiDisplay;
-Landroid/hardware/fingerprint/Fingerprint;->getFingerId()I
-Landroid/hardware/fingerprint/Fingerprint;->getName()Ljava/lang/CharSequence;
Landroid/hardware/fingerprint/IFingerprintService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/hardware/input/IInputManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/hardware/input/IInputManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/input/IInputManager;
diff --git a/core/java/android/animation/IntEvaluator.java b/core/java/android/animation/IntEvaluator.java
index 34fb0dc..1de2ae7 100644
--- a/core/java/android/animation/IntEvaluator.java
+++ b/core/java/android/animation/IntEvaluator.java
@@ -24,7 +24,7 @@
/**
* This function returns the result of linearly interpolating the start and end values, with
* <code>fraction</code> representing the proportion between the start and end values. The
- * calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>,
+ * calculation is a simple parametric calculation: <code>result = x0 + t * (x1 - x0)</code>,
* where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
* and <code>t</code> is <code>fraction</code>.
*
@@ -39,4 +39,4 @@
int startInt = startValue;
return (int)(startInt + fraction * (endValue - startInt));
}
-}
\ No newline at end of file
+}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 8e0fa13..6bac52d 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4406,9 +4406,9 @@
/**
* Requests permissions to be granted to this application. These permissions
* must be requested in your manifest, they should not be granted to your app,
- * and they should have protection level {@link android.content.pm.PermissionInfo
- * #PROTECTION_DANGEROUS dangerous}, regardless whether they are declared by
- * the platform or a third-party app.
+ * and they should have protection level {@link
+ * android.content.pm.PermissionInfo#PROTECTION_DANGEROUS dangerous}, regardless
+ * whether they are declared by the platform or a third-party app.
* <p>
* Normal permissions {@link android.content.pm.PermissionInfo#PROTECTION_NORMAL}
* are granted at install time if requested in the manifest. Signature permissions
@@ -4452,7 +4452,7 @@
* result callbacks including {@link #onRequestPermissionsResult(int, String[], int[])}.
* </p>
* <p>
- * The <a href="http://developer.android.com/samples/RuntimePermissions/index.html">
+ * The <a href="https://github.com/googlesamples/android-RuntimePermissions">
* RuntimePermissions</a> sample app demonstrates how to use this method to
* request permissions at run time.
* </p>
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index f27b286..3f579bc 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -3080,16 +3080,32 @@
*/
public int processState;
+ /**
+ * Whether the app is focused in multi-window environment.
+ * @hide
+ */
+ public boolean isFocused;
+
+ /**
+ * Copy of {@link com.android.server.am.ProcessRecord#lastActivityTime} of the process.
+ * @hide
+ */
+ public long lastActivityTime;
+
public RunningAppProcessInfo() {
importance = IMPORTANCE_FOREGROUND;
importanceReasonCode = REASON_UNKNOWN;
processState = PROCESS_STATE_IMPORTANT_FOREGROUND;
+ isFocused = false;
+ lastActivityTime = 0;
}
public RunningAppProcessInfo(String pProcessName, int pPid, String pArr[]) {
processName = pProcessName;
pid = pPid;
pkgList = pArr;
+ isFocused = false;
+ lastActivityTime = 0;
}
public int describeContents() {
@@ -3110,6 +3126,8 @@
ComponentName.writeToParcel(importanceReasonComponent, dest);
dest.writeInt(importanceReasonImportance);
dest.writeInt(processState);
+ dest.writeInt(isFocused ? 1 : 0);
+ dest.writeLong(lastActivityTime);
}
public void readFromParcel(Parcel source) {
@@ -3126,6 +3144,8 @@
importanceReasonComponent = ComponentName.readFromParcel(source);
importanceReasonImportance = source.readInt();
processState = source.readInt();
+ isFocused = source.readInt() != 0;
+ lastActivityTime = source.readLong();
}
public static final Creator<RunningAppProcessInfo> CREATOR =
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 4e6cc7e..e5cfe84 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -21,6 +21,7 @@
import android.content.ComponentName;
import android.content.IIntentSender;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.IBinder;
@@ -31,6 +32,7 @@
import com.android.internal.app.IVoiceInteractor;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -41,6 +43,11 @@
public abstract class ActivityManagerInternal {
+ // Access modes for handleIncomingUser.
+ public static final int ALLOW_NON_FULL = 0;
+ public static final int ALLOW_NON_FULL_IN_PROFILE = 1;
+ public static final int ALLOW_FULL_ONLY = 2;
+
/**
* Grant Uri permissions from one app to another. This method only extends
* permission grants if {@code callingUid} has permission to them.
@@ -63,15 +70,6 @@
String processName, String abiOverride, int uid, Runnable crashHandler);
/**
- * Called when a user has been deleted. This can happen during normal device usage
- * or just at startup, when partially removed users are purged. Any state persisted by the
- * ActivityManager should be purged now.
- *
- * @param userId The user being cleaned up.
- */
- public abstract void onUserRemoved(int userId);
-
- /**
* Kill foreground apps from the specified user.
*/
public abstract void killForegroundAppsForUser(int userHandle);
@@ -95,15 +93,6 @@
boolean adding);
/**
- * Updates and persists the {@link Configuration} for a given user.
- *
- * @param values the configuration to update
- * @param userId the user to update the configuration for
- */
- public abstract void updatePersistentConfigurationForUser(@NonNull Configuration values,
- int userId);
-
- /**
* Get the procstate for the UID. The return value will be between
* {@link ActivityManager#MIN_PROCESS_STATE} and {@link ActivityManager#MAX_PROCESS_STATE}.
* Note if the UID doesn't exist, it'll return {@link ActivityManager#PROCESS_STATE_NONEXISTENT}
@@ -155,17 +144,6 @@
public abstract void clearSavedANRState();
/**
- * Set a uid that is allowed to bypass stopped app switches, launching an app
- * whenever it wants.
- *
- * @param type Type of the caller -- unique string the caller supplies to identify itself
- * and disambiguate with other calles.
- * @param uid The uid of the app to be allowed, or -1 to clear the uid for this type.
- * @param userId The user it is allowed for.
- */
- public abstract void setAllowAppSwitches(@NonNull String type, int uid, int userId);
-
- /**
* @return true if runtime was restarted, false if it's normal boot
*/
public abstract boolean isRuntimeRestarted();
@@ -199,4 +177,40 @@
* Returns a list that contains the memory stats for currently running processes.
*/
public abstract List<ProcessMemoryState> getMemoryStateForProcesses();
+
+ /**
+ * Checks to see if the calling pid is allowed to handle the user. Returns adjusted user id as
+ * needed.
+ */
+ public abstract int handleIncomingUser(int callingPid, int callingUid, int userId,
+ boolean allowAll, int allowMode, String name, String callerPackage);
+
+ /** Checks if the calling binder pid as the permission. */
+ public abstract void enforceCallingPermission(String permission, String func);
+
+ /** Returns the current user id. */
+ public abstract int getCurrentUserId();
+
+ /** Returns true if the user is running. */
+ public abstract boolean isUserRunning(int userId, int flags);
+
+ /** Trims memory usage in the system by removing/stopping unused application processes. */
+ public abstract void trimApplications();
+
+ /** Returns the screen compatibility mode for the given application. */
+ public abstract int getPackageScreenCompatMode(ApplicationInfo ai);
+
+ /** Sets the screen compatibility mode for the given application. */
+ public abstract void setPackageScreenCompatMode(ApplicationInfo ai, int mode);
+
+ /** Closes all system dialogs. */
+ public abstract void closeSystemDialogs(String reason);
+
+ /** Kill the processes in the list due to their tasks been removed. */
+ public abstract void killProcessesForRemovedTask(ArrayList<Object> procsToKill);
+
+ /**
+ * Returns {@code true} if {@code uid} is running an activity from {@code packageName}.
+ */
+ public abstract boolean hasRunningActivity(int uid, @Nullable String packageName);
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 8639849..8b33963 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -350,8 +350,10 @@
public static final int OP_START_FOREGROUND = 76;
/** @hide */
public static final int OP_BLUETOOTH_SCAN = 77;
+ /** @hide Use the face authentication API. */
+ public static final int OP_USE_FACE = 78;
/** @hide */
- public static final int _NUM_OP = 78;
+ public static final int _NUM_OP = 79;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -596,6 +598,9 @@
/** @hide */
public static final String OPSTR_BLUETOOTH_SCAN = "android:bluetooth_scan";
+ /** @hide Use the face authentication API. */
+ public static final String OPSTR_USE_FACE = "android:use_face";
+
// Warning: If an permission is added here it also has to be added to
// com.android.packageinstaller.permission.utils.EventLogger
private static final int[] RUNTIME_AND_APPOP_PERMISSIONS_OPS = {
@@ -733,6 +738,7 @@
OP_MANAGE_IPSEC_TUNNELS, // MANAGE_IPSEC_HANDOVERS
OP_START_FOREGROUND, // START_FOREGROUND
OP_COARSE_LOCATION, // BLUETOOTH_SCAN
+ OP_USE_FACE, // FACE
};
/**
@@ -817,6 +823,7 @@
OPSTR_MANAGE_IPSEC_TUNNELS,
OPSTR_START_FOREGROUND,
OPSTR_BLUETOOTH_SCAN,
+ OPSTR_USE_FACE,
};
/**
@@ -902,6 +909,7 @@
"MANAGE_IPSEC_TUNNELS",
"START_FOREGROUND",
"BLUETOOTH_SCAN",
+ "USE_FACE",
};
/**
@@ -987,6 +995,7 @@
null, // no permission for OP_MANAGE_IPSEC_TUNNELS
Manifest.permission.FOREGROUND_SERVICE,
null, // no permission for OP_BLUETOOTH_SCAN
+ Manifest.permission.USE_BIOMETRIC,
};
/**
@@ -1073,6 +1082,7 @@
null, // MANAGE_IPSEC_TUNNELS
null, // START_FOREGROUND
null, // maybe should be UserManager.DISALLOW_SHARE_LOCATION, //BLUETOOTH_SCAN
+ null, // USE_FACE
};
/**
@@ -1158,6 +1168,7 @@
false, // MANAGE_IPSEC_HANDOVERS
false, // START_FOREGROUND
true, // BLUETOOTH_SCAN
+ false, // USE_FACE
};
/**
@@ -1242,6 +1253,7 @@
AppOpsManager.MODE_ERRORED, // MANAGE_IPSEC_TUNNELS
AppOpsManager.MODE_ALLOWED, // OP_START_FOREGROUND
AppOpsManager.MODE_ALLOWED, // OP_BLUETOOTH_SCAN
+ AppOpsManager.MODE_ALLOWED, // USE_FACE
};
/**
@@ -1330,6 +1342,7 @@
false, // MANAGE_IPSEC_TUNNELS
false, // START_FOREGROUND
false, // BLUETOOTH_SCAN
+ false, // USE_FACE
};
/**
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 0e44833..344610a 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -73,6 +73,7 @@
import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
+import android.os.StrictMode;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
@@ -149,15 +150,16 @@
@Override
public PackageInfo getPackageInfo(String packageName, int flags)
throws NameNotFoundException {
- return getPackageInfoAsUser(packageName, flags, mContext.getUserId());
+ return getPackageInfoAsUser(packageName, flags, getUserId());
}
@Override
public PackageInfo getPackageInfo(VersionedPackage versionedPackage, int flags)
throws NameNotFoundException {
+ final int userId = getUserId();
try {
- PackageInfo pi = mPM.getPackageInfoVersioned(versionedPackage, flags,
- mContext.getUserId());
+ PackageInfo pi = mPM.getPackageInfoVersioned(versionedPackage,
+ updateFlagsForPackage(flags, userId), userId);
if (pi != null) {
return pi;
}
@@ -171,7 +173,8 @@
public PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
throws NameNotFoundException {
try {
- PackageInfo pi = mPM.getPackageInfo(packageName, flags, userId);
+ PackageInfo pi = mPM.getPackageInfo(packageName,
+ updateFlagsForPackage(flags, userId), userId);
if (pi != null) {
return pi;
}
@@ -262,8 +265,10 @@
@Override
public int[] getPackageGids(String packageName, int flags)
throws NameNotFoundException {
+ final int userId = getUserId();
try {
- int[] gids = mPM.getPackageGids(packageName, flags, mContext.getUserId());
+ int[] gids = mPM.getPackageGids(packageName,
+ updateFlagsForPackage(flags, userId), userId);
if (gids != null) {
return gids;
}
@@ -276,7 +281,7 @@
@Override
public int getPackageUid(String packageName, int flags) throws NameNotFoundException {
- return getPackageUidAsUser(packageName, flags, mContext.getUserId());
+ return getPackageUidAsUser(packageName, flags, getUserId());
}
@Override
@@ -288,7 +293,8 @@
public int getPackageUidAsUser(String packageName, int flags, int userId)
throws NameNotFoundException {
try {
- int uid = mPM.getPackageUid(packageName, flags, userId);
+ int uid = mPM.getPackageUid(packageName,
+ updateFlagsForPackage(flags, userId), userId);
if (uid >= 0) {
return uid;
}
@@ -374,14 +380,15 @@
@Override
public ApplicationInfo getApplicationInfo(String packageName, int flags)
throws NameNotFoundException {
- return getApplicationInfoAsUser(packageName, flags, mContext.getUserId());
+ return getApplicationInfoAsUser(packageName, flags, getUserId());
}
@Override
public ApplicationInfo getApplicationInfoAsUser(String packageName, int flags, int userId)
throws NameNotFoundException {
try {
- ApplicationInfo ai = mPM.getApplicationInfo(packageName, flags, userId);
+ ApplicationInfo ai = mPM.getApplicationInfo(packageName,
+ updateFlagsForApplication(flags, userId), userId);
if (ai != null) {
// This is a temporary hack. Callers must use
// createPackageContext(packageName).getApplicationInfo() to
@@ -423,8 +430,10 @@
@Override
public ActivityInfo getActivityInfo(ComponentName className, int flags)
throws NameNotFoundException {
+ final int userId = getUserId();
try {
- ActivityInfo ai = mPM.getActivityInfo(className, flags, mContext.getUserId());
+ ActivityInfo ai = mPM.getActivityInfo(className,
+ updateFlagsForComponent(flags, userId, null), userId);
if (ai != null) {
return ai;
}
@@ -438,8 +447,10 @@
@Override
public ActivityInfo getReceiverInfo(ComponentName className, int flags)
throws NameNotFoundException {
+ final int userId = getUserId();
try {
- ActivityInfo ai = mPM.getReceiverInfo(className, flags, mContext.getUserId());
+ ActivityInfo ai = mPM.getReceiverInfo(className,
+ updateFlagsForComponent(flags, userId, null), userId);
if (ai != null) {
return ai;
}
@@ -453,8 +464,10 @@
@Override
public ServiceInfo getServiceInfo(ComponentName className, int flags)
throws NameNotFoundException {
+ final int userId = getUserId();
try {
- ServiceInfo si = mPM.getServiceInfo(className, flags, mContext.getUserId());
+ ServiceInfo si = mPM.getServiceInfo(className,
+ updateFlagsForComponent(flags, userId, null), userId);
if (si != null) {
return si;
}
@@ -468,8 +481,10 @@
@Override
public ProviderInfo getProviderInfo(ComponentName className, int flags)
throws NameNotFoundException {
+ final int userId = getUserId();
try {
- ProviderInfo pi = mPM.getProviderInfo(className, flags, mContext.getUserId());
+ ProviderInfo pi = mPM.getProviderInfo(className,
+ updateFlagsForComponent(flags, userId, null), userId);
if (pi != null) {
return pi;
}
@@ -492,7 +507,7 @@
/** @hide */
@Override
public @NonNull List<SharedLibraryInfo> getSharedLibraries(int flags) {
- return getSharedLibrariesAsUser(flags, mContext.getUserId());
+ return getSharedLibrariesAsUser(flags, getUserId());
}
/** @hide */
@@ -535,7 +550,7 @@
@Override
public ChangedPackages getChangedPackages(int sequenceNumber) {
try {
- return mPM.getChangedPackages(sequenceNumber, mContext.getUserId());
+ return mPM.getChangedPackages(sequenceNumber, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -578,7 +593,7 @@
@Override
public int checkPermission(String permName, String pkgName) {
try {
- return mPM.checkPermission(permName, pkgName, mContext.getUserId());
+ return mPM.checkPermission(permName, pkgName, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -587,7 +602,7 @@
@Override
public boolean isPermissionRevokedByPolicy(String permName, String pkgName) {
try {
- return mPM.isPermissionRevokedByPolicy(permName, pkgName, mContext.getUserId());
+ return mPM.isPermissionRevokedByPolicy(permName, pkgName, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -681,7 +696,7 @@
public boolean shouldShowRequestPermissionRationale(String permission) {
try {
return mPM.shouldShowRequestPermissionRationale(permission,
- mContext.getPackageName(), mContext.getUserId());
+ mContext.getPackageName(), getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -769,7 +784,7 @@
@SuppressWarnings("unchecked")
@Override
public List<PackageInfo> getInstalledPackages(int flags) {
- return getInstalledPackagesAsUser(flags, mContext.getUserId());
+ return getInstalledPackagesAsUser(flags, getUserId());
}
/** @hide */
@@ -778,7 +793,7 @@
public List<PackageInfo> getInstalledPackagesAsUser(int flags, int userId) {
try {
ParceledListSlice<PackageInfo> parceledList =
- mPM.getInstalledPackages(flags, userId);
+ mPM.getInstalledPackages(updateFlagsForPackage(flags, userId), userId);
if (parceledList == null) {
return Collections.emptyList();
}
@@ -792,10 +807,11 @@
@Override
public List<PackageInfo> getPackagesHoldingPermissions(
String[] permissions, int flags) {
- final int userId = mContext.getUserId();
+ final int userId = getUserId();
try {
ParceledListSlice<PackageInfo> parceledList =
- mPM.getPackagesHoldingPermissions(permissions, flags, userId);
+ mPM.getPackagesHoldingPermissions(permissions,
+ updateFlagsForPackage(flags, userId), userId);
if (parceledList == null) {
return Collections.emptyList();
}
@@ -808,7 +824,7 @@
@SuppressWarnings("unchecked")
@Override
public List<ApplicationInfo> getInstalledApplications(int flags) {
- return getInstalledApplicationsAsUser(flags, mContext.getUserId());
+ return getInstalledApplicationsAsUser(flags, getUserId());
}
/** @hide */
@@ -817,7 +833,7 @@
public List<ApplicationInfo> getInstalledApplicationsAsUser(int flags, int userId) {
try {
ParceledListSlice<ApplicationInfo> parceledList =
- mPM.getInstalledApplications(flags, userId);
+ mPM.getInstalledApplications(updateFlagsForApplication(flags, userId), userId);
if (parceledList == null) {
return Collections.emptyList();
}
@@ -832,8 +848,7 @@
@Override
public List<InstantAppInfo> getInstantApps() {
try {
- ParceledListSlice<InstantAppInfo> slice =
- mPM.getInstantApps(mContext.getUserId());
+ ParceledListSlice<InstantAppInfo> slice = mPM.getInstantApps(getUserId());
if (slice != null) {
return slice.getList();
}
@@ -847,8 +862,7 @@
@Override
public Drawable getInstantAppIcon(String packageName) {
try {
- Bitmap bitmap = mPM.getInstantAppIcon(
- packageName, mContext.getUserId());
+ Bitmap bitmap = mPM.getInstantAppIcon(packageName, getUserId());
if (bitmap != null) {
return new BitmapDrawable(null, bitmap);
}
@@ -866,7 +880,7 @@
@Override
public boolean isInstantApp(String packageName) {
try {
- return mPM.isInstantApp(packageName, mContext.getUserId());
+ return mPM.isInstantApp(packageName, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -886,8 +900,7 @@
@Override
public @NonNull byte[] getInstantAppCookie() {
try {
- final byte[] cookie = mPM.getInstantAppCookie(
- mContext.getPackageName(), mContext.getUserId());
+ final byte[] cookie = mPM.getInstantAppCookie(mContext.getPackageName(), getUserId());
if (cookie != null) {
return cookie;
} else {
@@ -910,8 +923,7 @@
+ getInstantAppCookieMaxBytes());
}
try {
- mPM.setInstantAppCookie(mContext.getPackageName(),
- cookie, mContext.getUserId());
+ mPM.setInstantAppCookie(mContext.getPackageName(), cookie, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -920,8 +932,7 @@
@Override
public boolean setInstantAppCookie(@NonNull byte[] cookie) {
try {
- return mPM.setInstantAppCookie(mContext.getPackageName(),
- cookie, mContext.getUserId());
+ return mPM.setInstantAppCookie(mContext.getPackageName(), cookie, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -929,7 +940,7 @@
@Override
public ResolveInfo resolveActivity(Intent intent, int flags) {
- return resolveActivityAsUser(intent, flags, mContext.getUserId());
+ return resolveActivityAsUser(intent, flags, getUserId());
}
@Override
@@ -938,7 +949,7 @@
return mPM.resolveIntent(
intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- flags,
+ updateFlagsForComponent(flags, userId, intent),
userId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -948,7 +959,7 @@
@Override
public List<ResolveInfo> queryIntentActivities(Intent intent,
int flags) {
- return queryIntentActivitiesAsUser(intent, flags, mContext.getUserId());
+ return queryIntentActivitiesAsUser(intent, flags, getUserId());
}
/** @hide Same as above but for a specific user */
@@ -957,10 +968,11 @@
public List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent,
int flags, int userId) {
try {
- ParceledListSlice<ResolveInfo> parceledList =
- mPM.queryIntentActivities(intent,
- intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- flags, userId);
+ ParceledListSlice<ResolveInfo> parceledList = mPM.queryIntentActivities(
+ intent,
+ intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ updateFlagsForComponent(flags, userId, intent),
+ userId);
if (parceledList == null) {
return Collections.emptyList();
}
@@ -972,9 +984,9 @@
@Override
@SuppressWarnings("unchecked")
- public List<ResolveInfo> queryIntentActivityOptions(
- ComponentName caller, Intent[] specifics, Intent intent,
- int flags) {
+ public List<ResolveInfo> queryIntentActivityOptions(ComponentName caller, Intent[] specifics,
+ Intent intent, int flags) {
+ final int userId = getUserId();
final ContentResolver resolver = mContext.getContentResolver();
String[] specificTypes = null;
@@ -995,9 +1007,14 @@
}
try {
- ParceledListSlice<ResolveInfo> parceledList =
- mPM.queryIntentActivityOptions(caller, specifics, specificTypes, intent,
- intent.resolveTypeIfNeeded(resolver), flags, mContext.getUserId());
+ ParceledListSlice<ResolveInfo> parceledList = mPM.queryIntentActivityOptions(
+ caller,
+ specifics,
+ specificTypes,
+ intent,
+ intent.resolveTypeIfNeeded(resolver),
+ updateFlagsForComponent(flags, userId, intent),
+ userId);
if (parceledList == null) {
return Collections.emptyList();
}
@@ -1014,10 +1031,11 @@
@SuppressWarnings("unchecked")
public List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent, int flags, int userId) {
try {
- ParceledListSlice<ResolveInfo> parceledList =
- mPM.queryIntentReceivers(intent,
- intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- flags, userId);
+ ParceledListSlice<ResolveInfo> parceledList = mPM.queryIntentReceivers(
+ intent,
+ intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ updateFlagsForComponent(flags, userId, intent),
+ userId);
if (parceledList == null) {
return Collections.emptyList();
}
@@ -1029,7 +1047,7 @@
@Override
public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags) {
- return queryBroadcastReceiversAsUser(intent, flags, mContext.getUserId());
+ return queryBroadcastReceiversAsUser(intent, flags, getUserId());
}
@Override
@@ -1039,7 +1057,7 @@
return mPM.resolveService(
intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- flags,
+ updateFlagsForComponent(flags, userId, intent),
userId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1048,17 +1066,18 @@
@Override
public ResolveInfo resolveService(Intent intent, int flags) {
- return resolveServiceAsUser(intent, flags, mContext.getUserId());
+ return resolveServiceAsUser(intent, flags, getUserId());
}
@Override
@SuppressWarnings("unchecked")
public List<ResolveInfo> queryIntentServicesAsUser(Intent intent, int flags, int userId) {
try {
- ParceledListSlice<ResolveInfo> parceledList =
- mPM.queryIntentServices(intent,
+ ParceledListSlice<ResolveInfo> parceledList = mPM.queryIntentServices(
+ intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- flags, userId);
+ updateFlagsForComponent(flags, userId, intent),
+ userId);
if (parceledList == null) {
return Collections.emptyList();
}
@@ -1070,7 +1089,7 @@
@Override
public List<ResolveInfo> queryIntentServices(Intent intent, int flags) {
- return queryIntentServicesAsUser(intent, flags, mContext.getUserId());
+ return queryIntentServicesAsUser(intent, flags, getUserId());
}
@Override
@@ -1078,10 +1097,11 @@
public List<ResolveInfo> queryIntentContentProvidersAsUser(
Intent intent, int flags, int userId) {
try {
- ParceledListSlice<ResolveInfo> parceledList =
- mPM.queryIntentContentProviders(intent,
- intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- flags, userId);
+ ParceledListSlice<ResolveInfo> parceledList = mPM.queryIntentContentProviders(
+ intent,
+ intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ updateFlagsForComponent(flags, userId, intent),
+ userId);
if (parceledList == null) {
return Collections.emptyList();
}
@@ -1093,19 +1113,20 @@
@Override
public List<ResolveInfo> queryIntentContentProviders(Intent intent, int flags) {
- return queryIntentContentProvidersAsUser(intent, flags, mContext.getUserId());
+ return queryIntentContentProvidersAsUser(intent, flags, getUserId());
}
@Override
public ProviderInfo resolveContentProvider(String name, int flags) {
- return resolveContentProviderAsUser(name, flags, mContext.getUserId());
+ return resolveContentProviderAsUser(name, flags, getUserId());
}
/** @hide **/
@Override
public ProviderInfo resolveContentProviderAsUser(String name, int flags, int userId) {
try {
- return mPM.resolveContentProvider(name, flags, userId);
+ return mPM.resolveContentProvider(name,
+ updateFlagsForComponent(flags, userId, null), userId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1122,8 +1143,8 @@
public List<ProviderInfo> queryContentProviders(String processName,
int uid, int flags, String metaDataKey) {
try {
- ParceledListSlice<ProviderInfo> slice =
- mPM.queryContentProviders(processName, uid, flags, metaDataKey);
+ ParceledListSlice<ProviderInfo> slice = mPM.queryContentProviders(processName, uid,
+ updateFlagsForComponent(flags, UserHandle.getUserId(uid), null), metaDataKey);
return slice != null ? slice.getList() : Collections.<ProviderInfo>emptyList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1517,6 +1538,73 @@
mPM = pm;
}
+ /**
+ * Update given flags when being used to request {@link PackageInfo}.
+ */
+ private int updateFlagsForPackage(int flags, int userId) {
+ if ((flags & (GET_ACTIVITIES | GET_RECEIVERS | GET_SERVICES | GET_PROVIDERS)) != 0) {
+ // Caller is asking for component details, so they'd better be
+ // asking for specific Direct Boot matching behavior
+ if ((flags & (MATCH_DIRECT_BOOT_UNAWARE
+ | MATCH_DIRECT_BOOT_AWARE
+ | MATCH_DIRECT_BOOT_AUTO)) == 0) {
+ onImplicitDirectBoot(userId);
+ }
+ }
+ return flags;
+ }
+
+ /**
+ * Update given flags when being used to request {@link ApplicationInfo}.
+ */
+ private int updateFlagsForApplication(int flags, int userId) {
+ return updateFlagsForPackage(flags, userId);
+ }
+
+ /**
+ * Update given flags when being used to request {@link ComponentInfo}.
+ */
+ private int updateFlagsForComponent(int flags, int userId, Intent intent) {
+ if (intent != null) {
+ if ((intent.getFlags() & Intent.FLAG_DIRECT_BOOT_AUTO) != 0) {
+ flags |= MATCH_DIRECT_BOOT_AUTO;
+ }
+ }
+
+ // Caller is asking for component details, so they'd better be
+ // asking for specific Direct Boot matching behavior
+ if ((flags & (MATCH_DIRECT_BOOT_UNAWARE
+ | MATCH_DIRECT_BOOT_AWARE
+ | MATCH_DIRECT_BOOT_AUTO)) == 0) {
+ onImplicitDirectBoot(userId);
+ }
+ return flags;
+ }
+
+ private void onImplicitDirectBoot(int userId) {
+ // Only report if someone is relying on implicit behavior while the user
+ // is locked; code running when unlocked is going to see both aware and
+ // unaware components.
+ if (StrictMode.vmImplicitDirectBootEnabled()) {
+ // We can cache the unlocked state for the userId we're running as,
+ // since any relocking of that user will always result in our
+ // process being killed to release any CE FDs we're holding onto.
+ if (userId == UserHandle.myUserId()) {
+ if (mUserUnlocked) {
+ return;
+ } else if (mContext.getSystemService(UserManager.class)
+ .isUserUnlockingOrUnlocked(userId)) {
+ mUserUnlocked = true;
+ } else {
+ StrictMode.onImplicitDirectBoot();
+ }
+ } else if (!mContext.getSystemService(UserManager.class)
+ .isUserUnlockingOrUnlocked(userId)) {
+ StrictMode.onImplicitDirectBoot();
+ }
+ }
+ }
+
@Nullable
private Drawable getCachedIcon(@NonNull ResourceName name) {
synchronized (sSync) {
@@ -1730,7 +1818,7 @@
@Override
public int installExistingPackage(String packageName, int installReason)
throws NameNotFoundException {
- return installExistingPackageAsUser(packageName, installReason, mContext.getUserId());
+ return installExistingPackageAsUser(packageName, installReason, getUserId());
}
@Override
@@ -2089,7 +2177,7 @@
@Override
public void deletePackage(String packageName, IPackageDeleteObserver observer, int flags) {
- deletePackageAsUser(packageName, observer, flags, mContext.getUserId());
+ deletePackageAsUser(packageName, observer, flags, getUserId());
}
@Override
@@ -2107,7 +2195,7 @@
public void clearApplicationUserData(String packageName,
IPackageDataObserver observer) {
try {
- mPM.clearApplicationUserData(packageName, observer, mContext.getUserId());
+ mPM.clearApplicationUserData(packageName, observer, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2158,7 +2246,7 @@
try {
return mPM.setPackagesSuspendedAsUser(packageNames, suspended, appExtras,
launcherExtras, dialogMessage, mContext.getOpPackageName(),
- mContext.getUserId());
+ getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2169,7 +2257,7 @@
final PersistableBundle extras;
try {
extras = mPM.getSuspendedPackageAppExtras(mContext.getOpPackageName(),
- mContext.getUserId());
+ getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2189,7 +2277,7 @@
@Override
public boolean isPackageSuspended(String packageName) throws NameNotFoundException {
try {
- return isPackageSuspendedForUser(packageName, mContext.getUserId());
+ return isPackageSuspendedForUser(packageName, getUserId());
} catch (IllegalArgumentException ie) {
throw new NameNotFoundException(packageName);
}
@@ -2197,7 +2285,7 @@
@Override
public boolean isPackageSuspended() {
- return isPackageSuspendedForUser(mContext.getOpPackageName(), mContext.getUserId());
+ return isPackageSuspendedForUser(mContext.getOpPackageName(), getUserId());
}
/** @hide */
@@ -2247,7 +2335,7 @@
public void addPreferredActivity(IntentFilter filter,
int match, ComponentName[] set, ComponentName activity) {
try {
- mPM.addPreferredActivity(filter, match, set, activity, mContext.getUserId());
+ mPM.addPreferredActivity(filter, match, set, activity, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2267,7 +2355,7 @@
public void replacePreferredActivity(IntentFilter filter,
int match, ComponentName[] set, ComponentName activity) {
try {
- mPM.replacePreferredActivity(filter, match, set, activity, mContext.getUserId());
+ mPM.replacePreferredActivity(filter, match, set, activity, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2316,7 +2404,7 @@
public void setComponentEnabledSetting(ComponentName componentName,
int newState, int flags) {
try {
- mPM.setComponentEnabledSetting(componentName, newState, flags, mContext.getUserId());
+ mPM.setComponentEnabledSetting(componentName, newState, flags, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2325,7 +2413,7 @@
@Override
public int getComponentEnabledSetting(ComponentName componentName) {
try {
- return mPM.getComponentEnabledSetting(componentName, mContext.getUserId());
+ return mPM.getComponentEnabledSetting(componentName, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2336,7 +2424,7 @@
int newState, int flags) {
try {
mPM.setApplicationEnabledSetting(packageName, newState, flags,
- mContext.getUserId(), mContext.getOpPackageName());
+ getUserId(), mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2345,7 +2433,7 @@
@Override
public int getApplicationEnabledSetting(String packageName) {
try {
- return mPM.getApplicationEnabledSetting(packageName, mContext.getUserId());
+ return mPM.getApplicationEnabledSetting(packageName, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2457,7 +2545,7 @@
if (mInstaller == null) {
try {
mInstaller = new PackageInstaller(mPM.getPackageInstaller(),
- mContext.getPackageName(), mContext.getUserId());
+ mContext.getPackageName(), getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2469,7 +2557,7 @@
@Override
public boolean isPackageAvailable(String packageName) {
try {
- return mPM.isPackageAvailable(packageName, mContext.getUserId());
+ return mPM.isPackageAvailable(packageName, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2509,7 +2597,7 @@
if (itemInfo.showUserIcon != UserHandle.USER_NULL) {
return dr;
}
- return getUserBadgedIcon(dr, new UserHandle(mContext.getUserId()));
+ return getUserBadgedIcon(dr, new UserHandle(getUserId()));
}
/**
@@ -2657,6 +2745,9 @@
private final ContextImpl mContext;
private final IPackageManager mPM;
+ /** Assume locked until we hear otherwise */
+ private volatile boolean mUserUnlocked = false;
+
private static final Object sSync = new Object();
private static ArrayMap<ResourceName, WeakReference<Drawable.ConstantState>> sIconCache
= new ArrayMap<ResourceName, WeakReference<Drawable.ConstantState>>();
@@ -2701,7 +2792,7 @@
@Override
public boolean canRequestPackageInstalls() {
try {
- return mPM.canRequestPackageInstalls(mContext.getPackageName(), mContext.getUserId());
+ return mPM.canRequestPackageInstalls(mContext.getPackageName(), getUserId());
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -2811,7 +2902,7 @@
@Override
public CharSequence getHarmfulAppWarning(String packageName) {
try {
- return mPM.getHarmfulAppWarning(packageName, mContext.getUserId());
+ return mPM.getHarmfulAppWarning(packageName, getUserId());
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -2820,7 +2911,7 @@
@Override
public void setHarmfulAppWarning(String packageName, CharSequence warning) {
try {
- mPM.setHarmfulAppWarning(packageName, warning, mContext.getUserId());
+ mPM.setHarmfulAppWarning(packageName, warning, getUserId());
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index b39eb9b..49d3fff 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -237,11 +237,8 @@
// running.
List<ApplicationInfo> getRunningExternalApplications();
void finishHeavyWeightApp();
- // A StrictMode violation to be handled. The violationMask is a
- // subset of the original StrictMode policy bitmask, with only the
- // bit violated and penalty bits to be executed by the
- // ActivityManagerService remaining set.
- void handleApplicationStrictModeViolation(in IBinder app, int violationMask,
+ // A StrictMode violation to be handled.
+ void handleApplicationStrictModeViolation(in IBinder app, int penaltyMask,
in StrictMode.ViolationInfo crashInfo);
boolean isTopActivityImmersive();
void crashApplication(int uid, int initialPid, in String packageName, int userId, in String message);
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index a508289..1eb187e 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -418,4 +418,7 @@
void setVrThread(int tid);
void setPersistentVrThread(int tid);
+ void stopAppSwitches();
+ void resumeAppSwitches();
+ void setActivityController(in IActivityController watcher, boolean imAMonkey);
}
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index ba355f9..1ad3054 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -644,7 +644,7 @@
@Nullable
private Uri restoreSoundUri(Context context, @Nullable Uri uri) {
- if (uri == null) {
+ if (uri == null || Uri.EMPTY.equals(uri)) {
return null;
}
ContentResolver contentResolver = context.getContentResolver();
@@ -680,7 +680,7 @@
private Uri getSoundForBackup(Context context) {
Uri sound = getSound();
- if (sound == null) {
+ if (sound == null || Uri.EMPTY.equals(sound)) {
return null;
}
Uri canonicalSound = context.getContentResolver().canonicalize(sound);
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index e5f143c..b432baa 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -26,6 +26,7 @@
import android.app.slice.SliceManager;
import android.app.timedetector.TimeDetector;
import android.app.timezone.RulesManager;
+import android.app.timezonedetector.TimeZoneDetector;
import android.app.trust.TrustManager;
import android.app.usage.IStorageStatsManager;
import android.app.usage.IUsageStatsManager;
@@ -54,6 +55,8 @@
import android.hardware.SystemSensorManager;
import android.hardware.camera2.CameraManager;
import android.hardware.display.DisplayManager;
+import android.hardware.face.FaceManager;
+import android.hardware.face.IFaceService;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.IFingerprintService;
import android.hardware.hdmi.HdmiControlManager;
@@ -791,6 +794,22 @@
return new FingerprintManager(ctx.getOuterContext(), service);
}});
+ registerService(Context.FACE_SERVICE, FaceManager.class,
+ new CachedServiceFetcher<FaceManager>() {
+ @Override
+ public FaceManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ final IBinder binder;
+ if (ctx.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.O) {
+ binder = ServiceManager.getServiceOrThrow(Context.FACE_SERVICE);
+ } else {
+ binder = ServiceManager.getService(Context.FACE_SERVICE);
+ }
+ IFaceService service = IFaceService.Stub.asInterface(binder);
+ return new FaceManager(ctx.getOuterContext(), service);
+ }
+ });
+
registerService(Context.TV_INPUT_SERVICE, TvInputManager.class,
new CachedServiceFetcher<TvInputManager>() {
@Override
@@ -1015,6 +1034,13 @@
throws ServiceNotFoundException {
return new TimeDetector();
}});
+ registerService(Context.TIME_ZONE_DETECTOR_SERVICE, TimeZoneDetector.class,
+ new CachedServiceFetcher<TimeZoneDetector>() {
+ @Override
+ public TimeZoneDetector createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ return new TimeZoneDetector();
+ }});
}
/**
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index fde756c..6ad6c25 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -996,17 +996,29 @@
}
/**
- * If the current wallpaper is a live wallpaper component, return the
- * information about that wallpaper. Otherwise, if it is a static image,
- * simply return null.
+ * Returns the information about the wallpaper if the current wallpaper is
+ * a live wallpaper component. Otherwise, if the wallpaper is a static image,
+ * this returns null.
*/
public WallpaperInfo getWallpaperInfo() {
+ return getWallpaperInfo(mContext.getUserId());
+ }
+
+ /**
+ * Returns the information about the wallpaper if the current wallpaper is
+ * a live wallpaper component. Otherwise, if the wallpaper is a static image,
+ * this returns null.
+ *
+ * @param userId Owner of the wallpaper.
+ * @hide
+ */
+ public WallpaperInfo getWallpaperInfo(int userId) {
try {
if (sGlobals.mService == null) {
Log.w(TAG, "WallpaperService not running");
throw new RuntimeException(new DeadSystemException());
} else {
- return sGlobals.mService.getWallpaperInfo(mContext.getUserId());
+ return sGlobals.mService.getWallpaperInfo(userId);
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index 09c7981..aea767e 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -59,11 +59,6 @@
/** The current windowing mode of the configuration. */
private @WindowingMode int mWindowingMode;
- private int mFlags;
-
- /** Indicates that this window should always be on top of the other windows. */
- private static final int PFLAG_ALWAYS_ON_TOP = 1 << 0;
-
/** Windowing mode is currently not defined. */
public static final int WINDOWING_MODE_UNDEFINED = 0;
/** Occupies the full area of the screen or the parent container. */
@@ -129,6 +124,24 @@
})
public @interface ActivityType {}
+ /** The current always on top status of the configuration. */
+ private @AlwaysOnTop int mAlwaysOnTop;
+
+ /** Always on top is currently not defined. */
+ private static final int ALWAYS_ON_TOP_UNDEFINED = 0;
+ /** Always on top is currently on for this configuration. */
+ private static final int ALWAYS_ON_TOP_ON = 1;
+ /** Always on top is currently off for this configuration. */
+ private static final int ALWAYS_ON_TOP_OFF = 2;
+
+ /** @hide */
+ @IntDef(prefix = { "ALWAYS_ON_TOP_" }, value = {
+ ALWAYS_ON_TOP_UNDEFINED,
+ ALWAYS_ON_TOP_ON,
+ ALWAYS_ON_TOP_OFF,
+ })
+ private @interface AlwaysOnTop {}
+
/** Bit that indicates that the {@link #mBounds} changed.
* @hide */
public static final int WINDOW_CONFIG_BOUNDS = 1 << 0;
@@ -141,16 +154,16 @@
/** Bit that indicates that the {@link #mActivityType} changed.
* @hide */
public static final int WINDOW_CONFIG_ACTIVITY_TYPE = 1 << 3;
- /** Bit that indicates that the {@link #mFlags} changed.
+ /** Bit that indicates that the {@link #mAlwaysOnTop} changed.
* @hide */
- public static final int WINDOW_CONFIG_FLAGS = 1 << 4;
+ public static final int WINDOW_CONFIG_ALWAYS_ON_TOP = 1 << 4;
/** @hide */
@IntDef(flag = true, prefix = { "WINDOW_CONFIG_" }, value = {
WINDOW_CONFIG_BOUNDS,
WINDOW_CONFIG_APP_BOUNDS,
WINDOW_CONFIG_WINDOWING_MODE,
WINDOW_CONFIG_ACTIVITY_TYPE,
- WINDOW_CONFIG_FLAGS
+ WINDOW_CONFIG_ALWAYS_ON_TOP,
})
public @interface WindowConfig {}
@@ -176,7 +189,7 @@
dest.writeParcelable(mAppBounds, flags);
dest.writeInt(mWindowingMode);
dest.writeInt(mActivityType);
- dest.writeInt(mFlags);
+ dest.writeInt(mAlwaysOnTop);
}
private void readFromParcel(Parcel source) {
@@ -184,7 +197,7 @@
mAppBounds = source.readParcelable(Rect.class.getClassLoader());
mWindowingMode = source.readInt();
mActivityType = source.readInt();
- mFlags = source.readInt();
+ mAlwaysOnTop = source.readInt();
}
@Override
@@ -232,9 +245,7 @@
setAppBounds(rect.left, rect.top, rect.right, rect.bottom);
}
- private void setFlags(int flags) {
- mFlags = flags;
- }
+
/**
* Sets whether this window should be always on top.
@@ -242,11 +253,11 @@
* @hide
*/
public void setAlwaysOnTop(boolean alwaysOnTop) {
- if (alwaysOnTop) {
- mFlags |= PFLAG_ALWAYS_ON_TOP;
- } else {
- mFlags &= ~PFLAG_ALWAYS_ON_TOP;
- }
+ mAlwaysOnTop = alwaysOnTop ? ALWAYS_ON_TOP_ON : ALWAYS_ON_TOP_OFF;
+ }
+
+ private void setAlwaysOnTop(@AlwaysOnTop int alwaysOnTop) {
+ mAlwaysOnTop = alwaysOnTop;
}
/**
@@ -308,7 +319,7 @@
setAppBounds(other.mAppBounds);
setWindowingMode(other.mWindowingMode);
setActivityType(other.mActivityType);
- setFlags(other.mFlags);
+ setAlwaysOnTop(other.mAlwaysOnTop);
}
/** Set this object to completely undefined.
@@ -323,7 +334,7 @@
setBounds(null);
setWindowingMode(WINDOWING_MODE_UNDEFINED);
setActivityType(ACTIVITY_TYPE_UNDEFINED);
- setFlags(0);
+ setAlwaysOnTop(ALWAYS_ON_TOP_UNDEFINED);
}
/**
@@ -341,10 +352,6 @@
changed |= WINDOW_CONFIG_BOUNDS;
setBounds(delta.mBounds);
}
- if (delta.mFlags != mFlags) {
- changed |= WINDOW_CONFIG_FLAGS;
- setFlags(delta.mFlags);
- }
if (delta.mAppBounds != null && !delta.mAppBounds.equals(mAppBounds)) {
changed |= WINDOW_CONFIG_APP_BOUNDS;
setAppBounds(delta.mAppBounds);
@@ -359,6 +366,11 @@
changed |= WINDOW_CONFIG_ACTIVITY_TYPE;
setActivityType(delta.mActivityType);
}
+ if (delta.mAlwaysOnTop != ALWAYS_ON_TOP_UNDEFINED
+ && mAlwaysOnTop != delta.mAlwaysOnTop) {
+ changed |= WINDOW_CONFIG_ALWAYS_ON_TOP;
+ setAlwaysOnTop(delta.mAlwaysOnTop);
+ }
return changed;
}
@@ -380,10 +392,6 @@
changes |= WINDOW_CONFIG_BOUNDS;
}
- if (mFlags != other.mFlags) {
- changes |= WINDOW_CONFIG_FLAGS;
- }
-
// Make sure that one of the values is not null and that they are not equal.
if ((compareUndefined || other.mAppBounds != null)
&& mAppBounds != other.mAppBounds
@@ -401,6 +409,11 @@
changes |= WINDOW_CONFIG_ACTIVITY_TYPE;
}
+ if ((compareUndefined || other.mAlwaysOnTop != ALWAYS_ON_TOP_UNDEFINED)
+ && mAlwaysOnTop != other.mAlwaysOnTop) {
+ changes |= WINDOW_CONFIG_ALWAYS_ON_TOP;
+ }
+
return changes;
}
@@ -435,8 +448,7 @@
if (n != 0) return n;
n = mActivityType - that.mActivityType;
if (n != 0) return n;
-
- n = mFlags - that.mFlags;
+ n = mAlwaysOnTop - that.mAlwaysOnTop;
if (n != 0) return n;
// if (n != 0) return n;
@@ -465,7 +477,7 @@
result = 31 * result + mWindowingMode;
result = 31 * result + mActivityType;
- result = 31 * result + mFlags;
+ result = 31 * result + mAlwaysOnTop;
return result;
}
@@ -476,7 +488,7 @@
+ " mAppBounds=" + mAppBounds
+ " mWindowingMode=" + windowingModeToString(mWindowingMode)
+ " mActivityType=" + activityTypeToString(mActivityType)
- + " mFlags=0x" + Integer.toHexString(mFlags)
+ + " mAlwaysOnTop=" + alwaysOnTopToString(mAlwaysOnTop)
+ "}";
}
@@ -563,7 +575,7 @@
* @hide
*/
public boolean isAlwaysOnTop() {
- return mWindowingMode == WINDOWING_MODE_PINNED || (mFlags & PFLAG_ALWAYS_ON_TOP) != 0;
+ return mWindowingMode == WINDOWING_MODE_PINNED || mAlwaysOnTop == ALWAYS_ON_TOP_ON;
}
/**
@@ -640,4 +652,14 @@
}
return String.valueOf(applicationType);
}
+
+ /** @hide */
+ public static String alwaysOnTopToString(@AlwaysOnTop int alwaysOnTop) {
+ switch (alwaysOnTop) {
+ case ALWAYS_ON_TOP_UNDEFINED: return "undefined";
+ case ALWAYS_ON_TOP_ON: return "on";
+ case ALWAYS_ON_TOP_OFF: return "off";
+ }
+ return String.valueOf(alwaysOnTop);
+ }
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index ff38c1f..5e7f1e4 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3237,8 +3237,8 @@
/**
* Called by a device/profile owner to set the timeout after which unlocking with secondary, non
- * strong auth (e.g. fingerprint, trust agents) times out, i.e. the user has to use a strong
- * authentication method like password, pin or pattern.
+ * strong auth (e.g. fingerprint, face, trust agents) times out, i.e. the user has to use a
+ * strong authentication method like password, pin or pattern.
*
* <p>This timeout is used internally to reset the timer to require strong auth again after
* specified timeout each time it has been successfully used.
@@ -3710,7 +3710,6 @@
| DevicePolicyManager.KEYGUARD_DISABLE_IRIS
| DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
-
/**
* Disable all current and future keyguard customizations.
*/
@@ -4898,10 +4897,10 @@
/**
* @hide
*/
- public void reportFailedFingerprintAttempt(int userHandle) {
+ public void reportFailedBiometricAttempt(int userHandle) {
if (mService != null) {
try {
- mService.reportFailedFingerprintAttempt(userHandle);
+ mService.reportFailedBiometricAttempt(userHandle);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4911,10 +4910,10 @@
/**
* @hide
*/
- public void reportSuccessfulFingerprintAttempt(int userHandle) {
+ public void reportSuccessfulBiometricAttempt(int userHandle) {
if (mService != null) {
try {
- mService.reportSuccessfulFingerprintAttempt(userHandle);
+ mService.reportSuccessfulBiometricAttempt(userHandle);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -8300,6 +8299,22 @@
}
/**
+ * Makes all accumulated network logs available to DPC in a new batch.
+ * Only callable by ADB. If throttled, returns time to wait in milliseconds, otherwise 0.
+ * @hide
+ */
+ public long forceNetworkLogs() {
+ if (mService == null) {
+ return -1;
+ }
+ try {
+ return mService.forceNetworkLogs();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Forces a batch of security logs to be fetched from logd and makes it available for DPC.
* Only callable by ADB. If throttled, returns time to wait in milliseconds, otherwise 0.
* @hide
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 37508cd..c95bc5b 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -132,8 +132,8 @@
void reportPasswordChanged(int userId);
void reportFailedPasswordAttempt(int userHandle);
void reportSuccessfulPasswordAttempt(int userHandle);
- void reportFailedFingerprintAttempt(int userHandle);
- void reportSuccessfulFingerprintAttempt(int userHandle);
+ void reportFailedBiometricAttempt(int userHandle);
+ void reportSuccessfulBiometricAttempt(int userHandle);
void reportKeyguardDismissed(int userHandle);
void reportKeyguardSecured(int userHandle);
@@ -347,6 +347,7 @@
boolean isSecurityLoggingEnabled(in ComponentName admin);
ParceledListSlice retrieveSecurityLogs(in ComponentName admin);
ParceledListSlice retrievePreRebootSecurityLogs(in ComponentName admin);
+ long forceNetworkLogs();
long forceSecurityLogs();
boolean isUninstallInQueue(String packageName);
diff --git a/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl b/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl
new file mode 100644
index 0000000..ef2cbab
--- /dev/null
+++ b/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 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.app.timezonedetector;
+
+/**
+ * System private API to comunicate with time zone detector service.
+ *
+ * <p>Used by parts of the Android system with signals associated with the device's time zone to
+ * provide information to the Time Zone Detector Service.
+ *
+ * <p>Use the {@link android.app.timezonedetector.TimeZoneDetector} class rather than going through
+ * this Binder interface directly. See {@link android.app.timezonedetector.TimeZoneDetectorService}
+ * for more complete documentation.
+ *
+ *
+ * {@hide}
+ */
+interface ITimeZoneDetectorService {
+ void stubbedCall();
+}
diff --git a/core/java/android/app/timezonedetector/TimeZoneDetector.java b/core/java/android/app/timezonedetector/TimeZoneDetector.java
new file mode 100644
index 0000000..be3c764
--- /dev/null
+++ b/core/java/android/app/timezonedetector/TimeZoneDetector.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2018 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.app.timezonedetector;
+
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.ServiceManager.ServiceNotFoundException;
+import android.util.Log;
+
+/**
+ * The interface through which system components can send signals to the TimeZoneDetectorService.
+ * @hide
+ */
+@SystemService(Context.TIME_ZONE_DETECTOR_SERVICE)
+public final class TimeZoneDetector {
+
+ private static final String TAG = "timezonedetector.TimeZoneDetector";
+ private static final boolean DEBUG = false;
+
+ private final ITimeZoneDetectorService mITimeZoneDetectorService;
+
+ public TimeZoneDetector() throws ServiceNotFoundException {
+ mITimeZoneDetectorService = ITimeZoneDetectorService.Stub.asInterface(
+ ServiceManager.getServiceOrThrow(Context.TIME_ZONE_DETECTOR_SERVICE));
+
+ }
+ /**
+ * Does nothing.
+ * TODO: Remove this when the service implementation is built out.
+ */
+ public void stubbedCall() {
+ if (DEBUG) {
+ Log.d(TAG, "stubbedCall called");
+ }
+ try {
+ mITimeZoneDetectorService.stubbedCall();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+}
diff --git a/core/java/android/app/trust/ITrustManager.aidl b/core/java/android/app/trust/ITrustManager.aidl
index 6d65e3e..9985cc0 100644
--- a/core/java/android/app/trust/ITrustManager.aidl
+++ b/core/java/android/app/trust/ITrustManager.aidl
@@ -17,6 +17,7 @@
package android.app.trust;
import android.app.trust.ITrustListener;
+import android.hardware.biometrics.BiometricSourceType;
/**
* System private API to comunicate with trust service.
@@ -34,6 +35,6 @@
boolean isDeviceLocked(int userId);
boolean isDeviceSecure(int userId);
boolean isTrustUsuallyManaged(int userId);
- void unlockedByFingerprintForUser(int userId);
- void clearAllFingerprints();
+ void unlockedByBiometricForUser(int userId, in BiometricSourceType source);
+ void clearAllBiometricRecognized(in BiometricSourceType target);
}
diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java
index 8ab0b70..fb27bed 100644
--- a/core/java/android/app/trust/TrustManager.java
+++ b/core/java/android/app/trust/TrustManager.java
@@ -20,6 +20,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.content.Context;
+import android.hardware.biometrics.BiometricSourceType;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -195,26 +196,28 @@
}
/**
- * Updates the trust state for the user due to the user unlocking via fingerprint.
- * Should only be called if user authenticated via fingerprint and bouncer can be skipped.
+ * Updates the trust state for the user due to the user unlocking via a biometric sensor.
+ * Should only be called if user authenticated via fingerprint, face, or iris and bouncer
+ * can be skipped.
+ *
* @param userId
*/
@RequiresPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE)
- public void unlockedByFingerprintForUser(int userId) {
+ public void unlockedByBiometricForUser(int userId, BiometricSourceType source) {
try {
- mService.unlockedByFingerprintForUser(userId);
+ mService.unlockedByBiometricForUser(userId, source);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Clears authenticated fingerprints for all users.
+ * Clears authentication by the specified biometric type for all users.
*/
@RequiresPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE)
- public void clearAllFingerprints() {
+ public void clearAllBiometricRecognized(BiometricSourceType source) {
try {
- mService.clearAllFingerprints();
+ mService.clearAllBiometricRecognized(source);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index c0cfb90..c515bce 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3005,6 +3005,7 @@
NSD_SERVICE,
AUDIO_SERVICE,
FINGERPRINT_SERVICE,
+ //@hide: FACE_SERVICE,
MEDIA_ROUTER_SERVICE,
TELEPHONY_SERVICE,
TELEPHONY_SUBSCRIPTION_SERVICE,
@@ -3060,6 +3061,7 @@
CROSS_PROFILE_APPS_SERVICE,
//@hide: SYSTEM_UPDATE_SERVICE,
//@hide: TIME_DETECTOR_SERVICE,
+ //@hide: TIME_ZONE_DETECTOR_SERVICE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ServiceName {}
@@ -3652,6 +3654,18 @@
/**
* Use with {@link #getSystemService(String)} to retrieve a
+ * Use with {@link #getSystemService} to retrieve a
+ * {@link android.hardware.face.FaceManager} for handling management
+ * of face authentication.
+ *
+ * @hide
+ * @see #getSystemService
+ * @see android.hardware.face.FaceManager
+ */
+ public static final String FACE_SERVICE = "face";
+
+ /**
+ * Use with {@link #getSystemService} to retrieve a
* {@link android.media.MediaRouter} for controlling and managing
* routing of media.
*
@@ -4231,6 +4245,15 @@
public static final String TIME_DETECTOR_SERVICE = "time_detector";
/**
+ * Use with {@link #getSystemService(String)} to retrieve an
+ * {@link android.app.timezonedetector.ITimeZoneDetectorService}.
+ * @hide
+ *
+ * @see #getSystemService(String)
+ */
+ public static final String TIME_ZONE_DETECTOR_SERVICE = "time_zone_detector";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 631c4b7..78738e9 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -5372,19 +5372,23 @@
public static final int FLAG_GRANT_PREFIX_URI_PERMISSION = 0x00000080;
/**
- * Internal flag used to indicate that a system component has done their
- * homework and verified that they correctly handle packages and components
- * that come and go over time. In particular:
- * <ul>
- * <li>Apps installed on external storage, which will appear to be
- * uninstalled while the the device is ejected.
- * <li>Apps with encryption unaware components, which will appear to not
- * exist while the device is locked.
- * </ul>
- *
- * @hide
+ * Flag used to automatically match intents based on their Direct Boot
+ * awareness and the current user state.
+ * <p>
+ * Since the default behavior is to automatically apply the current user
+ * state, this is effectively a sentinel value that doesn't change the
+ * output of any queries based on its presence or absence.
+ * <p>
+ * Instead, this value can be useful in conjunction with
+ * {@link android.os.StrictMode.VmPolicy.Builder#detectImplicitDirectBoot()}
+ * to detect when a caller is relying on implicit automatic matching,
+ * instead of confirming the explicit behavior they want.
*/
- public static final int FLAG_DEBUG_TRIAGED_MISSING = 0x00000100;
+ public static final int FLAG_DIRECT_BOOT_AUTO = 0x00000100;
+
+ /** {@hide} */
+ @Deprecated
+ public static final int FLAG_DEBUG_TRIAGED_MISSING = FLAG_DIRECT_BOOT_AUTO;
/**
* Internal flag used to indicate ephemeral applications should not be
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index d65e051..3120421 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1120,6 +1120,9 @@
/** @hide */
public String[] splitClassLoaderNames;
+ /** @hide */
+ public boolean hiddenUntilInstalled;
+
/**
* Represents the default policy. The actual policy used will depend on other properties of
* the application, e.g. the target SDK version.
@@ -1460,6 +1463,7 @@
compileSdkVersion = orig.compileSdkVersion;
compileSdkVersionCodename = orig.compileSdkVersionCodename;
mHiddenApiPolicy = orig.mHiddenApiPolicy;
+ hiddenUntilInstalled = orig.hiddenUntilInstalled;
}
public String toString() {
@@ -1534,6 +1538,7 @@
dest.writeString(compileSdkVersionCodename);
dest.writeString(appComponentFactory);
dest.writeInt(mHiddenApiPolicy);
+ dest.writeInt(hiddenUntilInstalled ? 1 : 0);
}
public static final Parcelable.Creator<ApplicationInfo> CREATOR
@@ -1605,6 +1610,7 @@
compileSdkVersionCodename = source.readString();
appComponentFactory = source.readString();
mHiddenApiPolicy = source.readInt();
+ hiddenUntilInstalled = source.readInt() != 0;
}
/**
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index c988fa9..bc5b32c 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -598,6 +598,9 @@
boolean setApplicationHiddenSettingAsUser(String packageName, boolean hidden, int userId);
boolean getApplicationHiddenSettingAsUser(String packageName, int userId);
+ void setSystemAppHiddenUntilInstalled(String packageName, boolean hidden);
+ boolean setSystemAppInstallState(String packageName, boolean installed, int userId);
+
IPackageInstaller getPackageInstaller();
boolean setBlockUninstallForUser(String packageName, boolean blockUninstall, int userId);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 43b6984..721063a 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -147,6 +147,7 @@
GET_DISABLED_COMPONENTS,
GET_DISABLED_UNTIL_USED_COMPONENTS,
GET_UNINSTALLED_PACKAGES,
+ MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
})
@Retention(RetentionPolicy.SOURCE)
public @interface PackageInfoFlags {}
@@ -164,6 +165,7 @@
MATCH_STATIC_SHARED_LIBRARIES,
GET_DISABLED_UNTIL_USED_COMPONENTS,
GET_UNINSTALLED_PACKAGES,
+ MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ApplicationInfoFlags {}
@@ -177,6 +179,7 @@
MATCH_DEFAULT_ONLY,
MATCH_DISABLED_COMPONENTS,
MATCH_DISABLED_UNTIL_USED_COMPONENTS,
+ MATCH_DIRECT_BOOT_AUTO,
MATCH_DIRECT_BOOT_AWARE,
MATCH_DIRECT_BOOT_UNAWARE,
MATCH_SYSTEM_ONLY,
@@ -200,6 +203,7 @@
MATCH_DISABLED_COMPONENTS,
MATCH_DISABLED_UNTIL_USED_COMPONENTS,
MATCH_DEFAULT_ONLY,
+ MATCH_DIRECT_BOOT_AUTO,
MATCH_DIRECT_BOOT_AWARE,
MATCH_DIRECT_BOOT_UNAWARE,
MATCH_SYSTEM_ONLY,
@@ -504,22 +508,35 @@
public static final int GET_SIGNING_CERTIFICATES = 0x08000000;
/**
- * Internal flag used to indicate that a system component has done their
- * homework and verified that they correctly handle packages and components
- * that come and go over time. In particular:
+ * Querying flag: automatically match components based on their Direct Boot
+ * awareness and the current user state.
+ * <p>
+ * Since the default behavior is to automatically apply the current user
+ * state, this is effectively a sentinel value that doesn't change the
+ * output of any queries based on its presence or absence.
+ * <p>
+ * Instead, this value can be useful in conjunction with
+ * {@link android.os.StrictMode.VmPolicy.Builder#detectImplicitDirectBoot()}
+ * to detect when a caller is relying on implicit automatic matching,
+ * instead of confirming the explicit behavior they want, using a
+ * combination of these flags:
* <ul>
- * <li>Apps installed on external storage, which will appear to be
- * uninstalled while the the device is ejected.
- * <li>Apps with encryption unaware components, which will appear to not
- * exist while the device is locked.
+ * <li>{@link #MATCH_DIRECT_BOOT_AWARE}
+ * <li>{@link #MATCH_DIRECT_BOOT_UNAWARE}
+ * <li>{@link #MATCH_DIRECT_BOOT_AUTO}
* </ul>
- *
- * @see #MATCH_UNINSTALLED_PACKAGES
- * @see #MATCH_DIRECT_BOOT_AWARE
- * @see #MATCH_DIRECT_BOOT_UNAWARE
+ */
+ public static final int MATCH_DIRECT_BOOT_AUTO = 0x10000000;
+
+ /** @hide */
+ @Deprecated
+ public static final int MATCH_DEBUG_TRIAGED_MISSING = MATCH_DIRECT_BOOT_AUTO;
+
+ /**
+ * Internal flag used to indicate that a package is a hidden system app.
* @hide
*/
- public static final int MATCH_DEBUG_TRIAGED_MISSING = 0x10000000;
+ public static final int MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS = 0x20000000;
/**
* Flag for {@link #addCrossProfileIntentFilter}: if this flag is set: when
@@ -2245,12 +2262,20 @@
/**
* Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device has biometric hardware to detect a fingerprint.
- */
+ */
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_FINGERPRINT = "android.hardware.fingerprint";
/**
* Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device has biometric hardware to perform face authentication.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_FACE = "android.hardware.face";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device supports portrait orientation
* screens. For backwards compatibility, you can assume that if neither
* this nor {@link #FEATURE_SCREEN_LANDSCAPE} is set then the device supports
@@ -4847,7 +4872,8 @@
* on the system for other users, also install it for the specified user.
* @hide
*/
- @RequiresPermission(anyOf = {
+ @RequiresPermission(anyOf = {
+ Manifest.permission.INSTALL_EXISTING_PACKAGES,
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.INTERACT_ACROSS_USERS_FULL})
public abstract int installExistingPackageAsUser(String packageName, @UserIdInt int userId)
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 950070e..54d383a 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -646,11 +646,19 @@
*/
private static boolean checkUseInstalledOrHidden(int flags, PackageUserState state,
ApplicationInfo appInfo) {
+ // Returns false if the package is hidden system app until installed.
+ if ((flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) == 0
+ && !state.installed
+ && appInfo != null && appInfo.hiddenUntilInstalled) {
+ return false;
+ }
+
// If available for the target user, or trying to match uninstalled packages and it's
// a system app.
return state.isAvailable(flags)
|| (appInfo != null && appInfo.isSystemApp()
- && (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0);
+ && ((flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0
+ || (flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) != 0));
}
public static boolean isAvailable(PackageUserState state) {
@@ -2206,10 +2214,10 @@
com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion);
if (val != null) {
if (val.type == TypedValue.TYPE_STRING && val.string != null) {
- targetCode = minCode = val.string.toString();
+ minCode = val.string.toString();
} else {
// If it's not a string, it's an integer.
- targetVers = minVers = val.data;
+ minVers = val.data;
}
}
@@ -2225,6 +2233,9 @@
// If it's not a string, it's an integer.
targetVers = val.data;
}
+ } else {
+ targetVers = minVers;
+ targetCode = minCode;
}
sa.recycle();
@@ -3097,6 +3108,14 @@
0);
perm.info.requestRes = sa.getResourceId(
com.android.internal.R.styleable.AndroidManifestPermissionGroup_request, 0);
+ perm.info.requestDetailResourceId = sa.getResourceId(
+ com.android.internal.R.styleable.AndroidManifestPermissionGroup_requestDetail, 0);
+ perm.info.backgroundRequestResourceId = sa.getResourceId(
+ com.android.internal.R.styleable.AndroidManifestPermissionGroup_backgroundRequest,
+ 0);
+ perm.info.backgroundRequestDetailResourceId = sa.getResourceId(
+ com.android.internal.R.styleable
+ .AndroidManifestPermissionGroup_backgroundRequestDetail, 0);
perm.info.flags = sa.getInt(
com.android.internal.R.styleable.AndroidManifestPermissionGroup_permissionGroupFlags, 0);
perm.info.priority = sa.getInt(
@@ -3151,6 +3170,19 @@
perm.info.requestRes = sa.getResourceId(
com.android.internal.R.styleable.AndroidManifestPermission_request, 0);
+ if (sa.hasValue(
+ com.android.internal.R.styleable.AndroidManifestPermission_backgroundPermission)) {
+ if ("android".equals(owner.packageName)) {
+ perm.info.backgroundPermission = sa.getNonResourceString(
+ com.android.internal.R.styleable
+ .AndroidManifestPermission_backgroundPermission);
+ } else {
+ Slog.w(TAG, owner.packageName + " defines permission '" + perm.info.name
+ + "' with a background permission. Only the 'android' package can do "
+ + "that.");
+ }
+ }
+
perm.info.protectionLevel = sa.getInt(
com.android.internal.R.styleable.AndroidManifestPermission_protectionLevel,
PermissionInfo.PROTECTION_NORMAL);
diff --git a/core/java/android/content/pm/PermissionGroupInfo.java b/core/java/android/content/pm/PermissionGroupInfo.java
index 7c4478d..8cf66d8 100644
--- a/core/java/android/content/pm/PermissionGroupInfo.java
+++ b/core/java/android/content/pm/PermissionGroupInfo.java
@@ -45,6 +45,42 @@
public @StringRes int requestRes;
/**
+ * A string resource identifier (in the package's resources) used as subtitle when requesting
+ * only access while in the foreground.
+ *
+ * From the "requestDetail" attribute or, if not set, {@link
+ * android.content.res.ResourceId#ID_NULL}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public @StringRes int requestDetailResourceId;
+
+ /**
+ * A string resource identifier (in the package's resources) used when requesting background
+ * access. Also used when requesting both foreground and background access.
+ *
+ * From the "backgroundRequest" attribute or, if not set, {@link
+ * android.content.res.ResourceId#ID_NULL}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public @StringRes int backgroundRequestResourceId;
+
+ /**
+ * A string resource identifier (in the package's resources) used as subtitle when requesting
+ * background access.
+ *
+ * From the "backgroundRequestDetail" attribute or, if not set, {@link
+ * android.content.res.ResourceId#ID_NULL}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public @StringRes int backgroundRequestDetailResourceId;
+
+ /**
* The description string provided in the AndroidManifest file, if any. You
* probably don't want to use this, since it will be null if the description
* is in a resource. You probably want
@@ -76,6 +112,9 @@
super(orig);
descriptionRes = orig.descriptionRes;
requestRes = orig.requestRes;
+ requestDetailResourceId = orig.requestDetailResourceId;
+ backgroundRequestResourceId = orig.backgroundRequestResourceId;
+ backgroundRequestDetailResourceId = orig.backgroundRequestDetailResourceId;
nonLocalizedDescription = orig.nonLocalizedDescription;
flags = orig.flags;
priority = orig.priority;
@@ -119,6 +158,9 @@
super.writeToParcel(dest, parcelableFlags);
dest.writeInt(descriptionRes);
dest.writeInt(requestRes);
+ dest.writeInt(requestDetailResourceId);
+ dest.writeInt(backgroundRequestResourceId);
+ dest.writeInt(backgroundRequestDetailResourceId);
TextUtils.writeToParcel(nonLocalizedDescription, dest, parcelableFlags);
dest.writeInt(flags);
dest.writeInt(priority);
@@ -138,6 +180,9 @@
super(source);
descriptionRes = source.readInt();
requestRes = source.readInt();
+ requestDetailResourceId = source.readInt();
+ backgroundRequestResourceId = source.readInt();
+ backgroundRequestDetailResourceId = source.readInt();
nonLocalizedDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
flags = source.readInt();
priority = source.readInt();
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index 938409a..535ef00 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -285,6 +285,21 @@
public int requestRes;
/**
+ * Some permissions only grant access while the app is in foreground. Some of these permissions
+ * allow to add background capabilities by adding another permission.
+ *
+ * If this is such a permission, this is the name of the permission adding the background
+ * access.
+ *
+ * From the "backgroundPermission" attribute or, if not set null
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public String backgroundPermission;
+
+ /**
* The description string provided in the AndroidManifest file, if any. You
* probably don't want to use this, since it will be null if the description
* is in a resource. You probably want
@@ -373,6 +388,7 @@
protectionLevel = orig.protectionLevel;
flags = orig.flags;
group = orig.group;
+ backgroundPermission = orig.backgroundPermission;
descriptionRes = orig.descriptionRes;
requestRes = orig.requestRes;
nonLocalizedDescription = orig.nonLocalizedDescription;
@@ -436,6 +452,7 @@
dest.writeInt(protectionLevel);
dest.writeInt(flags);
dest.writeString(group);
+ dest.writeString(backgroundPermission);
dest.writeInt(descriptionRes);
dest.writeInt(requestRes);
TextUtils.writeToParcel(nonLocalizedDescription, dest, parcelableFlags);
@@ -475,6 +492,7 @@
protectionLevel = source.readInt();
flags = source.readInt();
group = source.readString();
+ backgroundPermission = source.readString();
descriptionRes = source.readInt();
requestRes = source.readInt();
nonLocalizedDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 9350aab..22e1f45 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -571,9 +571,7 @@
/**
* An empty Camera for testing purpose.
*/
- Camera() {
- initAppOps();
- }
+ Camera() {}
private void initAppOps() {
IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
diff --git a/core/java/android/hardware/biometrics/BiometricAuthenticator.java b/core/java/android/hardware/biometrics/BiometricAuthenticator.java
index c811999..e7c5116 100644
--- a/core/java/android/hardware/biometrics/BiometricAuthenticator.java
+++ b/core/java/android/hardware/biometrics/BiometricAuthenticator.java
@@ -33,7 +33,50 @@
* Container for biometric data
* @hide
*/
- abstract class BiometricIdentifier implements Parcelable {}
+ abstract class Identifier implements Parcelable {
+ private CharSequence mName;
+ private int mBiometricId;
+ private long mDeviceId; // physical device this is associated with
+
+ public Identifier() {}
+
+ public Identifier(CharSequence name, int biometricId, long deviceId) {
+ mName = name;
+ mBiometricId = biometricId;
+ mDeviceId = deviceId;
+ }
+
+ /**
+ * Gets the human-readable name for the given biometric.
+ * @return name given to the biometric
+ */
+ public CharSequence getName() {
+ return mName;
+ }
+
+ /**
+ * Gets the device-specific biometric id. Used by Settings to map a name to a specific
+ * biometric template.
+ */
+ public int getBiometricId() {
+ return mBiometricId;
+ }
+
+ /**
+ * Device this biometric belongs to.
+ */
+ public long getDeviceId() {
+ return mDeviceId;
+ }
+
+ public void setName(CharSequence name) {
+ mName = name;
+ }
+
+ public void setDeviceId(long deviceId) {
+ mDeviceId = deviceId;
+ }
+ }
/**
* Container for callback data from {@link BiometricAuthenticator#authenticate(
@@ -42,7 +85,7 @@
* AuthenticationCallback)}
*/
class AuthenticationResult {
- private BiometricIdentifier mIdentifier;
+ private Identifier mIdentifier;
private CryptoObject mCryptoObject;
private int mUserId;
@@ -58,7 +101,7 @@
* @param userId
* @hide
*/
- public AuthenticationResult(CryptoObject crypto, BiometricIdentifier identifier,
+ public AuthenticationResult(CryptoObject crypto, Identifier identifier,
int userId) {
mCryptoObject = crypto;
mIdentifier = identifier;
@@ -80,7 +123,7 @@
* operations.
* @hide
*/
- public BiometricIdentifier getId() {
+ public Identifier getId() {
return mIdentifier;
}
diff --git a/core/java/android/hardware/biometrics/BiometricFaceConstants.java b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
new file mode 100644
index 0000000..008601c
--- /dev/null
+++ b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2018 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.biometrics;
+
+import android.hardware.face.FaceManager;
+
+/**
+ * Interface containing all of the face-specific constants.
+ * @hide
+ */
+public interface BiometricFaceConstants {
+ //
+ // Error messages from face authentication hardware during initialization, enrollment,
+ // authentication or removal. Must agree with the list in HAL h file
+ //
+ /**
+ * The hardware is unavailable. Try again later.
+ */
+ public static final int FACE_ERROR_HW_UNAVAILABLE = 1;
+ /**
+ * Error state returned when the sensor was unable to process the current image.
+ */
+ public static final int FACE_ERROR_UNABLE_TO_PROCESS = 2;
+ /**
+ * Error state returned when the current request has been running too long. This is intended to
+ * prevent programs from waiting for the face authentication sensor indefinitely. The timeout is
+ * platform and sensor-specific, but is generally on the order of 30 seconds.
+ */
+ public static final int FACE_ERROR_TIMEOUT = 3;
+ /**
+ * Error state returned for operations like enrollment; the operation cannot be completed
+ * because there's not enough storage remaining to complete the operation.
+ */
+ public static final int FACE_ERROR_NO_SPACE = 4;
+ /**
+ * The operation was canceled because the face authentication sensor is unavailable. For
+ * example, this may happen when the user is switched, the device is locked or another pending
+ * operation prevents or disables it.
+ */
+ public static final int FACE_ERROR_CANCELED = 5;
+ /**
+ * The {@link FaceManager#remove} call failed. Typically this will happen when the
+ * provided face id was incorrect.
+ *
+ * @hide
+ */
+ public static final int FACE_ERROR_UNABLE_TO_REMOVE = 6;
+ /**
+ * The operation was canceled because the API is locked out due to too many attempts.
+ * This occurs after 5 failed attempts, and lasts for 30 seconds.
+ */
+ public static final int FACE_ERROR_LOCKOUT = 7;
+ /**
+ * Hardware vendors may extend this list if there are conditions that do not fall under one of
+ * the above categories. Vendors are responsible for providing error strings for these errors.
+ * These messages are typically reserved for internal operations such as enrollment, but may be
+ * used to express vendor errors not covered by the ones in HAL h file. Applications are
+ * expected to show the error message string if they happen, but are advised not to rely on the
+ * message id since they will be device and vendor-specific
+ */
+ public static final int FACE_ERROR_VENDOR = 8;
+
+ /**
+ * The operation was canceled because FACE_ERROR_LOCKOUT occurred too many times.
+ * Face authentication is disabled until the user unlocks with strong authentication
+ * (PIN/Pattern/Password)
+ */
+ public static final int FACE_ERROR_LOCKOUT_PERMANENT = 9;
+ /**
+ * The user canceled the operation. Upon receiving this, applications should use alternate
+ * authentication (e.g. a password). The application should also provide the means to return
+ * to face authentication, such as a "use face authentication" button.
+ */
+ public static final int FACE_ERROR_USER_CANCELED = 10;
+ /**
+ * The user does not have a face enrolled.
+ */
+ public static final int FACE_ERROR_NOT_ENROLLED = 11;
+ /**
+ * The device does not have a face sensor. This message will propagate if the calling app
+ * ignores the result from PackageManager.hasFeature(FEATURE_FACE) and calls
+ * this API anyway. Apps should always check for the feature before calling this API.
+ */
+ public static final int FACE_ERROR_HW_NOT_PRESENT = 12;
+ /**
+ * @hide
+ */
+ public static final int FACE_ERROR_VENDOR_BASE = 1000;
+
+ //
+ // Image acquisition messages. These will not be sent to the user, since they conflict with
+ // existing constants. These must agree with face@1.0/types.hal.
+ //
+
+ /**
+ * The image acquired was good.
+ */
+ public static final int FACE_ACQUIRED_GOOD = 0;
+
+ /**
+ * The face image was not good enough to process due to a detected condition.
+ * (See {@link #FACE_ACQUIRED_TOO_BRIGHT or @link #FACE_ACQUIRED_TOO_DARK}).
+ */
+ public static final int FACE_ACQUIRED_INSUFFICIENT = 1;
+
+ /**
+ * The face image was too bright due to too much ambient light.
+ * For example, it's reasonable to return this after multiple
+ * {@link #FACE_ACQUIRED_INSUFFICIENT}
+ * The user is expected to take action to retry in better lighting conditions
+ * when this is returned.
+ */
+ public static final int FACE_ACQUIRED_TOO_BRIGHT = 2;
+
+ /**
+ * The face image was too dark due to illumination light obscured.
+ * For example, it's reasonable to return this after multiple
+ * {@link #FACE_ACQUIRED_INSUFFICIENT}
+ * The user is expected to take action to retry in better lighting conditions
+ * when this is returned.
+ */
+ public static final int FACE_ACQUIRED_TOO_DARK = 3;
+
+ /**
+ * The detected face is too close to the sensor, and the image can't be processed.
+ * The user should be informed to move farther from the sensor when this is returned.
+ */
+ public static final int FACE_ACQUIRED_TOO_CLOSE = 4;
+
+ /**
+ * The detected face is too small, as the user might be too far from the sensor.
+ * The user should be informed to move closer to the sensor when this is returned.
+ */
+ public static final int FACE_ACQUIRED_TOO_FAR = 5;
+
+ /**
+ * Only the upper part of the face was detected. The sensor field of view is too high.
+ * The user should be informed to move up with respect to the sensor when this is returned.
+ */
+ public static final int FACE_ACQUIRED_TOO_HIGH = 6;
+
+ /**
+ * Only the lower part of the face was detected. The sensor field of view is too low.
+ * The user should be informed to move down with respect to the sensor when this is returned.
+ */
+ public static final int FACE_ACQUIRED_TOO_LOW = 7;
+
+ /**
+ * Only the right part of the face was detected. The sensor field of view is too far right.
+ * The user should be informed to move to the right with respect to the sensor
+ * when this is returned.
+ */
+ public static final int FACE_ACQUIRED_TOO_RIGHT = 8;
+
+ /**
+ * Only the left part of the face was detected. The sensor field of view is too far left.
+ * The user should be informed to move to the left with respect to the sensor
+ * when this is returned.
+ */
+ public static final int FACE_ACQUIRED_TOO_LEFT = 9;
+
+ /**
+ * The user's eyes have strayed away from the sensor. If this message is sent, the user should
+ * be informed to look at the device. If the user can't be found in the frame, one of the other
+ * acquisition messages should be sent, e.g. FACE_ACQUIRED_NOT_DETECTED.
+ */
+ public static final int FACE_ACQUIRED_POOR_GAZE = 10;
+
+ /**
+ * No face was detected in front of the sensor.
+ * The user should be informed to point the sensor to a face when this is returned.
+ */
+ public static final int FACE_ACQUIRED_NOT_DETECTED = 11;
+
+ /**
+ * Too much motion was detected.
+ * The user should be informed to keep their face steady relative to the
+ * sensor.
+ */
+ public static final int FACE_ACQUIRED_TOO_MUCH_MOTION = 12;
+
+ /**
+ * The sensor needs to be re-calibrated. This is an unexpected condition, and should only be
+ * sent if a serious, uncorrectable, and unrecoverable calibration issue is detected which
+ * requires user intervention, e.g. re-enrolling. The expected response to this message is to
+ * direct the user to re-enroll.
+ */
+ public static final int FACE_ACQUIRED_RECALIBRATE = 13;
+
+ /**
+ * Hardware vendors may extend this list if there are conditions that do not fall under one of
+ * the above categories. Vendors are responsible for providing error strings for these errors.
+ *
+ * @hide
+ */
+ public static final int FACE_ACQUIRED_VENDOR = 13;
+ /**
+ * @hide
+ */
+ public static final int FACE_ACQUIRED_VENDOR_BASE = 1000;
+}
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 1c9de45..bad418a 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -293,7 +293,7 @@
* @param userId
* @hide
*/
- public AuthenticationResult(CryptoObject crypto, BiometricIdentifier identifier,
+ public AuthenticationResult(CryptoObject crypto, Identifier identifier,
int userId) {
super(crypto, identifier, userId);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionCategory.java b/core/java/android/hardware/biometrics/BiometricSourceType.aidl
similarity index 65%
rename from packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionCategory.java
rename to core/java/android/hardware/biometrics/BiometricSourceType.aidl
index 19e556a..15440d8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionCategory.java
+++ b/core/java/android/hardware/biometrics/BiometricSourceType.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2018 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.
@@ -14,12 +14,9 @@
* limitations under the License.
*/
-package com.android.settingslib.suggestions;
+package android.hardware.biometrics;
-public class SuggestionCategory {
- public String category;
- public String pkg;
- public boolean multiple;
- public boolean exclusive;
- public long exclusiveExpireDaysInMillis;
-}
+/**
+ * @hide
+ */
+parcelable BiometricSourceType;
\ No newline at end of file
diff --git a/core/java/android/hardware/biometrics/BiometricSourceType.java b/core/java/android/hardware/biometrics/BiometricSourceType.java
new file mode 100644
index 0000000..4a08cf2
--- /dev/null
+++ b/core/java/android/hardware/biometrics/BiometricSourceType.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 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.biometrics;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+public enum BiometricSourceType implements Parcelable {
+ FINGERPRINT,
+ FACE,
+ IRIS;
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(name());
+ }
+
+ public static final Creator<BiometricSourceType> CREATOR = new Creator<BiometricSourceType>() {
+ @Override
+ public BiometricSourceType createFromParcel(final Parcel source) {
+ return BiometricSourceType.valueOf(source.readString());
+ }
+
+ @Override
+ public BiometricSourceType[] newArray(final int size) {
+ return new BiometricSourceType[size];
+ }
+ };
+}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl b/core/java/android/hardware/biometrics/IBiometricServiceLockoutResetCallback.aidl
similarity index 81%
rename from core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl
rename to core/java/android/hardware/biometrics/IBiometricServiceLockoutResetCallback.aidl
index 971e14c..ee033bf 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricServiceLockoutResetCallback.aidl
@@ -13,18 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.hardware.fingerprint;
+package android.hardware.biometrics;
-import android.hardware.fingerprint.Fingerprint;
-import android.os.Bundle;
import android.os.IRemoteCallback;
-import android.os.UserHandle;
/**
* Callback when lockout period expired and clients are allowed to authenticate again.
* @hide
*/
-oneway interface IFingerprintServiceLockoutResetCallback {
+oneway interface IBiometricServiceLockoutResetCallback {
/**
* A wakelock will be held until the reciever calls back into {@param callback}
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 87c64cd..32c6898 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -2365,13 +2365,25 @@
* {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, is defined relative to the active array rectangle given in
* this field, with <code>(0, 0)</code> being the top-left of this rectangle.</p>
* <p>The active array may be smaller than the full pixel array, since the full array may
- * include black calibration pixels or other inactive regions, and geometric correction
- * resulting in scaling or cropping may have been applied.</p>
+ * include black calibration pixels or other inactive regions.</p>
+ * <p>For devices that do not support {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the active
+ * array must be the same as {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.</p>
+ * <p>For devices that support {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the active array must
+ * be enclosed by {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}. The difference between
+ * pre-correction active array and active array accounts for scaling or cropping caused
+ * by lens geometric distortion correction.</p>
+ * <p>In general, application should always refer to active array size for controls like
+ * metering regions or crop region. Two exceptions are when the application is dealing with
+ * RAW image buffers (RAW_SENSOR, RAW10, RAW12 etc), or when application explicitly set
+ * {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} to OFF. In these cases, application should refer
+ * to {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.</p>
* <p><b>Units</b>: Pixel coordinates on the image sensor</p>
* <p>This key is available on all devices.</p>
*
+ * @see CaptureRequest#DISTORTION_CORRECTION_MODE
* @see CaptureRequest#SCALER_CROP_REGION
* @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE
+ * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
*/
@PublicKey
public static final Key<android.graphics.Rect> SENSOR_INFO_ACTIVE_ARRAY_SIZE =
@@ -2616,9 +2628,9 @@
* <ol>
* <li>{@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion}.</li>
* </ol>
- * <p>If all of the geometric distortion fields are no-ops, this rectangle will be the same
- * as the post-distortion-corrected rectangle given in
- * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</p>
+ * <p>If the camera device doesn't support geometric distortion correction, or all of the
+ * geometric distortion fields are no-ops, this rectangle will be the same as the
+ * post-distortion-corrected rectangle given in {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</p>
* <p>This rectangle is defined relative to the full pixel array; (0,0) is the top-left of
* the full pixel array, and the size of the full pixel array is given by
* {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize}.</p>
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 411a97e..aca77a5 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1269,11 +1269,26 @@
* Otherwise will always be present.</p>
* <p>The maximum number of regions supported by the device is determined by the value
* of {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AE android.control.maxRegionsAe}.</p>
- * <p>The coordinate system is based on the active pixel array,
- * with (0,0) being the top-left pixel in the active pixel array, and
+ * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+ * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with (0,0) being
+ * the top-left pixel in the active pixel array, and
* ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
- * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the
- * bottom-right pixel in the active pixel array.</p>
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the
+ * active pixel array.</p>
+ * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+ * system depends on the mode being set.
+ * When the distortion correction mode is OFF, the coordinate system follows
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with
+ * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array, and
+ * ({@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.width - 1,
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.height - 1) being the bottom-right
+ * pixel in the pre-correction active pixel array.
+ * When the distortion correction mode is not OFF, the coordinate system follows
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
+ * <code>(0, 0)</code> being the top-left pixel of the active array, and
+ * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the
+ * active pixel array.</p>
* <p>The weight must be within <code>[0, 1000]</code>, and represents a weight
* for every pixel in the area. This means that a large metering area
* with the same weight as a smaller area will have more effect in
@@ -1289,15 +1304,20 @@
* region and output only the intersection rectangle as the metering region in the result
* metadata. If the region is entirely outside the crop region, it will be ignored and
* not reported in the result metadata.</p>
- * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p>
+ * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on
+ * distortion correction capability and mode</p>
* <p><b>Range of valid values:</b><br>
* Coordinates must be between <code>[(0,0), (width, height))</code> of
- * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p>
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}
+ * depending on distortion correction capability and mode</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
* @see CameraCharacteristics#CONTROL_MAX_REGIONS_AE
+ * @see CaptureRequest#DISTORTION_CORRECTION_MODE
* @see CaptureRequest#SCALER_CROP_REGION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
*/
@PublicKey
public static final Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AE_REGIONS =
@@ -1443,11 +1463,26 @@
* Otherwise will always be present.</p>
* <p>The maximum number of focus areas supported by the device is determined by the value
* of {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AF android.control.maxRegionsAf}.</p>
- * <p>The coordinate system is based on the active pixel array,
- * with (0,0) being the top-left pixel in the active pixel array, and
+ * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+ * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with (0,0) being
+ * the top-left pixel in the active pixel array, and
* ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
- * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the
- * bottom-right pixel in the active pixel array.</p>
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the
+ * active pixel array.</p>
+ * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+ * system depends on the mode being set.
+ * When the distortion correction mode is OFF, the coordinate system follows
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with
+ * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array, and
+ * ({@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.width - 1,
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.height - 1) being the bottom-right
+ * pixel in the pre-correction active pixel array.
+ * When the distortion correction mode is not OFF, the coordinate system follows
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
+ * <code>(0, 0)</code> being the top-left pixel of the active array, and
+ * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the
+ * active pixel array.</p>
* <p>The weight must be within <code>[0, 1000]</code>, and represents a weight
* for every pixel in the area. This means that a large metering area
* with the same weight as a smaller area will have more effect in
@@ -1464,15 +1499,20 @@
* region and output only the intersection rectangle as the metering region in the result
* metadata. If the region is entirely outside the crop region, it will be ignored and
* not reported in the result metadata.</p>
- * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p>
+ * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on
+ * distortion correction capability and mode</p>
* <p><b>Range of valid values:</b><br>
* Coordinates must be between <code>[(0,0), (width, height))</code> of
- * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p>
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}
+ * depending on distortion correction capability and mode</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
* @see CameraCharacteristics#CONTROL_MAX_REGIONS_AF
+ * @see CaptureRequest#DISTORTION_CORRECTION_MODE
* @see CaptureRequest#SCALER_CROP_REGION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
*/
@PublicKey
public static final Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AF_REGIONS =
@@ -1612,11 +1652,26 @@
* Otherwise will always be present.</p>
* <p>The maximum number of regions supported by the device is determined by the value
* of {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AWB android.control.maxRegionsAwb}.</p>
- * <p>The coordinate system is based on the active pixel array,
- * with (0,0) being the top-left pixel in the active pixel array, and
+ * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+ * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with (0,0) being
+ * the top-left pixel in the active pixel array, and
* ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
- * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the
- * bottom-right pixel in the active pixel array.</p>
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the
+ * active pixel array.</p>
+ * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+ * system depends on the mode being set.
+ * When the distortion correction mode is OFF, the coordinate system follows
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with
+ * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array, and
+ * ({@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.width - 1,
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.height - 1) being the bottom-right
+ * pixel in the pre-correction active pixel array.
+ * When the distortion correction mode is not OFF, the coordinate system follows
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
+ * <code>(0, 0)</code> being the top-left pixel of the active array, and
+ * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the
+ * active pixel array.</p>
* <p>The weight must range from 0 to 1000, and represents a weight
* for every pixel in the area. This means that a large metering area
* with the same weight as a smaller area will have more effect in
@@ -1632,15 +1687,20 @@
* region and output only the intersection rectangle as the metering region in the result
* metadata. If the region is entirely outside the crop region, it will be ignored and
* not reported in the result metadata.</p>
- * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p>
+ * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on
+ * distortion correction capability and mode</p>
* <p><b>Range of valid values:</b><br>
* Coordinates must be between <code>[(0,0), (width, height))</code> of
- * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p>
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}
+ * depending on distortion correction capability and mode</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
* @see CameraCharacteristics#CONTROL_MAX_REGIONS_AWB
+ * @see CaptureRequest#DISTORTION_CORRECTION_MODE
* @see CaptureRequest#SCALER_CROP_REGION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
*/
@PublicKey
public static final Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AWB_REGIONS =
@@ -2433,9 +2493,17 @@
/**
* <p>The desired region of the sensor to read out for this capture.</p>
* <p>This control can be used to implement digital zoom.</p>
- * <p>The crop region coordinate system is based off
- * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with <code>(0, 0)</code> being the
- * top-left corner of the sensor active array.</p>
+ * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+ * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with <code>(0, 0)</code> being
+ * the top-left pixel of the active array.</p>
+ * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+ * system depends on the mode being set.
+ * When the distortion correction mode is OFF, the coordinate system follows
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with
+ * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array.
+ * When the distortion correction mode is not OFF, the coordinate system follows
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
+ * <code>(0, 0)</code> being the top-left pixel of the active array.</p>
* <p>Output streams use this rectangle to produce their output,
* cropping to a smaller region if necessary to maintain the
* stream's aspect ratio, then scaling the sensor input to
@@ -2454,20 +2522,30 @@
* outputs will crop horizontally (pillarbox), and 16:9
* streams will match exactly. These additional crops will
* be centered within the crop region.</p>
- * <p>The width and height of the crop region cannot
- * be set to be smaller than
+ * <p>If the coordinate system is android.sensor.info.activeArraysSize, the width and height
+ * of the crop region cannot be set to be smaller than
* <code>floor( activeArraySize.width / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code> and
* <code>floor( activeArraySize.height / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code>, respectively.</p>
+ * <p>If the coordinate system is {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, the width
+ * and height of the crop region cannot be set to be smaller than
+ * <code>floor( preCorrectionActiveArraySize.width / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code>
+ * and
+ * <code>floor( preCorrectionActiveArraySize.height / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code>,
+ * respectively.</p>
* <p>The camera device may adjust the crop region to account
* for rounding and other hardware requirements; the final
* crop region used will be included in the output capture
* result.</p>
* <p><b>Units</b>: Pixel coordinates relative to
- * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p>
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on distortion correction
+ * capability and mode</p>
* <p>This key is available on all devices.</p>
*
+ * @see CaptureRequest#DISTORTION_CORRECTION_MODE
* @see CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
*/
@PublicKey
public static final Key<android.graphics.Rect> SCALER_CROP_REGION =
@@ -3186,15 +3264,14 @@
* any correction at all would slow down capture rate. Every output stream will have a
* similar amount of enhancement applied.</p>
* <p>The correction only applies to processed outputs such as YUV, JPEG, or DEPTH16; it is not
- * applied to any RAW output. Metadata coordinates such as face rectangles or metering
+ * applied to any RAW output. Metadata coordinates such as face rectangles or metering
* regions are also not affected by correction.</p>
- * <p>Applications enabling distortion correction need to pay extra attention when converting
- * image coordinates between corrected output buffers and the sensor array. For example, if
- * the app supports tap-to-focus and enables correction, it then has to apply the distortion
- * model described in {@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion} to the image buffer tap coordinates to properly
- * calculate the tap position on the sensor active array to be used with
- * {@link CaptureRequest#CONTROL_AF_REGIONS android.control.afRegions}. The same applies in reverse to detected face rectangles if
- * they need to be drawn on top of the corrected output buffers.</p>
+ * <p>This control will be on by default on devices that support this control. Applications
+ * disabling distortion correction need to pay extra attention with the coordinate system of
+ * metering regions, crop region, and face rectangles. When distortion correction is OFF,
+ * metadata coordinates follow the coordinate system of
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}. When distortion is not OFF, metadata
+ * coordinates follow the coordinate system of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</p>
* <p><b>Possible values:</b>
* <ul>
* <li>{@link #DISTORTION_CORRECTION_MODE_OFF OFF}</li>
@@ -3205,9 +3282,10 @@
* {@link CameraCharacteristics#DISTORTION_CORRECTION_AVAILABLE_MODES android.distortionCorrection.availableModes}</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
- * @see CaptureRequest#CONTROL_AF_REGIONS
* @see CameraCharacteristics#DISTORTION_CORRECTION_AVAILABLE_MODES
* @see CameraCharacteristics#LENS_DISTORTION
+ * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
* @see #DISTORTION_CORRECTION_MODE_OFF
* @see #DISTORTION_CORRECTION_MODE_FAST
* @see #DISTORTION_CORRECTION_MODE_HIGH_QUALITY
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 361d83d..d003f9a 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -730,11 +730,26 @@
* Otherwise will always be present.</p>
* <p>The maximum number of regions supported by the device is determined by the value
* of {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AE android.control.maxRegionsAe}.</p>
- * <p>The coordinate system is based on the active pixel array,
- * with (0,0) being the top-left pixel in the active pixel array, and
+ * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+ * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with (0,0) being
+ * the top-left pixel in the active pixel array, and
* ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
- * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the
- * bottom-right pixel in the active pixel array.</p>
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the
+ * active pixel array.</p>
+ * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+ * system depends on the mode being set.
+ * When the distortion correction mode is OFF, the coordinate system follows
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with
+ * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array, and
+ * ({@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.width - 1,
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.height - 1) being the bottom-right
+ * pixel in the pre-correction active pixel array.
+ * When the distortion correction mode is not OFF, the coordinate system follows
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
+ * <code>(0, 0)</code> being the top-left pixel of the active array, and
+ * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the
+ * active pixel array.</p>
* <p>The weight must be within <code>[0, 1000]</code>, and represents a weight
* for every pixel in the area. This means that a large metering area
* with the same weight as a smaller area will have more effect in
@@ -750,15 +765,20 @@
* region and output only the intersection rectangle as the metering region in the result
* metadata. If the region is entirely outside the crop region, it will be ignored and
* not reported in the result metadata.</p>
- * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p>
+ * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on
+ * distortion correction capability and mode</p>
* <p><b>Range of valid values:</b><br>
* Coordinates must be between <code>[(0,0), (width, height))</code> of
- * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p>
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}
+ * depending on distortion correction capability and mode</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
* @see CameraCharacteristics#CONTROL_MAX_REGIONS_AE
+ * @see CaptureRequest#DISTORTION_CORRECTION_MODE
* @see CaptureRequest#SCALER_CROP_REGION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
*/
@PublicKey
public static final Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AE_REGIONS =
@@ -1152,11 +1172,26 @@
* Otherwise will always be present.</p>
* <p>The maximum number of focus areas supported by the device is determined by the value
* of {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AF android.control.maxRegionsAf}.</p>
- * <p>The coordinate system is based on the active pixel array,
- * with (0,0) being the top-left pixel in the active pixel array, and
+ * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+ * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with (0,0) being
+ * the top-left pixel in the active pixel array, and
* ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
- * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the
- * bottom-right pixel in the active pixel array.</p>
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the
+ * active pixel array.</p>
+ * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+ * system depends on the mode being set.
+ * When the distortion correction mode is OFF, the coordinate system follows
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with
+ * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array, and
+ * ({@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.width - 1,
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.height - 1) being the bottom-right
+ * pixel in the pre-correction active pixel array.
+ * When the distortion correction mode is not OFF, the coordinate system follows
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
+ * <code>(0, 0)</code> being the top-left pixel of the active array, and
+ * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the
+ * active pixel array.</p>
* <p>The weight must be within <code>[0, 1000]</code>, and represents a weight
* for every pixel in the area. This means that a large metering area
* with the same weight as a smaller area will have more effect in
@@ -1173,15 +1208,20 @@
* region and output only the intersection rectangle as the metering region in the result
* metadata. If the region is entirely outside the crop region, it will be ignored and
* not reported in the result metadata.</p>
- * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p>
+ * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on
+ * distortion correction capability and mode</p>
* <p><b>Range of valid values:</b><br>
* Coordinates must be between <code>[(0,0), (width, height))</code> of
- * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p>
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}
+ * depending on distortion correction capability and mode</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
* @see CameraCharacteristics#CONTROL_MAX_REGIONS_AF
+ * @see CaptureRequest#DISTORTION_CORRECTION_MODE
* @see CaptureRequest#SCALER_CROP_REGION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
*/
@PublicKey
public static final Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AF_REGIONS =
@@ -1730,11 +1770,26 @@
* Otherwise will always be present.</p>
* <p>The maximum number of regions supported by the device is determined by the value
* of {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AWB android.control.maxRegionsAwb}.</p>
- * <p>The coordinate system is based on the active pixel array,
- * with (0,0) being the top-left pixel in the active pixel array, and
+ * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+ * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with (0,0) being
+ * the top-left pixel in the active pixel array, and
* ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
- * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the
- * bottom-right pixel in the active pixel array.</p>
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the
+ * active pixel array.</p>
+ * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+ * system depends on the mode being set.
+ * When the distortion correction mode is OFF, the coordinate system follows
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with
+ * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array, and
+ * ({@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.width - 1,
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.height - 1) being the bottom-right
+ * pixel in the pre-correction active pixel array.
+ * When the distortion correction mode is not OFF, the coordinate system follows
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
+ * <code>(0, 0)</code> being the top-left pixel of the active array, and
+ * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the
+ * active pixel array.</p>
* <p>The weight must range from 0 to 1000, and represents a weight
* for every pixel in the area. This means that a large metering area
* with the same weight as a smaller area will have more effect in
@@ -1750,15 +1805,20 @@
* region and output only the intersection rectangle as the metering region in the result
* metadata. If the region is entirely outside the crop region, it will be ignored and
* not reported in the result metadata.</p>
- * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p>
+ * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on
+ * distortion correction capability and mode</p>
* <p><b>Range of valid values:</b><br>
* Coordinates must be between <code>[(0,0), (width, height))</code> of
- * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p>
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}
+ * depending on distortion correction capability and mode</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
* @see CameraCharacteristics#CONTROL_MAX_REGIONS_AWB
+ * @see CaptureRequest#DISTORTION_CORRECTION_MODE
* @see CaptureRequest#SCALER_CROP_REGION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
*/
@PublicKey
public static final Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AWB_REGIONS =
@@ -3099,9 +3159,17 @@
/**
* <p>The desired region of the sensor to read out for this capture.</p>
* <p>This control can be used to implement digital zoom.</p>
- * <p>The crop region coordinate system is based off
- * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with <code>(0, 0)</code> being the
- * top-left corner of the sensor active array.</p>
+ * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+ * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with <code>(0, 0)</code> being
+ * the top-left pixel of the active array.</p>
+ * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+ * system depends on the mode being set.
+ * When the distortion correction mode is OFF, the coordinate system follows
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with
+ * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array.
+ * When the distortion correction mode is not OFF, the coordinate system follows
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
+ * <code>(0, 0)</code> being the top-left pixel of the active array.</p>
* <p>Output streams use this rectangle to produce their output,
* cropping to a smaller region if necessary to maintain the
* stream's aspect ratio, then scaling the sensor input to
@@ -3120,20 +3188,30 @@
* outputs will crop horizontally (pillarbox), and 16:9
* streams will match exactly. These additional crops will
* be centered within the crop region.</p>
- * <p>The width and height of the crop region cannot
- * be set to be smaller than
+ * <p>If the coordinate system is android.sensor.info.activeArraysSize, the width and height
+ * of the crop region cannot be set to be smaller than
* <code>floor( activeArraySize.width / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code> and
* <code>floor( activeArraySize.height / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code>, respectively.</p>
+ * <p>If the coordinate system is {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, the width
+ * and height of the crop region cannot be set to be smaller than
+ * <code>floor( preCorrectionActiveArraySize.width / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code>
+ * and
+ * <code>floor( preCorrectionActiveArraySize.height / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code>,
+ * respectively.</p>
* <p>The camera device may adjust the crop region to account
* for rounding and other hardware requirements; the final
* crop region used will be included in the output capture
* result.</p>
* <p><b>Units</b>: Pixel coordinates relative to
- * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p>
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on distortion correction
+ * capability and mode</p>
* <p>This key is available on all devices.</p>
*
+ * @see CaptureRequest#DISTORTION_CORRECTION_MODE
* @see CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
*/
@PublicKey
public static final Key<android.graphics.Rect> SCALER_CROP_REGION =
@@ -3624,12 +3702,23 @@
/**
* <p>List of landmarks for detected
* faces.</p>
- * <p>The coordinate system is that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
+ * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+ * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with <code>(0, 0)</code> being
+ * the top-left pixel of the active array.</p>
+ * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+ * system depends on the mode being set.
+ * When the distortion correction mode is OFF, the coordinate system follows
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with
+ * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array.
+ * When the distortion correction mode is not OFF, the coordinate system follows
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
* <code>(0, 0)</code> being the top-left pixel of the active array.</p>
* <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} == FULL
* This key is available on all devices.</p>
*
+ * @see CaptureRequest#DISTORTION_CORRECTION_MODE
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
* @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
* @hide
*/
@@ -3639,12 +3728,23 @@
/**
* <p>List of the bounding rectangles for detected
* faces.</p>
- * <p>The coordinate system is that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
+ * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+ * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with <code>(0, 0)</code> being
+ * the top-left pixel of the active array.</p>
+ * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+ * system depends on the mode being set.
+ * When the distortion correction mode is OFF, the coordinate system follows
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with
+ * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array.
+ * When the distortion correction mode is not OFF, the coordinate system follows
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
* <code>(0, 0)</code> being the top-left pixel of the active array.</p>
* <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} != OFF
* This key is available on all devices.</p>
*
+ * @see CaptureRequest#DISTORTION_CORRECTION_MODE
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
* @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
* @hide
*/
@@ -4478,15 +4578,14 @@
* any correction at all would slow down capture rate. Every output stream will have a
* similar amount of enhancement applied.</p>
* <p>The correction only applies to processed outputs such as YUV, JPEG, or DEPTH16; it is not
- * applied to any RAW output. Metadata coordinates such as face rectangles or metering
+ * applied to any RAW output. Metadata coordinates such as face rectangles or metering
* regions are also not affected by correction.</p>
- * <p>Applications enabling distortion correction need to pay extra attention when converting
- * image coordinates between corrected output buffers and the sensor array. For example, if
- * the app supports tap-to-focus and enables correction, it then has to apply the distortion
- * model described in {@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion} to the image buffer tap coordinates to properly
- * calculate the tap position on the sensor active array to be used with
- * {@link CaptureRequest#CONTROL_AF_REGIONS android.control.afRegions}. The same applies in reverse to detected face rectangles if
- * they need to be drawn on top of the corrected output buffers.</p>
+ * <p>This control will be on by default on devices that support this control. Applications
+ * disabling distortion correction need to pay extra attention with the coordinate system of
+ * metering regions, crop region, and face rectangles. When distortion correction is OFF,
+ * metadata coordinates follow the coordinate system of
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}. When distortion is not OFF, metadata
+ * coordinates follow the coordinate system of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</p>
* <p><b>Possible values:</b>
* <ul>
* <li>{@link #DISTORTION_CORRECTION_MODE_OFF OFF}</li>
@@ -4497,9 +4596,10 @@
* {@link CameraCharacteristics#DISTORTION_CORRECTION_AVAILABLE_MODES android.distortionCorrection.availableModes}</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
- * @see CaptureRequest#CONTROL_AF_REGIONS
* @see CameraCharacteristics#DISTORTION_CORRECTION_AVAILABLE_MODES
* @see CameraCharacteristics#LENS_DISTORTION
+ * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
* @see #DISTORTION_CORRECTION_MODE_OFF
* @see #DISTORTION_CORRECTION_MODE_FAST
* @see #DISTORTION_CORRECTION_MODE_HIGH_QUALITY
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index a040a09..1ee3c93 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -82,9 +82,9 @@
*
* </ul>
*
- * <p> As of {@link android.os.Build.VERSION_CODES#P Android P}, all formats can be used for
- * sharing, subject to device support. On prior API levels, only {@link ImageFormat#PRIVATE}
- * format may be used.</p>
+ * <p> As of {@link android.os.Build.VERSION_CODES#P Android P}, all formats except
+ * {@link ImageFormat#JPEG} and {@link ImageFormat#RAW_PRIVATE} can be used for sharing, subject to
+ * device support. On prior API levels, only {@link ImageFormat#PRIVATE} format may be used.</p>
*
* @see CameraDevice#createCaptureSessionByOutputConfigurations
*
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index c56b685..414c463 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -725,7 +725,7 @@
* Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration}
* for the class/size combination (in nanoseconds).
*
- * <p>This assumes a the {@code klass} is set up to use {@link ImageFormat#PRIVATE}.
+ * <p>This assumes that the {@code klass} is set up to use {@link ImageFormat#PRIVATE}.
* For user-defined formats, use {@link #getOutputMinFrameDuration(int, Size)}.</p>
*
* <p>{@code klass} should be one of the ones which is supported by
@@ -870,7 +870,7 @@
/**
* Get the stall duration for the class/size combination (in nanoseconds).
*
- * <p>This assumes a the {@code klass} is set up to use {@link ImageFormat#PRIVATE}.
+ * <p>This assumes that the {@code klass} is set up to use {@link ImageFormat#PRIVATE}.
* For user-defined formats, use {@link #getOutputMinFrameDuration(int, Size)}.</p>
*
* <p>{@code klass} should be one of the ones with a non-empty array returned by
diff --git a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionCategory.java b/core/java/android/hardware/face/Face.aidl
similarity index 65%
copy from packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionCategory.java
copy to core/java/android/hardware/face/Face.aidl
index 19e556a..a7c9141 100644
--- a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionCategory.java
+++ b/core/java/android/hardware/face/Face.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2018 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.
@@ -13,13 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package android.hardware.face;
-package com.android.settingslib.suggestions;
-
-public class SuggestionCategory {
- public String category;
- public String pkg;
- public boolean multiple;
- public boolean exclusive;
- public long exclusiveExpireDaysInMillis;
-}
+/**
+ * @hide
+ */
+parcelable Face;
diff --git a/core/java/android/hardware/face/Face.java b/core/java/android/hardware/face/Face.java
new file mode 100644
index 0000000..6a508ac
--- /dev/null
+++ b/core/java/android/hardware/face/Face.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2018 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.biometrics.BiometricAuthenticator;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Container for face metadata.
+ *
+ * @hide
+ */
+public final class Face extends BiometricAuthenticator.Identifier {
+ private CharSequence mName;
+ private int mFaceId;
+ private long mDeviceId; // physical device this face is associated with
+
+ public Face(CharSequence name, int faceId, long deviceId) {
+ mName = name;
+ mFaceId = faceId;
+ mDeviceId = deviceId;
+ }
+
+ private Face(Parcel in) {
+ mName = in.readString();
+ mFaceId = in.readInt();
+ mDeviceId = in.readLong();
+ }
+
+ /**
+ * Gets the human-readable name for the given fingerprint.
+ * @return name given to finger
+ */
+ public CharSequence getName() {
+ return mName;
+ }
+
+ /**
+ * Gets the device-specific finger id. Used by Settings to map a name to a specific
+ * fingerprint template.
+ * @return device-specific id for this finger
+ * @hide
+ */
+ public int getFaceId() {
+ return mFaceId;
+ }
+
+ /**
+ * Device this face belongs to.
+ *
+ * @hide
+ */
+ public long getDeviceId() {
+ return mDeviceId;
+ }
+
+ /**
+ * Describes the contents.
+ * @return
+ */
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Writes to a parcel.
+ * @param out
+ * @param flags Additional flags about how the object should be written.
+ */
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mName.toString());
+ out.writeInt(mFaceId);
+ out.writeLong(mDeviceId);
+ }
+
+ public static final Parcelable.Creator<Face> CREATOR = new Parcelable.Creator<Face>() {
+ public Face createFromParcel(Parcel in) {
+ return new Face(in);
+ }
+
+ public Face[] newArray(int size) {
+ return new Face[size];
+ }
+ };
+}
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
new file mode 100644
index 0000000..3ed6228
--- /dev/null
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -0,0 +1,1037 @@
+/**
+ * Copyright (C) 2018 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 static android.Manifest.permission.INTERACT_ACROSS_USERS;
+import static android.Manifest.permission.MANAGE_FACE;
+import static android.Manifest.permission.USE_BIOMETRIC;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemService;
+import android.app.ActivityManager;
+import android.content.Context;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricFaceConstants;
+import android.hardware.biometrics.BiometricPrompt;
+import android.hardware.biometrics.CryptoObject;
+import android.hardware.biometrics.IBiometricPromptReceiver;
+import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.CancellationSignal.OnCancelListener;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IRemoteCallback;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.internal.R;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * A class that coordinates access to the face authentication hardware.
+ * @hide
+ */
+@SystemService(Context.FACE_SERVICE)
+public class FaceManager implements BiometricFaceConstants {
+
+
+ private static final String TAG = "FaceManager";
+ private static final boolean DEBUG = true;
+ private static final int MSG_ENROLL_RESULT = 100;
+ private static final int MSG_ACQUIRED = 101;
+ private static final int MSG_AUTHENTICATION_SUCCEEDED = 102;
+ private static final int MSG_AUTHENTICATION_FAILED = 103;
+ private static final int MSG_ERROR = 104;
+ private static final int MSG_REMOVED = 105;
+
+ private IFaceService mService;
+ private final Context mContext;
+ private IBinder mToken = new Binder();
+ private BiometricAuthenticator.AuthenticationCallback mAuthenticationCallback;
+ private EnrollmentCallback mEnrollmentCallback;
+ private RemovalCallback mRemovalCallback;
+ private CryptoObject mCryptoObject;
+ private Face mRemovalFace;
+ private Handler mHandler;
+ private Executor mExecutor;
+
+ private IFaceServiceReceiver mServiceReceiver = new IFaceServiceReceiver.Stub() {
+
+ @Override // binder call
+ public void onEnrollResult(long deviceId, int faceId, int remaining) {
+ mHandler.obtainMessage(MSG_ENROLL_RESULT, remaining, 0,
+ new Face(null, faceId, deviceId)).sendToTarget();
+ }
+
+ @Override // binder call
+ public void onAcquired(long deviceId, int acquireInfo, int vendorCode) {
+ mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, vendorCode, deviceId).sendToTarget();
+ }
+
+ @Override // binder call
+ public void onAuthenticationSucceeded(long deviceId, Face face) {
+ mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, face).sendToTarget();
+ }
+
+ @Override // binder call
+ public void onAuthenticationFailed(long deviceId) {
+ mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget();
+ }
+
+ @Override // binder call
+ public void onError(long deviceId, int error, int vendorCode) {
+ mHandler.obtainMessage(MSG_ERROR, error, vendorCode, deviceId).sendToTarget();
+ }
+
+ @Override // binder call
+ public void onRemoved(long deviceId, int faceId, int remaining) {
+ mHandler.obtainMessage(MSG_REMOVED, remaining, 0,
+ new Face(null, faceId, deviceId)).sendToTarget();
+ }
+ };
+
+ /**
+ * @hide
+ */
+ public FaceManager(Context context, IFaceService service) {
+ mContext = context;
+ mService = service;
+ if (mService == null) {
+ Slog.v(TAG, "FaceAuthenticationManagerService was null");
+ }
+ mHandler = new MyHandler(context);
+ }
+
+ /**
+ * Request authentication of a crypto object. This call operates the face recognition hardware
+ * and starts capturing images. It terminates when
+ * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or
+ * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called, at
+ * which point the object is no longer valid. The operation can be canceled by using the
+ * provided cancel object.
+ *
+ * @param crypto object associated with the call or null if none required.
+ * @param cancel an object that can be used to cancel authentication
+ * @param flags optional flags; should be 0
+ * @param callback an object to receive authentication events
+ * @param handler an optional handler to handle callback events
+ * @throws IllegalArgumentException if the crypto operation is not supported or is not backed
+ * by
+ * <a href="{@docRoot}training/articles/keystore.html">Android
+ * Keystore facility</a>.
+ * @throws IllegalStateException if the crypto primitive is not initialized.
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC)
+ public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
+ int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) {
+ if (callback == null) {
+ throw new IllegalArgumentException("Must supply an authentication callback");
+ }
+
+ if (cancel != null) {
+ if (cancel.isCanceled()) {
+ Log.w(TAG, "authentication already canceled");
+ return;
+ } else {
+ cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
+ }
+ }
+
+ if (mService != null) {
+ try {
+ useHandler(handler);
+ mAuthenticationCallback = callback;
+ mCryptoObject = crypto;
+ long sessionId = crypto != null ? crypto.getOpId() : 0;
+ mService.authenticate(mToken, sessionId, mServiceReceiver, flags,
+ mContext.getOpPackageName(), null /* bundle */, null /* receiver */);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Remote exception while authenticating: ", e);
+ if (callback != null) {
+ // Though this may not be a hardware issue, it will cause apps to give up or try
+ // again later.
+ callback.onAuthenticationError(FACE_ERROR_HW_UNAVAILABLE,
+ getErrorString(FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
+ }
+ }
+ }
+ }
+
+ /**
+ * Use the provided handler thread for events.
+ */
+ private void useHandler(Handler handler) {
+ if (handler != null) {
+ mHandler = new MyHandler(handler.getLooper());
+ } else if (mHandler.getLooper() != mContext.getMainLooper()) {
+ mHandler = new MyHandler(mContext.getMainLooper());
+ }
+ }
+
+ /**
+ * This method invokes the BiometricPrompt.
+ */
+ private void authenticateWithPrompt(@Nullable android.hardware.biometrics.CryptoObject crypto,
+ @NonNull CancellationSignal cancel,
+ @NonNull Bundle bundle,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull IBiometricPromptReceiver receiver,
+ @NonNull BiometricAuthenticator.AuthenticationCallback callback) {
+ mCryptoObject = crypto;
+ if (cancel.isCanceled()) {
+ Slog.w(TAG, "authentication already canceled");
+ return;
+ } else {
+ cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
+ }
+
+ if (mService != null) {
+ try {
+ mExecutor = executor;
+ mAuthenticationCallback = callback;
+ final long sessionId = crypto != null ? crypto.getOpId() : 0;
+ mService.authenticate(mToken, sessionId, mServiceReceiver,
+ 0 /* flags */, mContext.getOpPackageName(), bundle, receiver);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Remote exception while authenticating", e);
+ mExecutor.execute(() -> {
+ callback.onAuthenticationError(FACE_ERROR_HW_UNAVAILABLE,
+ getErrorString(FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
+ });
+ }
+ }
+ }
+
+ /**
+ * Private method, see {@link BiometricPrompt#authenticate(CancellationSignal, Executor,
+ * BiometricPrompt.AuthenticationCallback)}
+ * @param cancel
+ * @param executor
+ * @param callback
+ * @hide
+ */
+ public void authenticate(
+ @NonNull CancellationSignal cancel,
+ @NonNull Bundle bundle,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull IBiometricPromptReceiver receiver,
+ @NonNull BiometricAuthenticator.AuthenticationCallback callback) {
+ if (cancel == null) {
+ throw new IllegalArgumentException("Must supply a cancellation signal");
+ }
+ if (bundle == null) {
+ throw new IllegalArgumentException("Must supply a bundle");
+ }
+ if (executor == null) {
+ throw new IllegalArgumentException("Must supply an executor");
+ }
+ if (receiver == null) {
+ throw new IllegalArgumentException("Must supply a receiver");
+ }
+ if (callback == null) {
+ throw new IllegalArgumentException("Must supply a calback");
+ }
+ authenticateWithPrompt(null, cancel, bundle, executor, receiver, callback);
+ }
+
+ /**
+ * Private method, see {@link BiometricPrompt#authenticate(BiometricPrompt.CryptoObject,
+ * CancellationSignal, Executor, BiometricPrompt.AuthenticationCallback)}
+ * @param crypto
+ * @param cancel
+ * @param executor
+ * @param callback
+ * @hide
+ */
+ public void authenticate(@NonNull android.hardware.biometrics.CryptoObject crypto,
+ @NonNull CancellationSignal cancel,
+ @NonNull Bundle bundle,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull IBiometricPromptReceiver receiver,
+ @NonNull BiometricAuthenticator.AuthenticationCallback callback) {
+ if (crypto == null) {
+ throw new IllegalArgumentException("Must supply a crypto object");
+ }
+ if (cancel == null) {
+ throw new IllegalArgumentException("Must supply a cancellation signal");
+ }
+ if (bundle == null) {
+ throw new IllegalArgumentException("Must supply a bundle");
+ }
+ if (executor == null) {
+ throw new IllegalArgumentException("Must supply an executor");
+ }
+ if (receiver == null) {
+ throw new IllegalArgumentException("Must supply a receiver");
+ }
+ if (callback == null) {
+ throw new IllegalArgumentException("Must supply a callback");
+ }
+ authenticateWithPrompt(crypto, cancel, bundle, executor, receiver, callback);
+ }
+
+ /**
+ * Request face authentication enrollment. This call operates the face authentication hardware
+ * and starts capturing images. Progress will be indicated by callbacks to the
+ * {@link EnrollmentCallback} object. It terminates when
+ * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)} or
+ * {@link EnrollmentCallback#onEnrollmentProgress(int) is called with remaining == 0, at
+ * which point the object is no longer valid. The operation can be canceled by using the
+ * provided cancel object.
+ *
+ * @param token a unique token provided by a recent creation or verification of device
+ * credentials (e.g. pin, pattern or password).
+ * @param cancel an object that can be used to cancel enrollment
+ * @param flags optional flags
+ * @param userId the user to whom this face will belong to
+ * @param callback an object to receive enrollment events
+ * @hide
+ */
+ @RequiresPermission(MANAGE_FACE)
+ public void enroll(byte[] token, CancellationSignal cancel, int flags,
+ int userId, EnrollmentCallback callback) {
+ if (userId == UserHandle.USER_CURRENT) {
+ userId = getCurrentUserId();
+ }
+ if (callback == null) {
+ throw new IllegalArgumentException("Must supply an enrollment callback");
+ }
+
+ if (cancel != null) {
+ if (cancel.isCanceled()) {
+ Log.w(TAG, "enrollment already canceled");
+ return;
+ } else {
+ cancel.setOnCancelListener(new OnEnrollCancelListener());
+ }
+ }
+
+ if (mService != null) {
+ try {
+ mEnrollmentCallback = callback;
+ mService.enroll(mToken, token, userId, mServiceReceiver, flags,
+ mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ Log.w(TAG, "Remote exception in enroll: ", e);
+ if (callback != null) {
+ // Though this may not be a hardware issue, it will cause apps to give up or try
+ // again later.
+ callback.onEnrollmentError(FACE_ERROR_HW_UNAVAILABLE,
+ getErrorString(FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
+ }
+ }
+ }
+ }
+
+ /**
+ * Requests a pre-enrollment auth token to tie enrollment to the confirmation of
+ * existing device credentials (e.g. pin/pattern/password).
+ *
+ * @hide
+ */
+ @RequiresPermission(MANAGE_FACE)
+ public long preEnroll() {
+ long result = 0;
+ if (mService != null) {
+ try {
+ result = mService.preEnroll(mToken);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Finishes enrollment and cancels the current auth token.
+ *
+ * @hide
+ */
+ @RequiresPermission(MANAGE_FACE)
+ public int postEnroll() {
+ int result = 0;
+ if (mService != null) {
+ try {
+ result = mService.postEnroll(mToken);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Sets the active user. This is meant to be used to select the current profile for enrollment
+ * to allow separate enrolled faces for a work profile
+ *
+ * @hide
+ */
+ @RequiresPermission(MANAGE_FACE)
+ public void setActiveUser(int userId) {
+ if (mService != null) {
+ try {
+ mService.setActiveUser(userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Remove given face template from face hardware and/or protected storage.
+ *
+ * @param face the face item to remove
+ * @param userId the user who this face belongs to
+ * @param callback an optional callback to verify that face templates have been
+ * successfully removed. May be null if no callback is required.
+ * @hide
+ */
+ @RequiresPermission(MANAGE_FACE)
+ public void remove(Face face, int userId, RemovalCallback callback) {
+ if (mService != null) {
+ try {
+ mRemovalCallback = callback;
+ mRemovalFace = face;
+ mService.remove(mToken, face.getFaceId(), userId, mServiceReceiver);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Remote exception in remove: ", e);
+ if (callback != null) {
+ callback.onRemovalError(face, FACE_ERROR_HW_UNAVAILABLE,
+ getErrorString(FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
+ }
+ }
+ }
+ }
+
+ /**
+ * Obtain the enrolled face template.
+ *
+ * @return the current face item
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC)
+ public List<Face> getEnrolledFaces(int userId) {
+ if (mService != null) {
+ try {
+ return mService.getEnrolledFaces(userId, mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Obtain the enrolled face template.
+ *
+ * @return the current face item
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC)
+ public List<Face> getEnrolledFaces() {
+ return getEnrolledFaces(UserHandle.myUserId());
+ }
+
+ /**
+ * Determine if there is a face enrolled.
+ *
+ * @return true if a face is enrolled, false otherwise
+ */
+ @RequiresPermission(USE_BIOMETRIC)
+ public boolean hasEnrolledFaces() {
+ if (mService != null) {
+ try {
+ return mService.hasEnrolledFaces(
+ UserHandle.myUserId(), mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @hide
+ */
+ @RequiresPermission(allOf = {
+ USE_BIOMETRIC,
+ INTERACT_ACROSS_USERS})
+ public boolean hasEnrolledFaces(int userId) {
+ if (mService != null) {
+ try {
+ return mService.hasEnrolledFaces(userId, mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if face authentication sensor hardware is present and functional.
+ *
+ * @return true if hardware is present and functional, false otherwise.
+ */
+ @RequiresPermission(USE_BIOMETRIC)
+ public boolean isHardwareDetected() {
+ if (mService != null) {
+ try {
+ long deviceId = 0; /* TODO: plumb hardware id to FPMS */
+ return mService.isHardwareDetected(deviceId, mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ } else {
+ Log.w(TAG, "isFaceHardwareDetected(): Service not connected!");
+ }
+ return false;
+ }
+
+ /**
+ * Retrieves the authenticator token for binding keys to the lifecycle
+ * of the calling user's face. Used only by internal clients.
+ *
+ * @hide
+ */
+ public long getAuthenticatorId() {
+ if (mService != null) {
+ try {
+ return mService.getAuthenticatorId(mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ } else {
+ Log.w(TAG, "getAuthenticatorId(): Service not connected!");
+ }
+ return 0;
+ }
+
+ /**
+ * Reset the lockout timer when asked to do so by keyguard.
+ *
+ * @param token an opaque token returned by password confirmation.
+ * @hide
+ */
+ public void resetTimeout(byte[] token) {
+ if (mService != null) {
+ try {
+ mService.resetTimeout(token);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ } else {
+ Log.w(TAG, "resetTimeout(): Service not connected!");
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void addLockoutResetCallback(final LockoutResetCallback callback) {
+ if (mService != null) {
+ try {
+ final PowerManager powerManager = mContext.getSystemService(PowerManager.class);
+ mService.addLockoutResetCallback(
+ new IBiometricServiceLockoutResetCallback.Stub() {
+
+ @Override
+ public void onLockoutReset(long deviceId,
+ IRemoteCallback serverCallback)
+ throws RemoteException {
+ try {
+ final PowerManager.WakeLock wakeLock = powerManager.newWakeLock(
+ PowerManager.PARTIAL_WAKE_LOCK,
+ "faceLockoutResetCallback");
+ wakeLock.acquire();
+ mHandler.post(() -> {
+ try {
+ callback.onLockoutReset();
+ } finally {
+ wakeLock.release();
+ }
+ });
+ } finally {
+ serverCallback.sendResult(null /* data */);
+ }
+ }
+ });
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ } else {
+ Log.w(TAG, "addLockoutResetCallback(): Service not connected!");
+ }
+ }
+
+ private int getCurrentUserId() {
+ try {
+ return ActivityManager.getService().getCurrentUser().id;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ private void cancelEnrollment() {
+ if (mService != null) {
+ try {
+ mService.cancelEnrollment(mToken);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ private void cancelAuthentication(CryptoObject cryptoObject) {
+ if (mService != null) {
+ try {
+ mService.cancelAuthentication(mToken, mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ private String getErrorString(int errMsg, int vendorCode) {
+ switch (errMsg) {
+ case FACE_ERROR_HW_UNAVAILABLE:
+ return mContext.getString(
+ com.android.internal.R.string.face_error_hw_not_available);
+ case FACE_ERROR_UNABLE_TO_PROCESS:
+ return mContext.getString(
+ com.android.internal.R.string.face_error_unable_to_process);
+ case FACE_ERROR_TIMEOUT:
+ return mContext.getString(com.android.internal.R.string.face_error_timeout);
+ case FACE_ERROR_NO_SPACE:
+ return mContext.getString(com.android.internal.R.string.face_error_no_space);
+ case FACE_ERROR_CANCELED:
+ return mContext.getString(com.android.internal.R.string.face_error_canceled);
+ case FACE_ERROR_LOCKOUT:
+ return mContext.getString(com.android.internal.R.string.face_error_lockout);
+ case FACE_ERROR_LOCKOUT_PERMANENT:
+ return mContext.getString(
+ com.android.internal.R.string.face_error_lockout_permanent);
+ case FACE_ERROR_NOT_ENROLLED:
+ return mContext.getString(com.android.internal.R.string.face_error_not_enrolled);
+ case FACE_ERROR_HW_NOT_PRESENT:
+ return mContext.getString(com.android.internal.R.string.face_error_hw_not_present);
+ case FACE_ERROR_VENDOR: {
+ String[] msgArray = mContext.getResources().getStringArray(
+ com.android.internal.R.array.face_error_vendor);
+ if (vendorCode < msgArray.length) {
+ return msgArray[vendorCode];
+ }
+ }
+ }
+ Slog.w(TAG, "Invalid error message: " + errMsg + ", " + vendorCode);
+ return null;
+ }
+
+ private String getAcquiredString(int acquireInfo, int vendorCode) {
+ switch (acquireInfo) {
+ case FACE_ACQUIRED_GOOD:
+ return null;
+ case FACE_ACQUIRED_INSUFFICIENT:
+ return mContext.getString(R.string.face_acquired_insufficient);
+ case FACE_ACQUIRED_TOO_BRIGHT:
+ return mContext.getString(R.string.face_acquired_too_bright);
+ case FACE_ACQUIRED_TOO_DARK:
+ return mContext.getString(R.string.face_acquired_too_dark);
+ case FACE_ACQUIRED_TOO_CLOSE:
+ return mContext.getString(R.string.face_acquired_too_close);
+ case FACE_ACQUIRED_TOO_FAR:
+ return mContext.getString(R.string.face_acquired_too_far);
+ case FACE_ACQUIRED_TOO_HIGH:
+ return mContext.getString(R.string.face_acquired_too_high);
+ case FACE_ACQUIRED_TOO_LOW:
+ return mContext.getString(R.string.face_acquired_too_low);
+ case FACE_ACQUIRED_TOO_RIGHT:
+ return mContext.getString(R.string.face_acquired_too_right);
+ case FACE_ACQUIRED_TOO_LEFT:
+ return mContext.getString(R.string.face_acquired_too_left);
+ case FACE_ACQUIRED_POOR_GAZE:
+ return mContext.getString(R.string.face_acquired_poor_gaze);
+ case FACE_ACQUIRED_NOT_DETECTED:
+ return mContext.getString(R.string.face_acquired_not_detected);
+ case FACE_ACQUIRED_VENDOR: {
+ String[] msgArray = mContext.getResources().getStringArray(
+ R.array.face_acquired_vendor);
+ if (vendorCode < msgArray.length) {
+ return msgArray[vendorCode];
+ }
+ }
+ }
+ Slog.w(TAG, "Invalid acquired message: " + acquireInfo + ", " + vendorCode);
+ return null;
+ }
+
+ /**
+ * Container for callback data from {@link FaceManager#authenticate(CryptoObject,
+ * CancellationSignal, int, AuthenticationCallback, Handler)}.
+ */
+ public static class AuthenticationResult {
+ private Face mFace;
+ private CryptoObject mCryptoObject;
+ private int mUserId;
+
+ /**
+ * Authentication result
+ *
+ * @param crypto the crypto object
+ * @param face the recognized face data, if allowed.
+ * @hide
+ */
+ public AuthenticationResult(CryptoObject crypto, Face face, int userId) {
+ mCryptoObject = crypto;
+ mFace = face;
+ mUserId = userId;
+ }
+
+ /**
+ * Obtain the crypto object associated with this transaction
+ *
+ * @return crypto object provided to {@link FaceManager#authenticate
+ * (CryptoObject,
+ * CancellationSignal, int, AuthenticationCallback, Handler)}.
+ */
+ public CryptoObject getCryptoObject() {
+ return mCryptoObject;
+ }
+
+ /**
+ * Obtain the Face associated with this operation. Applications are strongly
+ * discouraged from associating specific faces with specific applications or operations.
+ *
+ * @hide
+ */
+ public Face getFace() {
+ return mFace;
+ }
+
+ /**
+ * Obtain the userId for which this face was authenticated.
+ *
+ * @hide
+ */
+ public int getUserId() {
+ return mUserId;
+ }
+ }
+
+ /**
+ * Callback structure provided to {@link FaceManager#authenticate(CryptoObject,
+ * CancellationSignal, int, AuthenticationCallback, Handler)}. Users of {@link
+ * FaceManager#authenticate(CryptoObject, CancellationSignal,
+ * int, AuthenticationCallback, Handler) } must provide an implementation of this for listening
+ * to face events.
+ */
+ public abstract static class AuthenticationCallback
+ extends BiometricAuthenticator.AuthenticationCallback {
+
+ /**
+ * Called when an unrecoverable error has been encountered and the operation is complete.
+ * No further callbacks will be made on this object.
+ *
+ * @param errorCode An integer identifying the error message
+ * @param errString A human-readable error string that can be shown in UI
+ */
+ public void onAuthenticationError(int errorCode, CharSequence errString) {
+ }
+
+ /**
+ * Called when a recoverable error has been encountered during authentication. The help
+ * string is provided to give the user guidance for what went wrong, such as
+ * "Sensor dirty, please clean it."
+ *
+ * @param helpCode An integer identifying the error message
+ * @param helpString A human-readable string that can be shown in UI
+ */
+ public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
+ }
+
+ /**
+ * Called when a face is recognized.
+ *
+ * @param result An object containing authentication-related data
+ */
+ public void onAuthenticationSucceeded(AuthenticationResult result) {
+ }
+
+ /**
+ * Called when a face is detected but not recognized.
+ */
+ public void onAuthenticationFailed() {
+ }
+
+ /**
+ * Called when a face image has been acquired, but wasn't processed yet.
+ *
+ * @param acquireInfo one of FACE_ACQUIRED_* constants
+ * @hide
+ */
+ public void onAuthenticationAcquired(int acquireInfo) {
+ }
+ }
+
+ /**
+ * Callback structure provided to {@link FaceManager#enroll(long,
+ * EnrollmentCallback, CancellationSignal, int). Users of {@link #FaceAuthenticationManager()}
+ * must provide an implementation of this to {@link FaceManager#enroll(long,
+ * CancellationSignal, int, EnrollmentCallback) for listening to face enrollment events.
+ *
+ * @hide
+ */
+ public abstract static class EnrollmentCallback {
+
+ /**
+ * Called when an unrecoverable error has been encountered and the operation is complete.
+ * No further callbacks will be made on this object.
+ *
+ * @param errMsgId An integer identifying the error message
+ * @param errString A human-readable error string that can be shown in UI
+ */
+ public void onEnrollmentError(int errMsgId, CharSequence errString) {
+ }
+
+ /**
+ * Called when a recoverable error has been encountered during enrollment. The help
+ * string is provided to give the user guidance for what went wrong, such as
+ * "Image too dark, uncover light source" or what they need to do next, such as
+ * "Rotate face up / down."
+ *
+ * @param helpMsgId An integer identifying the error message
+ * @param helpString A human-readable string that can be shown in UI
+ */
+ public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
+ }
+
+ /**
+ * Called as each enrollment step progresses. Enrollment is considered complete when
+ * remaining reaches 0. This function will not be called if enrollment fails. See
+ * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)}
+ *
+ * @param remaining The number of remaining steps
+ * @param vendorMsg Vendor feedback about the current enroll attempt. Use it to customize
+ * the GUI according to vendor's requirements.
+ */
+ public void onEnrollmentProgress(int remaining, long vendorMsg) {
+ }
+ }
+
+ /**
+ * Callback structure provided to {@link #remove}. Users of {@link FaceManager}
+ * may
+ * optionally provide an implementation of this to
+ * {@link #remove(Face, int, RemovalCallback)} for listening to face template
+ * removal events.
+ *
+ * @hide
+ */
+ public abstract static class RemovalCallback {
+
+ /**
+ * Called when the given face can't be removed.
+ *
+ * @param face The face that the call attempted to remove
+ * @param errMsgId An associated error message id
+ * @param errString An error message indicating why the face id can't be removed
+ */
+ public void onRemovalError(Face face, int errMsgId, CharSequence errString) {
+ }
+
+ /**
+ * Called when a given face is successfully removed.
+ *
+ * @param face The face template that was removed.
+ */
+ public void onRemovalSucceeded(Face face) {
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public abstract static class LockoutResetCallback {
+
+ /**
+ * Called when lockout period expired and clients are allowed to listen for face
+ * authentication
+ * again.
+ */
+ public void onLockoutReset() {
+ }
+ }
+
+ private class OnEnrollCancelListener implements OnCancelListener {
+ @Override
+ public void onCancel() {
+ cancelEnrollment();
+ }
+ }
+
+ private class OnAuthenticationCancelListener implements OnCancelListener {
+ private CryptoObject mCrypto;
+
+ OnAuthenticationCancelListener(CryptoObject crypto) {
+ mCrypto = crypto;
+ }
+
+ @Override
+ public void onCancel() {
+ cancelAuthentication(mCrypto);
+ }
+ }
+
+ private class MyHandler extends Handler {
+ private MyHandler(Context context) {
+ super(context.getMainLooper());
+ }
+
+ private MyHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(android.os.Message msg) {
+ switch (msg.what) {
+ case MSG_ENROLL_RESULT:
+ sendEnrollResult((EnrollResultMsg) msg.obj);
+ break;
+ case MSG_ACQUIRED:
+ sendAcquiredResult((Long) msg.obj /* deviceId */, msg.arg1 /* acquire info */,
+ msg.arg2 /* vendorCode */);
+ break;
+ case MSG_AUTHENTICATION_SUCCEEDED:
+ sendAuthenticatedSucceeded((Face) msg.obj, msg.arg1 /* userId */);
+ break;
+ case MSG_AUTHENTICATION_FAILED:
+ sendAuthenticatedFailed();
+ break;
+ case MSG_ERROR:
+ sendErrorResult((Long) msg.obj /* deviceId */, msg.arg1 /* errMsgId */,
+ msg.arg2 /* vendorCode */);
+ break;
+ case MSG_REMOVED:
+ sendRemovedResult((Face) msg.obj);
+ break;
+ }
+ }
+ };
+
+ private void sendRemovedResult(Face face) {
+ if (mRemovalCallback == null) {
+ return;
+ }
+ if (face == null) {
+ Log.e(TAG, "Received MSG_REMOVED, but face is null");
+ return;
+ }
+
+
+ mRemovalCallback.onRemovalSucceeded(face);
+ }
+
+ private void sendErrorResult(long deviceId, int errMsgId, int vendorCode) {
+ // emulate HAL 2.1 behavior and send real errMsgId
+ final int clientErrMsgId = errMsgId == FACE_ERROR_VENDOR
+ ? (vendorCode + FACE_ERROR_VENDOR_BASE) : errMsgId;
+ if (mEnrollmentCallback != null) {
+ mEnrollmentCallback.onEnrollmentError(clientErrMsgId,
+ getErrorString(errMsgId, vendorCode));
+ } else if (mAuthenticationCallback != null) {
+ mAuthenticationCallback.onAuthenticationError(clientErrMsgId,
+ getErrorString(errMsgId, vendorCode));
+ } else if (mRemovalCallback != null) {
+ mRemovalCallback.onRemovalError(mRemovalFace, clientErrMsgId,
+ getErrorString(errMsgId, vendorCode));
+ }
+ }
+
+ private void sendEnrollResult(EnrollResultMsg faceWrapper) {
+ if (mEnrollmentCallback != null) {
+ int remaining = faceWrapper.getRemaining();
+ long vendorMsg = faceWrapper.getVendorMsg();
+ mEnrollmentCallback.onEnrollmentProgress(remaining, vendorMsg);
+ }
+ }
+
+ private void sendAuthenticatedSucceeded(Face face, int userId) {
+ if (mAuthenticationCallback != null) {
+ final BiometricAuthenticator.AuthenticationResult result =
+ new BiometricAuthenticator.AuthenticationResult(mCryptoObject, face, userId);
+ mAuthenticationCallback.onAuthenticationSucceeded(result);
+ }
+ }
+
+ private void sendAuthenticatedFailed() {
+ if (mAuthenticationCallback != null) {
+ mAuthenticationCallback.onAuthenticationFailed();
+ }
+ }
+
+ private void sendAcquiredResult(long deviceId, int acquireInfo, int vendorCode) {
+ if (mAuthenticationCallback != null) {
+ mAuthenticationCallback.onAuthenticationAcquired(acquireInfo);
+ }
+ final String msg = getAcquiredString(acquireInfo, vendorCode);
+ if (msg == null) {
+ return;
+ }
+ final int clientInfo = acquireInfo == FACE_ACQUIRED_VENDOR
+ ? (vendorCode + FACE_ACQUIRED_VENDOR_BASE) : acquireInfo;
+ if (mEnrollmentCallback != null) {
+ mEnrollmentCallback.onEnrollmentHelp(clientInfo, msg);
+ } else if (mAuthenticationCallback != null) {
+ mAuthenticationCallback.onAuthenticationHelp(clientInfo, msg);
+ }
+ }
+
+ private class EnrollResultMsg {
+ private final Face mFace;
+ private final int mRemaining;
+ private final long mVendorMsg;
+
+ EnrollResultMsg(Face face, int remaining, long vendorMsg) {
+ mFace = face;
+ mRemaining = remaining;
+ mVendorMsg = vendorMsg;
+ }
+
+ Face getFace() {
+ return mFace;
+ }
+
+ long getVendorMsg() {
+ return mVendorMsg;
+ }
+
+ int getRemaining() {
+ return mRemaining;
+ }
+ }
+}
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
new file mode 100644
index 0000000..03bb7ae
--- /dev/null
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2018 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.os.Bundle;
+import android.hardware.biometrics.IBiometricPromptReceiver;
+import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
+import android.hardware.face.IFaceServiceReceiver;
+import android.hardware.face.Face;
+
+/**
+ * Communication channel from client to the face service.
+ * @hide
+ */
+interface IFaceService {
+ // Authenticate the given sessionId with a face
+ void authenticate(IBinder token, long sessionId,
+ IFaceServiceReceiver receiver, int flags, String opPackageName,
+ in Bundle bundle, IBiometricPromptReceiver dialogReceiver);
+
+ // Cancel authentication for the given sessionId
+ void cancelAuthentication(IBinder token, String opPackageName);
+
+ // Start face enrollment
+ void enroll(IBinder token, in byte [] cryptoToken, int userId, IFaceServiceReceiver receiver,
+ int flags, String opPackageName);
+
+ // Cancel enrollment in progress
+ void cancelEnrollment(IBinder token);
+
+ // Any errors resulting from this call will be returned to the listener
+ void remove(IBinder token, int faceId, int userId, IFaceServiceReceiver receiver);
+
+ // Rename the face specified by faceId to the given name
+ void rename(int faceId, String name);
+
+ // Get the enrolled face for user.
+ List<Face> getEnrolledFaces(int userId, String opPackageName);
+
+ // Determine if HAL is loaded and ready
+ boolean isHardwareDetected(long deviceId, String opPackageName);
+
+ // Get a pre-enrollment authentication token
+ long preEnroll(IBinder token);
+
+ // Finish an enrollment sequence and invalidate the authentication token
+ int postEnroll(IBinder token);
+
+ // Determine if a user has at least one enrolled face
+ boolean hasEnrolledFaces(int userId, String opPackageName);
+
+ // Gets the number of hardware devices
+ // int getHardwareDeviceCount();
+
+ // Gets the unique device id for hardware enumerated at i
+ // long getHardwareDevice(int i);
+
+ // Gets the authenticator ID for face
+ long getAuthenticatorId(String opPackageName);
+
+ // Reset the timeout when user authenticates with strong auth (e.g. PIN, pattern or password)
+ void resetTimeout(in byte [] cryptoToken);
+
+ // Add a callback which gets notified when the face lockout period expired.
+ void addLockoutResetCallback(IBiometricServiceLockoutResetCallback callback);
+
+ // Explicitly set the active user (for enrolling work profile)
+ void setActiveUser(int uid);
+
+ // Enumerate all faces
+ void enumerate(IBinder token, int userId, IFaceServiceReceiver receiver);
+}
diff --git a/core/java/android/hardware/face/IFaceServiceReceiver.aidl b/core/java/android/hardware/face/IFaceServiceReceiver.aidl
new file mode 100644
index 0000000..16fb690
--- /dev/null
+++ b/core/java/android/hardware/face/IFaceServiceReceiver.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2018 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.Face;
+import android.os.Bundle;
+import android.os.UserHandle;
+
+/**
+ * Communication channel from the FaceService back to FaceAuthenticationManager.
+ * @hide
+ */
+oneway interface IFaceServiceReceiver {
+ void onEnrollResult(long deviceId, int faceId, int remaining);
+ void onAcquired(long deviceId, int acquiredInfo, int vendorCode);
+ void onAuthenticationSucceeded(long deviceId, in Face face);
+ void onAuthenticationFailed(long deviceId);
+ void onError(long deviceId, int error, int vendorCode);
+ void onRemoved(long deviceId, int faceId, int remaining);
+}
diff --git a/core/java/android/hardware/fingerprint/Fingerprint.java b/core/java/android/hardware/fingerprint/Fingerprint.java
index c7ce8fa..bbd3d05 100644
--- a/core/java/android/hardware/fingerprint/Fingerprint.java
+++ b/core/java/android/hardware/fingerprint/Fingerprint.java
@@ -23,62 +23,36 @@
* Container for fingerprint metadata.
* @hide
*/
-public final class Fingerprint extends BiometricAuthenticator.BiometricIdentifier {
- private CharSequence mName;
+public final class Fingerprint extends BiometricAuthenticator.Identifier {
private int mGroupId;
- private int mFingerId;
- private long mDeviceId; // physical device this is associated with
public Fingerprint(CharSequence name, int groupId, int fingerId, long deviceId) {
- mName = name;
+ super(name, fingerId, deviceId);
mGroupId = groupId;
- mFingerId = fingerId;
- mDeviceId = deviceId;
}
private Fingerprint(Parcel in) {
- mName = in.readString();
+ super(in.readString(), in.readInt(), in.readLong());
mGroupId = in.readInt();
- mFingerId = in.readInt();
- mDeviceId = in.readLong();
}
/**
- * Gets the human-readable name for the given fingerprint.
- * @return name given to finger
- */
- public CharSequence getName() { return mName; }
-
- /**
- * Gets the device-specific finger id. Used by Settings to map a name to a specific
- * fingerprint template.
- * @return device-specific id for this finger
- * @hide
- */
- public int getFingerId() { return mFingerId; }
-
- /**
* Gets the group id specified when the fingerprint was enrolled.
* @return group id for the set of fingerprints this one belongs to.
- * @hide
*/
- public int getGroupId() { return mGroupId; }
-
- /**
- * Device this fingerprint belongs to.
- * @hide
- */
- public long getDeviceId() { return mDeviceId; }
+ public int getGroupId() {
+ return mGroupId;
+ }
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags) {
- out.writeString(mName.toString());
+ out.writeString(getName().toString());
+ out.writeInt(getBiometricId());
+ out.writeLong(getDeviceId());
out.writeInt(mGroupId);
- out.writeInt(mFingerId);
- out.writeLong(mDeviceId);
}
public static final Parcelable.Creator<Fingerprint> CREATOR
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index ebbfe1c..9192652 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -34,6 +34,7 @@
import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.IBiometricPromptReceiver;
+import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.os.Binder;
import android.os.Bundle;
import android.os.CancellationSignal;
@@ -403,7 +404,8 @@
/**
* Per-user version, see {@link FingerprintManager#authenticate(CryptoObject,
- * CancellationSignal, int, AuthenticationCallback, Handler)}
+ * CancellationSignal, int, AuthenticationCallback, Handler)}. This version does not
+ * display the BiometricPrompt.
* @param userId the user ID that the fingerprint hardware will authenticate for.
* @hide
*/
@@ -442,9 +444,7 @@
}
/**
- * Per-user version, see {@link FingerprintManager#authenticate(CryptoObject,
- * CancellationSignal, Bundle, Executor, IBiometricPromptReceiver, AuthenticationCallback)}
- * @param userId the user ID that the fingerprint hardware will authenticate for.
+ * Per-user version. This method invokes the BiometricPrompt.
*/
private void authenticate(int userId,
@Nullable android.hardware.biometrics.CryptoObject crypto,
@@ -657,7 +657,7 @@
if (mService != null) try {
mRemovalCallback = callback;
mRemovalFingerprint = fp;
- mService.remove(mToken, fp.getFingerId(), fp.getGroupId(), userId, mServiceReceiver);
+ mService.remove(mToken, fp.getBiometricId(), fp.getGroupId(), userId, mServiceReceiver);
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception in remove: ", e);
if (callback != null) {
@@ -841,7 +841,7 @@
try {
final PowerManager powerManager = mContext.getSystemService(PowerManager.class);
mService.addLockoutResetCallback(
- new IFingerprintServiceLockoutResetCallback.Stub() {
+ new IBiometricServiceLockoutResetCallback.Stub() {
@Override
public void onLockoutReset(long deviceId, IRemoteCallback serverCallback)
@@ -881,7 +881,7 @@
@Override
public void handleMessage(android.os.Message msg) {
- switch(msg.what) {
+ switch (msg.what) {
case MSG_ENROLL_RESULT:
sendEnrollResult((Fingerprint) msg.obj, msg.arg1 /* remaining */);
break;
@@ -908,45 +908,45 @@
break;
}
}
-
- private void sendRemovedResult(Fingerprint fingerprint, int remaining) {
- if (mRemovalCallback == null) {
- return;
- }
- if (fingerprint == null) {
- Slog.e(TAG, "Received MSG_REMOVED, but fingerprint is null");
- return;
- }
-
- int fingerId = fingerprint.getFingerId();
- int reqFingerId = mRemovalFingerprint.getFingerId();
- if (reqFingerId != 0 && fingerId != 0 && fingerId != reqFingerId) {
- Slog.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId);
- return;
- }
- int groupId = fingerprint.getGroupId();
- int reqGroupId = mRemovalFingerprint.getGroupId();
- if (groupId != reqGroupId) {
- Slog.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId);
- return;
- }
-
- mRemovalCallback.onRemovalSucceeded(fingerprint, remaining);
- }
-
- private void sendEnumeratedResult(long deviceId, int fingerId, int groupId) {
- if (mEnumerateCallback != null) {
- mEnumerateCallback.onEnumerate(new Fingerprint(null, groupId, fingerId, deviceId));
- }
- }
-
- private void sendEnrollResult(Fingerprint fp, int remaining) {
- if (mEnrollmentCallback != null) {
- mEnrollmentCallback.onEnrollmentProgress(remaining);
- }
- }
};
+ private void sendRemovedResult(Fingerprint fingerprint, int remaining) {
+ if (mRemovalCallback == null) {
+ return;
+ }
+ if (fingerprint == null) {
+ Slog.e(TAG, "Received MSG_REMOVED, but fingerprint is null");
+ return;
+ }
+
+ int fingerId = fingerprint.getBiometricId();
+ int reqFingerId = mRemovalFingerprint.getBiometricId();
+ if (reqFingerId != 0 && fingerId != 0 && fingerId != reqFingerId) {
+ Slog.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId);
+ return;
+ }
+ int groupId = fingerprint.getGroupId();
+ int reqGroupId = mRemovalFingerprint.getGroupId();
+ if (groupId != reqGroupId) {
+ Slog.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId);
+ return;
+ }
+
+ mRemovalCallback.onRemovalSucceeded(fingerprint, remaining);
+ }
+
+ private void sendEnumeratedResult(long deviceId, int fingerId, int groupId) {
+ if (mEnumerateCallback != null) {
+ mEnumerateCallback.onEnumerate(new Fingerprint(null, groupId, fingerId, deviceId));
+ }
+ }
+
+ private void sendEnrollResult(Fingerprint fp, int remaining) {
+ if (mEnrollmentCallback != null) {
+ mEnrollmentCallback.onEnrollmentProgress(remaining);
+ }
+ }
+
private void sendAuthenticatedSucceeded(Fingerprint fp, int userId) {
if (mAuthenticationCallback != null) {
final BiometricAuthenticator.AuthenticationResult result =
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 8aa2183..71a6420 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -17,9 +17,9 @@
import android.os.Bundle;
import android.hardware.biometrics.IBiometricPromptReceiver;
+import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.fingerprint.IFingerprintClientActiveCallback;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
-import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
import android.hardware.fingerprint.Fingerprint;
import java.util.List;
@@ -78,7 +78,7 @@
void resetTimeout(in byte [] cryptoToken);
// Add a callback which gets notified when the fingerprint lockout period expired.
- void addLockoutResetCallback(IFingerprintServiceLockoutResetCallback callback);
+ void addLockoutResetCallback(IBiometricServiceLockoutResetCallback callback);
// Explicitly set the active user (for enrolling work profile)
void setActiveUser(int uid);
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index b4c8a5e..431c651 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -370,19 +370,6 @@
InputConnection mStartedInputConnection;
EditorInfo mInputEditorInfo;
- /**
- * A token to keep tracking the last IPC that triggered
- * {@link #doStartInput(InputConnection, EditorInfo, boolean)}. If
- * {@link #doStartInput(InputConnection, EditorInfo, boolean)} was not caused by IPCs from
- * {@link com.android.server.InputMethodManagerService}, this needs to remain unchanged.
- *
- * <p>Some IPCs to {@link com.android.server.InputMethodManagerService} require this token to
- * disentangle event flows for various purposes such as better window animation and providing
- * fine-grained debugging information.</p>
- */
- @Nullable
- private IBinder mStartInputToken;
-
int mShowInputFlags;
boolean mShowInputRequested;
boolean mLastShowInputRequested;
@@ -528,7 +515,7 @@
public void dispatchStartInputWithToken(@Nullable InputConnection inputConnection,
@NonNull EditorInfo editorInfo, boolean restarting,
@NonNull IBinder startInputToken) {
- mStartInputToken = startInputToken;
+ mImm.reportStartInput(mToken, startInputToken);
// This needs to be dispatched to interface methods rather than doStartInput().
// Otherwise IME developers who have overridden those interface methods will lose
@@ -579,8 +566,8 @@
}
clearInsetOfPreviousIme();
// If user uses hard keyboard, IME button should always be shown.
- mImm.setImeWindowStatus(mToken, mStartInputToken,
- mapToImeWindowStatus(isInputViewShown()), mBackDisposition);
+ mImm.setImeWindowStatus(mToken, mapToImeWindowStatus(isInputViewShown()),
+ mBackDisposition);
if (resultReceiver != null) {
resultReceiver.send(wasVis != isInputViewShown()
? InputMethodManager.RESULT_SHOWN
@@ -1059,8 +1046,8 @@
}
// If user uses hard keyboard, IME button should always be shown.
boolean showing = onEvaluateInputViewShown();
- mImm.setImeWindowStatus(mToken, mStartInputToken,
- IME_ACTIVE | (showing ? IME_VISIBLE : 0), mBackDisposition);
+ mImm.setImeWindowStatus(mToken, IME_ACTIVE | (showing ? IME_VISIBLE : 0),
+ mBackDisposition);
}
}
@@ -1110,8 +1097,7 @@
return;
}
mBackDisposition = disposition;
- mImm.setImeWindowStatus(mToken, mStartInputToken, mapToImeWindowStatus(isInputViewShown()),
- mBackDisposition);
+ mImm.setImeWindowStatus(mToken, mapToImeWindowStatus(isInputViewShown()), mBackDisposition);
}
/**
@@ -1861,8 +1847,7 @@
final int nextImeWindowStatus = mapToImeWindowStatus(isInputViewShown());
if (previousImeWindowStatus != nextImeWindowStatus) {
- mImm.setImeWindowStatus(mToken, mStartInputToken, nextImeWindowStatus,
- mBackDisposition);
+ mImm.setImeWindowStatus(mToken, nextImeWindowStatus, mBackDisposition);
}
if ((previousImeWindowStatus & IME_ACTIVE) == 0) {
if (DEBUG) Log.v(TAG, "showWindow: showing!");
@@ -1887,7 +1872,7 @@
}
private void doHideWindow() {
- mImm.setImeWindowStatus(mToken, mStartInputToken, 0, mBackDisposition);
+ mImm.setImeWindowStatus(mToken, 0, mBackDisposition);
hideWindow();
}
@@ -2869,7 +2854,6 @@
p.println(" mInputStarted=" + mInputStarted
+ " mInputViewStarted=" + mInputViewStarted
+ " mCandidatesViewStarted=" + mCandidatesViewStarted);
- p.println(" mStartInputToken=" + mStartInputToken);
if (mInputEditorInfo != null) {
p.println(" mInputEditorInfo:");
diff --git a/core/java/android/os/IncidentReportArgs.java b/core/java/android/os/IncidentReportArgs.java
index 1aeac5f..3ca7f77 100644
--- a/core/java/android/os/IncidentReportArgs.java
+++ b/core/java/android/os/IncidentReportArgs.java
@@ -144,7 +144,6 @@
/**
* Set this incident report privacy policy spec.
- * @hide
*/
public void setPrivacyPolicy(int dest) {
switch (dest) {
diff --git a/core/java/android/os/RedactingFileDescriptor.java b/core/java/android/os/RedactingFileDescriptor.java
new file mode 100644
index 0000000..60eb5c3
--- /dev/null
+++ b/core/java/android/os/RedactingFileDescriptor.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.content.Context;
+import android.os.storage.StorageManager;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+import android.util.Slog;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+
+/**
+ * Variant of {@link FileDescriptor} that allows its creator to specify regions
+ * that should be redacted (appearing as zeros to the reader).
+ *
+ * @hide
+ */
+public class RedactingFileDescriptor {
+ private static final String TAG = "RedactingFileDescriptor";
+ private static final boolean DEBUG = true;
+
+ private final long[] mRedactRanges;
+
+ private FileDescriptor mInner = null;
+ private ParcelFileDescriptor mOuter = null;
+
+ private RedactingFileDescriptor(Context context, File file, long[] redactRanges)
+ throws IOException {
+ mRedactRanges = checkRangesArgument(redactRanges);
+
+ try {
+ try {
+ mInner = Os.open(file.getAbsolutePath(), OsConstants.O_RDONLY, 0);
+ mOuter = context.getSystemService(StorageManager.class)
+ .openProxyFileDescriptor(ParcelFileDescriptor.MODE_READ_ONLY, mCallback);
+ } catch (ErrnoException e) {
+ throw e.rethrowAsIOException();
+ }
+ } catch (IOException e) {
+ IoUtils.closeQuietly(mInner);
+ IoUtils.closeQuietly(mOuter);
+ throw e;
+ }
+ }
+
+ private static long[] checkRangesArgument(long[] ranges) {
+ if (ranges.length % 2 != 0) {
+ throw new IllegalArgumentException();
+ }
+ for (int i = 0; i < ranges.length - 1; i += 2) {
+ if (ranges[i] > ranges[i + 1]) {
+ throw new IllegalArgumentException();
+ }
+ }
+ return ranges;
+ }
+
+ /**
+ * Open the given {@link File} and returns a {@link ParcelFileDescriptor}
+ * that offers a redacted, read-only view of the underlying data.
+ *
+ * @param file The underlying file to open.
+ * @param redactRanges List of file offsets that should be redacted, stored
+ * as {@code [start1, end1, start2, end2, ...]}. Start values are
+ * inclusive and end values are exclusive.
+ */
+ public static ParcelFileDescriptor open(Context context, File file, long[] redactRanges)
+ throws IOException {
+ return new RedactingFileDescriptor(context, file, redactRanges).mOuter;
+ }
+
+ private final ProxyFileDescriptorCallback mCallback = new ProxyFileDescriptorCallback() {
+ @Override
+ public long onGetSize() throws ErrnoException {
+ return Os.fstat(mInner).st_size;
+ }
+
+ @Override
+ public int onRead(long offset, int size, byte[] data) throws ErrnoException {
+ int n = 0;
+ while (n < size) {
+ try {
+ final int res = Os.pread(mInner, data, n, size - n, offset + n);
+ if (res == 0) {
+ break;
+ } else {
+ n += res;
+ }
+ } catch (InterruptedIOException e) {
+ n += e.bytesTransferred;
+ }
+ }
+
+ // Redact any relevant ranges before returning
+ final long[] ranges = mRedactRanges;
+ for (int i = 0; i < ranges.length; i += 2) {
+ final long start = Math.max(offset, ranges[i]);
+ final long end = Math.min(offset + size, ranges[i + 1]);
+ for (long j = start; j < end; j++) {
+ data[(int) (j - offset)] = 0;
+ }
+ }
+ return n;
+ }
+
+ @Override
+ public int onWrite(long offset, int size, byte[] data) throws ErrnoException {
+ throw new ErrnoException(TAG, OsConstants.EBADF);
+ }
+
+ @Override
+ public void onFsync() throws ErrnoException {
+ Os.fsync(mInner);
+ }
+
+ @Override
+ public void onRelease() {
+ if (DEBUG) Slog.v(TAG, "onRelease()");
+ IoUtils.closeQuietly(mInner);
+ }
+ };
+}
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index f224550..ea76c9a3 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -16,6 +16,7 @@
package android.os;
import android.animation.ValueAnimator;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
@@ -27,6 +28,7 @@
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.net.TrafficStats;
import android.net.Uri;
import android.os.strictmode.CleartextNetworkViolation;
@@ -36,6 +38,7 @@
import android.os.strictmode.DiskWriteViolation;
import android.os.strictmode.ExplicitGcViolation;
import android.os.strictmode.FileUriExposedViolation;
+import android.os.strictmode.ImplicitDirectBootViolation;
import android.os.strictmode.InstanceCountViolation;
import android.os.strictmode.IntentReceiverLeakedViolation;
import android.os.strictmode.LeakedClosableViolation;
@@ -68,6 +71,8 @@
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayDeque;
@@ -187,116 +192,103 @@
// of the Looper.
private static final int MAX_OFFENSES_PER_LOOP = 10;
- // Byte 1: Thread-policy
+ /** @hide */
+ @IntDef(flag = true, prefix = { "DETECT_THREAD_", "PENALTY_" }, value = {
+ DETECT_THREAD_DISK_WRITE,
+ DETECT_THREAD_DISK_READ,
+ DETECT_THREAD_NETWORK,
+ DETECT_THREAD_CUSTOM,
+ DETECT_THREAD_RESOURCE_MISMATCH,
+ DETECT_THREAD_UNBUFFERED_IO,
+ DETECT_THREAD_EXPLICIT_GC,
+ PENALTY_GATHER,
+ PENALTY_LOG,
+ PENALTY_DIALOG,
+ PENALTY_DEATH,
+ PENALTY_FLASH,
+ PENALTY_DROPBOX,
+ PENALTY_DEATH_ON_NETWORK,
+ PENALTY_DEATH_ON_CLEARTEXT_NETWORK,
+ PENALTY_DEATH_ON_FILE_URI_EXPOSURE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ThreadPolicyMask {}
+
+ // Thread policy: bits 0-15
/** @hide */
- @TestApi public static final int DETECT_DISK_WRITE = 0x01; // for ThreadPolicy
-
+ private static final int DETECT_THREAD_DISK_WRITE = 1 << 0;
/** @hide */
- @TestApi public static final int DETECT_DISK_READ = 0x02; // for ThreadPolicy
-
+ private static final int DETECT_THREAD_DISK_READ = 1 << 1;
/** @hide */
- @TestApi public static final int DETECT_NETWORK = 0x04; // for ThreadPolicy
-
- /**
- * For StrictMode.noteSlowCall()
- *
- * @hide
- */
- @TestApi public static final int DETECT_CUSTOM = 0x08; // for ThreadPolicy
-
- /**
- * For StrictMode.noteResourceMismatch()
- *
- * @hide
- */
- @TestApi public static final int DETECT_RESOURCE_MISMATCH = 0x10; // for ThreadPolicy
-
+ private static final int DETECT_THREAD_NETWORK = 1 << 2;
/** @hide */
- @TestApi public static final int DETECT_UNBUFFERED_IO = 0x20; // for ThreadPolicy
-
+ private static final int DETECT_THREAD_CUSTOM = 1 << 3;
+ /** @hide */
+ private static final int DETECT_THREAD_RESOURCE_MISMATCH = 1 << 4;
+ /** @hide */
+ private static final int DETECT_THREAD_UNBUFFERED_IO = 1 << 5;
/** @hide */
- public static final int DETECT_EXPLICIT_GC = 0x40; // for ThreadPolicy
-
- private static final int ALL_THREAD_DETECT_BITS =
- DETECT_DISK_WRITE
- | DETECT_DISK_READ
- | DETECT_NETWORK
- | DETECT_CUSTOM
- | DETECT_RESOURCE_MISMATCH
- | DETECT_UNBUFFERED_IO
- | DETECT_EXPLICIT_GC;
-
- // Byte 2: Process-policy
-
- /**
- * Note, a "VM_" bit, not thread.
- *
- * @hide
- */
- @TestApi public static final int DETECT_VM_CURSOR_LEAKS = 0x01 << 8; // for VmPolicy
-
- /**
- * Note, a "VM_" bit, not thread.
- *
- * @hide
- */
- @TestApi public static final int DETECT_VM_CLOSABLE_LEAKS = 0x02 << 8; // for VmPolicy
-
- /**
- * Note, a "VM_" bit, not thread.
- *
- * @hide
- */
- @TestApi public static final int DETECT_VM_ACTIVITY_LEAKS = 0x04 << 8; // for VmPolicy
+ private static final int DETECT_THREAD_EXPLICIT_GC = 1 << 6;
/** @hide */
- @TestApi public static final int DETECT_VM_INSTANCE_LEAKS = 0x08 << 8; // for VmPolicy
+ private static final int DETECT_THREAD_ALL = 0x0000ffff;
/** @hide */
- @TestApi public static final int DETECT_VM_REGISTRATION_LEAKS = 0x10 << 8; // for VmPolicy
+ @IntDef(flag = true, prefix = { "DETECT_THREAD_", "PENALTY_" }, value = {
+ DETECT_VM_CURSOR_LEAKS,
+ DETECT_VM_CLOSABLE_LEAKS,
+ DETECT_VM_ACTIVITY_LEAKS,
+ DETECT_VM_INSTANCE_LEAKS,
+ DETECT_VM_REGISTRATION_LEAKS,
+ DETECT_VM_FILE_URI_EXPOSURE,
+ DETECT_VM_CLEARTEXT_NETWORK,
+ DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION,
+ DETECT_VM_UNTAGGED_SOCKET,
+ DETECT_VM_NON_SDK_API_USAGE,
+ DETECT_VM_IMPLICIT_DIRECT_BOOT,
+ PENALTY_GATHER,
+ PENALTY_LOG,
+ PENALTY_DIALOG,
+ PENALTY_DEATH,
+ PENALTY_FLASH,
+ PENALTY_DROPBOX,
+ PENALTY_DEATH_ON_NETWORK,
+ PENALTY_DEATH_ON_CLEARTEXT_NETWORK,
+ PENALTY_DEATH_ON_FILE_URI_EXPOSURE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface VmPolicyMask {}
+
+ // VM policy: bits 0-15
/** @hide */
- @TestApi public static final int DETECT_VM_FILE_URI_EXPOSURE = 0x20 << 8; // for VmPolicy
+ private static final int DETECT_VM_CURSOR_LEAKS = 1 << 0;
+ /** @hide */
+ private static final int DETECT_VM_CLOSABLE_LEAKS = 1 << 1;
+ /** @hide */
+ private static final int DETECT_VM_ACTIVITY_LEAKS = 1 << 2;
+ /** @hide */
+ private static final int DETECT_VM_INSTANCE_LEAKS = 1 << 3;
+ /** @hide */
+ private static final int DETECT_VM_REGISTRATION_LEAKS = 1 << 4;
+ /** @hide */
+ private static final int DETECT_VM_FILE_URI_EXPOSURE = 1 << 5;
+ /** @hide */
+ private static final int DETECT_VM_CLEARTEXT_NETWORK = 1 << 6;
+ /** @hide */
+ private static final int DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION = 1 << 7;
+ /** @hide */
+ private static final int DETECT_VM_UNTAGGED_SOCKET = 1 << 8;
+ /** @hide */
+ private static final int DETECT_VM_NON_SDK_API_USAGE = 1 << 9;
+ /** @hide */
+ private static final int DETECT_VM_IMPLICIT_DIRECT_BOOT = 1 << 10;
/** @hide */
- @TestApi public static final int DETECT_VM_CLEARTEXT_NETWORK = 0x40 << 8; // for VmPolicy
+ private static final int DETECT_VM_ALL = 0x0000ffff;
- /** @hide */
- @TestApi
- public static final int DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION = 0x80 << 8; // for VmPolicy
-
- /** @hide */
- @TestApi public static final int DETECT_VM_UNTAGGED_SOCKET = 0x80 << 24; // for VmPolicy
-
- /** @hide */
- @TestApi public static final int DETECT_VM_NON_SDK_API_USAGE = 0x40 << 24; // for VmPolicy
-
- private static final int ALL_VM_DETECT_BITS =
- DETECT_VM_CURSOR_LEAKS
- | DETECT_VM_CLOSABLE_LEAKS
- | DETECT_VM_ACTIVITY_LEAKS
- | DETECT_VM_INSTANCE_LEAKS
- | DETECT_VM_REGISTRATION_LEAKS
- | DETECT_VM_FILE_URI_EXPOSURE
- | DETECT_VM_CLEARTEXT_NETWORK
- | DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION
- | DETECT_VM_UNTAGGED_SOCKET
- | DETECT_VM_NON_SDK_API_USAGE;
-
-
- // Byte 3: Penalty
-
- /** {@hide} */
- public static final int PENALTY_LOG = 0x01 << 16; // normal android.util.Log
- /** {@hide} */
- public static final int PENALTY_DIALOG = 0x02 << 16;
- /** {@hide} */
- public static final int PENALTY_DEATH = 0x04 << 16;
- /** {@hide} */
- public static final int PENALTY_FLASH = 0x10 << 16;
- /** {@hide} */
- public static final int PENALTY_DROPBOX = 0x20 << 16;
+ // Penalty policy: bits 16-31
/**
* Non-public penalty mode which overrides all the other penalty bits and signals that we're in
@@ -307,50 +299,27 @@
*
* @hide
*/
- public static final int PENALTY_GATHER = 0x40 << 16;
+ public static final int PENALTY_GATHER = 1 << 31;
- // Byte 4: Special cases
+ /** {@hide} */
+ public static final int PENALTY_LOG = 1 << 30;
+ /** {@hide} */
+ public static final int PENALTY_DIALOG = 1 << 29;
+ /** {@hide} */
+ public static final int PENALTY_DEATH = 1 << 28;
+ /** {@hide} */
+ public static final int PENALTY_FLASH = 1 << 27;
+ /** {@hide} */
+ public static final int PENALTY_DROPBOX = 1 << 26;
+ /** {@hide} */
+ public static final int PENALTY_DEATH_ON_NETWORK = 1 << 25;
+ /** {@hide} */
+ public static final int PENALTY_DEATH_ON_CLEARTEXT_NETWORK = 1 << 24;
+ /** {@hide} */
+ public static final int PENALTY_DEATH_ON_FILE_URI_EXPOSURE = 1 << 23;
- /**
- * Death when network traffic is detected on main thread.
- *
- * @hide
- */
- public static final int PENALTY_DEATH_ON_NETWORK = 0x01 << 24;
-
- /**
- * Death when cleartext network traffic is detected.
- *
- * @hide
- */
- public static final int PENALTY_DEATH_ON_CLEARTEXT_NETWORK = 0x02 << 24;
-
- /**
- * Death when file exposure is detected.
- *
- * @hide
- */
- public static final int PENALTY_DEATH_ON_FILE_URI_EXPOSURE = 0x04 << 24;
-
- // CAUTION: we started stealing the top bits of Byte 4 for VM above
-
- /** Mask of all the penalty bits valid for thread policies. */
- private static final int THREAD_PENALTY_MASK =
- PENALTY_LOG
- | PENALTY_DIALOG
- | PENALTY_DEATH
- | PENALTY_DROPBOX
- | PENALTY_GATHER
- | PENALTY_DEATH_ON_NETWORK
- | PENALTY_FLASH;
-
- /** Mask of all the penalty bits valid for VM policies. */
- private static final int VM_PENALTY_MASK =
- PENALTY_LOG
- | PENALTY_DEATH
- | PENALTY_DROPBOX
- | PENALTY_DEATH_ON_CLEARTEXT_NETWORK
- | PENALTY_DEATH_ON_FILE_URI_EXPOSURE;
+ /** @hide */
+ public static final int PENALTY_ALL = 0xffff0000;
/** {@hide} */
public static final int NETWORK_POLICY_ACCEPT = 0;
@@ -448,11 +417,12 @@
/** The default, lax policy which doesn't catch anything. */
public static final ThreadPolicy LAX = new ThreadPolicy(0, null, null);
- final int mask;
+ final @ThreadPolicyMask int mask;
final OnThreadViolationListener mListener;
final Executor mCallbackExecutor;
- private ThreadPolicy(int mask, OnThreadViolationListener listener, Executor executor) {
+ private ThreadPolicy(@ThreadPolicyMask int mask, OnThreadViolationListener listener,
+ Executor executor) {
this.mask = mask;
mListener = listener;
mCallbackExecutor = executor;
@@ -482,7 +452,7 @@
* </pre>
*/
public static final class Builder {
- private int mMask = 0;
+ private @ThreadPolicyMask int mMask = 0;
private OnThreadViolationListener mListener;
private Executor mExecutor;
@@ -528,52 +498,52 @@
/** Disable the detection of everything. */
public Builder permitAll() {
- return disable(ALL_THREAD_DETECT_BITS);
+ return disable(DETECT_THREAD_ALL);
}
/** Enable detection of network operations. */
public Builder detectNetwork() {
- return enable(DETECT_NETWORK);
+ return enable(DETECT_THREAD_NETWORK);
}
/** Disable detection of network operations. */
public Builder permitNetwork() {
- return disable(DETECT_NETWORK);
+ return disable(DETECT_THREAD_NETWORK);
}
/** Enable detection of disk reads. */
public Builder detectDiskReads() {
- return enable(DETECT_DISK_READ);
+ return enable(DETECT_THREAD_DISK_READ);
}
/** Disable detection of disk reads. */
public Builder permitDiskReads() {
- return disable(DETECT_DISK_READ);
+ return disable(DETECT_THREAD_DISK_READ);
}
/** Enable detection of slow calls. */
public Builder detectCustomSlowCalls() {
- return enable(DETECT_CUSTOM);
+ return enable(DETECT_THREAD_CUSTOM);
}
/** Disable detection of slow calls. */
public Builder permitCustomSlowCalls() {
- return disable(DETECT_CUSTOM);
+ return disable(DETECT_THREAD_CUSTOM);
}
/** Disable detection of mismatches between defined resource types and getter calls. */
public Builder permitResourceMismatches() {
- return disable(DETECT_RESOURCE_MISMATCH);
+ return disable(DETECT_THREAD_RESOURCE_MISMATCH);
}
/** Detect unbuffered input/output operations. */
public Builder detectUnbufferedIo() {
- return enable(DETECT_UNBUFFERED_IO);
+ return enable(DETECT_THREAD_UNBUFFERED_IO);
}
/** Disable detection of unbuffered input/output operations. */
public Builder permitUnbufferedIo() {
- return disable(DETECT_UNBUFFERED_IO);
+ return disable(DETECT_THREAD_UNBUFFERED_IO);
}
/**
@@ -589,17 +559,17 @@
* resource as an integer to avoid unnecessary type conversion.
*/
public Builder detectResourceMismatches() {
- return enable(DETECT_RESOURCE_MISMATCH);
+ return enable(DETECT_THREAD_RESOURCE_MISMATCH);
}
/** Enable detection of disk writes. */
public Builder detectDiskWrites() {
- return enable(DETECT_DISK_WRITE);
+ return enable(DETECT_THREAD_DISK_WRITE);
}
/** Disable detection of disk writes. */
public Builder permitDiskWrites() {
- return disable(DETECT_DISK_WRITE);
+ return disable(DETECT_THREAD_DISK_WRITE);
}
/**
@@ -612,7 +582,7 @@
// TODO(b/3400644): Un-hide ExplicitGcViolation for next API update
// TODO(b/3400644): Make DETECT_EXPLICIT_GC a @TestApi for next API update
// TODO(b/3400644): Call this from detectAll in next API update
- return enable(DETECT_EXPLICIT_GC);
+ return enable(DETECT_THREAD_EXPLICIT_GC);
}
/**
@@ -622,7 +592,7 @@
*/
public Builder permitExplicitGc() {
// TODO(b/3400644): Un-hide this for next API update
- return disable(DETECT_EXPLICIT_GC);
+ return disable(DETECT_THREAD_EXPLICIT_GC);
}
/**
@@ -695,13 +665,13 @@
return penaltyListener(executor, listener);
}
- private Builder enable(int bit) {
- mMask |= bit;
+ private Builder enable(@ThreadPolicyMask int mask) {
+ mMask |= mask;
return this;
}
- private Builder disable(int bit) {
- mMask &= ~bit;
+ private Builder disable(@ThreadPolicyMask int mask) {
+ mMask &= ~mask;
return this;
}
@@ -738,7 +708,7 @@
/** The default, lax policy which doesn't catch anything. */
public static final VmPolicy LAX = new VmPolicy(0, EMPTY_CLASS_LIMIT_MAP, null, null);
- final int mask;
+ final @VmPolicyMask int mask;
final OnVmViolationListener mListener;
final Executor mCallbackExecutor;
@@ -746,7 +716,7 @@
final HashMap<Class, Integer> classInstanceLimit;
private VmPolicy(
- int mask,
+ @VmPolicyMask int mask,
HashMap<Class, Integer> classInstanceLimit,
OnVmViolationListener listener,
Executor executor) {
@@ -783,7 +753,7 @@
* </pre>
*/
public static final class Builder {
- private int mMask;
+ private @VmPolicyMask int mMask;
private OnVmViolationListener mListener;
private Executor mExecutor;
@@ -891,6 +861,8 @@
}
// TODO: Decide whether to detect non SDK API usage beyond a certain API level.
+ // TODO: enable detectImplicitDirectBoot() once system is less noisy
+
return this;
}
@@ -999,6 +971,29 @@
}
/**
+ * Detect any implicit reliance on Direct Boot automatic filtering
+ * of {@link PackageManager} values. Violations are only triggered
+ * when implicit calls are made while the user is locked.
+ * <p>
+ * Apps becoming Direct Boot aware need to carefully inspect each
+ * query site and explicitly decide which combination of flags they
+ * want to use:
+ * <ul>
+ * <li>{@link PackageManager#MATCH_DIRECT_BOOT_AWARE}
+ * <li>{@link PackageManager#MATCH_DIRECT_BOOT_UNAWARE}
+ * <li>{@link PackageManager#MATCH_DIRECT_BOOT_AUTO}
+ * </ul>
+ */
+ public Builder detectImplicitDirectBoot() {
+ return enable(DETECT_VM_IMPLICIT_DIRECT_BOOT);
+ }
+
+ /** @hide */
+ public Builder permitImplicitDirectBoot() {
+ return disable(DETECT_VM_IMPLICIT_DIRECT_BOOT);
+ }
+
+ /**
* Crashes the whole process on violation. This penalty runs at the end of all enabled
* penalties so you'll still get your logging or other violations before the process
* dies.
@@ -1059,13 +1054,13 @@
return penaltyListener(executor, listener);
}
- private Builder enable(int bit) {
- mMask |= bit;
+ private Builder enable(@VmPolicyMask int mask) {
+ mMask |= mask;
return this;
}
- Builder disable(int bit) {
- mMask &= ~bit;
+ Builder disable(@VmPolicyMask int mask) {
+ mMask &= ~mask;
return this;
}
@@ -1130,21 +1125,21 @@
}
/** @hide */
- public static void setThreadPolicyMask(final int policyMask) {
+ public static void setThreadPolicyMask(@ThreadPolicyMask int threadPolicyMask) {
// In addition to the Java-level thread-local in Dalvik's
// BlockGuard, we also need to keep a native thread-local in
// Binder in order to propagate the value across Binder calls,
// even across native-only processes. The two are kept in
// sync via the callback to onStrictModePolicyChange, below.
- setBlockGuardPolicy(policyMask);
+ setBlockGuardPolicy(threadPolicyMask);
// And set the Android native version...
- Binder.setThreadStrictModePolicy(policyMask);
+ Binder.setThreadStrictModePolicy(threadPolicyMask);
}
// Sets the policy in Dalvik/libcore (BlockGuard)
- private static void setBlockGuardPolicy(final int policyMask) {
- if (policyMask == 0) {
+ private static void setBlockGuardPolicy(@ThreadPolicyMask int threadPolicyMask) {
+ if (threadPolicyMask == 0) {
BlockGuard.setThreadPolicy(BlockGuard.LAX_POLICY);
return;
}
@@ -1156,7 +1151,7 @@
androidPolicy = THREAD_ANDROID_POLICY.get();
BlockGuard.setThreadPolicy(androidPolicy);
}
- androidPolicy.setPolicyMask(policyMask);
+ androidPolicy.setThreadPolicyMask(threadPolicyMask);
}
// Sets up CloseGuard in Dalvik/libcore
@@ -1173,8 +1168,13 @@
* @return the bitmask of all the DETECT_* and PENALTY_* bits currently enabled
* @hide
*/
- public static int getThreadPolicyMask() {
- return BlockGuard.getThreadPolicy().getPolicyMask();
+ public static @ThreadPolicyMask int getThreadPolicyMask() {
+ final BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
+ if (policy instanceof AndroidBlockGuardPolicy) {
+ return ((AndroidBlockGuardPolicy) policy).getThreadPolicyMask();
+ } else {
+ return 0;
+ }
}
/** Returns the current thread's policy. */
@@ -1206,9 +1206,9 @@
}
/** @hide */
- public static int allowThreadDiskWritesMask() {
+ public static @ThreadPolicyMask int allowThreadDiskWritesMask() {
int oldPolicyMask = getThreadPolicyMask();
- int newPolicyMask = oldPolicyMask & ~(DETECT_DISK_WRITE | DETECT_DISK_READ);
+ int newPolicyMask = oldPolicyMask & ~(DETECT_THREAD_DISK_WRITE | DETECT_THREAD_DISK_READ);
if (newPolicyMask != oldPolicyMask) {
setThreadPolicyMask(newPolicyMask);
}
@@ -1230,9 +1230,9 @@
}
/** @hide */
- public static int allowThreadDiskReadsMask() {
+ public static @ThreadPolicyMask int allowThreadDiskReadsMask() {
int oldPolicyMask = getThreadPolicyMask();
- int newPolicyMask = oldPolicyMask & ~(DETECT_DISK_READ);
+ int newPolicyMask = oldPolicyMask & ~(DETECT_THREAD_DISK_READ);
if (newPolicyMask != oldPolicyMask) {
setThreadPolicyMask(newPolicyMask);
}
@@ -1400,32 +1400,6 @@
sVmPolicy.mCallbackExecutor);
}
- /**
- * Parses the BlockGuard policy mask out from the Exception's getMessage() String value. Kinda
- * gross, but least invasive. :/
- *
- * <p>Input is of the following forms: "policy=137 violation=64" "policy=137 violation=64
- * msg=Arbitrary text"
- *
- * <p>Returns 0 on failure, which is a valid policy, but not a valid policy during a violation
- * (else there must've been some policy in effect to violate).
- */
- private static int parsePolicyFromMessage(String message) {
- if (message == null || !message.startsWith("policy=")) {
- return 0;
- }
- int spaceIndex = message.indexOf(' ');
- if (spaceIndex == -1) {
- return 0;
- }
- String policyString = message.substring(7, spaceIndex);
- try {
- return Integer.parseInt(policyString);
- } catch (NumberFormatException e) {
- return 0;
- }
- }
-
private static final ThreadLocal<ArrayList<ViolationInfo>> violationsBeingTimed =
new ThreadLocal<ArrayList<ViolationInfo>>() {
@Override
@@ -1456,30 +1430,30 @@
}
private static class AndroidBlockGuardPolicy implements BlockGuard.Policy {
- private int mPolicyMask;
+ private @ThreadPolicyMask int mThreadPolicyMask;
// Map from violation stacktrace hashcode -> uptimeMillis of
// last violation. No locking needed, as this is only
// accessed by the same thread.
private ArrayMap<Integer, Long> mLastViolationTime;
- public AndroidBlockGuardPolicy(final int policyMask) {
- mPolicyMask = policyMask;
+ public AndroidBlockGuardPolicy(@ThreadPolicyMask int threadPolicyMask) {
+ mThreadPolicyMask = threadPolicyMask;
}
@Override
public String toString() {
- return "AndroidBlockGuardPolicy; mPolicyMask=" + mPolicyMask;
+ return "AndroidBlockGuardPolicy; mPolicyMask=" + mThreadPolicyMask;
}
// Part of BlockGuard.Policy interface:
public int getPolicyMask() {
- return mPolicyMask;
+ return mThreadPolicyMask;
}
// Part of BlockGuard.Policy interface:
public void onWriteToDisk() {
- if ((mPolicyMask & DETECT_DISK_WRITE) == 0) {
+ if ((mThreadPolicyMask & DETECT_THREAD_DISK_WRITE) == 0) {
return;
}
if (tooManyViolationsThisLoop()) {
@@ -1490,7 +1464,7 @@
// Not part of BlockGuard.Policy; just part of StrictMode:
void onCustomSlowCall(String name) {
- if ((mPolicyMask & DETECT_CUSTOM) == 0) {
+ if ((mThreadPolicyMask & DETECT_THREAD_CUSTOM) == 0) {
return;
}
if (tooManyViolationsThisLoop()) {
@@ -1501,7 +1475,7 @@
// Not part of BlockGuard.Policy; just part of StrictMode:
void onResourceMismatch(Object tag) {
- if ((mPolicyMask & DETECT_RESOURCE_MISMATCH) == 0) {
+ if ((mThreadPolicyMask & DETECT_THREAD_RESOURCE_MISMATCH) == 0) {
return;
}
if (tooManyViolationsThisLoop()) {
@@ -1512,7 +1486,7 @@
// Not part of BlockGuard.Policy; just part of StrictMode:
public void onUnbufferedIO() {
- if ((mPolicyMask & DETECT_UNBUFFERED_IO) == 0) {
+ if ((mThreadPolicyMask & DETECT_THREAD_UNBUFFERED_IO) == 0) {
return;
}
if (tooManyViolationsThisLoop()) {
@@ -1523,7 +1497,7 @@
// Part of BlockGuard.Policy interface:
public void onReadFromDisk() {
- if ((mPolicyMask & DETECT_DISK_READ) == 0) {
+ if ((mThreadPolicyMask & DETECT_THREAD_DISK_READ) == 0) {
return;
}
if (tooManyViolationsThisLoop()) {
@@ -1534,10 +1508,10 @@
// Part of BlockGuard.Policy interface:
public void onNetwork() {
- if ((mPolicyMask & DETECT_NETWORK) == 0) {
+ if ((mThreadPolicyMask & DETECT_THREAD_NETWORK) == 0) {
return;
}
- if ((mPolicyMask & PENALTY_DEATH_ON_NETWORK) != 0) {
+ if ((mThreadPolicyMask & PENALTY_DEATH_ON_NETWORK) != 0) {
throw new NetworkOnMainThreadException();
}
if (tooManyViolationsThisLoop()) {
@@ -1548,7 +1522,7 @@
// Part of BlockGuard.Policy interface:
public void onExplicitGc() {
- if ((mPolicyMask & DETECT_EXPLICIT_GC) == 0) {
+ if ((mThreadPolicyMask & DETECT_THREAD_EXPLICIT_GC) == 0) {
return;
}
if (tooManyViolationsThisLoop()) {
@@ -1557,8 +1531,12 @@
startHandlingViolationException(new ExplicitGcViolation());
}
- public void setPolicyMask(int policyMask) {
- mPolicyMask = policyMask;
+ public @ThreadPolicyMask int getThreadPolicyMask() {
+ return mThreadPolicyMask;
+ }
+
+ public void setThreadPolicyMask(@ThreadPolicyMask int threadPolicyMask) {
+ mThreadPolicyMask = threadPolicyMask;
}
// Start handling a violation that just started and hasn't
@@ -1567,7 +1545,8 @@
// thread and, if so, uses it to roughly measure how long the
// violation took.
void startHandlingViolationException(Violation e) {
- final ViolationInfo info = new ViolationInfo(e, mPolicyMask);
+ final int penaltyMask = (mThreadPolicyMask & PENALTY_ALL);
+ final ViolationInfo info = new ViolationInfo(e, penaltyMask);
info.violationUptimeMillis = SystemClock.uptimeMillis();
handleViolationWithTimingAttempt(info);
}
@@ -1596,7 +1575,7 @@
//
// TODO: if in gather mode, ignore Looper.myLooper() and always
// go into this immediate mode?
- if (looper == null || (info.mPolicy & THREAD_PENALTY_MASK) == PENALTY_DEATH) {
+ if (looper == null || (info.mPenaltyMask == PENALTY_DEATH)) {
info.durationMillis = -1; // unknown (redundant, already set)
onThreadPolicyViolation(info);
return;
@@ -1667,7 +1646,7 @@
// to people who push/pop temporary policy in regions of code,
// hence the policy being passed around.
void onThreadPolicyViolation(final ViolationInfo info) {
- if (LOG_V) Log.d(TAG, "onThreadPolicyViolation; policy=" + info.mPolicy);
+ if (LOG_V) Log.d(TAG, "onThreadPolicyViolation; penalty=" + info.mPenaltyMask);
if (info.penaltyEnabled(PENALTY_GATHER)) {
ArrayList<ViolationInfo> violations = gatheredViolations.get();
@@ -1708,25 +1687,20 @@
final Violation violation = info.mViolation;
- // The violationMaskSubset, passed to ActivityManager, is a
- // subset of the original StrictMode policy bitmask, with
- // only the bit violated and penalty bits to be executed
- // by the ActivityManagerService remaining set.
- int violationMaskSubset = 0;
+ // Penalties that ActivityManager should execute on our behalf.
+ int penaltyMask = 0;
if (info.penaltyEnabled(PENALTY_DIALOG)
&& timeSinceLastViolationMillis > MIN_DIALOG_INTERVAL_MS) {
- violationMaskSubset |= PENALTY_DIALOG;
+ penaltyMask |= PENALTY_DIALOG;
}
if (info.penaltyEnabled(PENALTY_DROPBOX) && lastViolationTime == 0) {
- violationMaskSubset |= PENALTY_DROPBOX;
+ penaltyMask |= PENALTY_DROPBOX;
}
- if (violationMaskSubset != 0) {
- violationMaskSubset |= info.getViolationBit();
-
- final boolean justDropBox = (info.mPolicy & THREAD_PENALTY_MASK) == PENALTY_DROPBOX;
+ if (penaltyMask != 0) {
+ final boolean justDropBox = (info.mPenaltyMask == PENALTY_DROPBOX);
if (justDropBox) {
// If all we're going to ask the activity manager
// to do is dropbox it (the common case during
@@ -1734,13 +1708,13 @@
// call synchronously which Binder data suggests
// isn't always super fast, despite the implementation
// in the ActivityManager trying to be mostly async.
- dropboxViolationAsync(violationMaskSubset, info);
+ dropboxViolationAsync(penaltyMask, info);
} else {
- handleApplicationStrictModeViolation(violationMaskSubset, info);
+ handleApplicationStrictModeViolation(penaltyMask, info);
}
}
- if ((info.getPolicyMask() & PENALTY_DEATH) != 0) {
+ if (info.penaltyEnabled(PENALTY_DEATH)) {
throw new RuntimeException("StrictMode ThreadPolicy violation", violation);
}
@@ -1753,11 +1727,11 @@
executor.execute(
() -> {
// Lift violated policy to prevent infinite recursion.
- ThreadPolicy oldPolicy = allowThreadViolations();
+ ThreadPolicy oldPolicy = StrictMode.allowThreadViolations();
try {
listener.onThreadViolation(violation);
} finally {
- setThreadPolicy(oldPolicy);
+ StrictMode.setThreadPolicy(oldPolicy);
}
});
} catch (RejectedExecutionException e) {
@@ -1774,7 +1748,7 @@
* per-thread and vm-wide violations when applicable.
*/
private static void dropboxViolationAsync(
- final int violationMaskSubset, final ViolationInfo info) {
+ final int penaltyMask, final ViolationInfo info) {
int outstanding = sDropboxCallsInFlight.incrementAndGet();
if (outstanding > 20) {
// What's going on? Let's not make make the situation
@@ -1786,13 +1760,13 @@
if (LOG_V) Log.d(TAG, "Dropboxing async; in-flight=" + outstanding);
BackgroundThread.getHandler().post(() -> {
- handleApplicationStrictModeViolation(violationMaskSubset, info);
+ handleApplicationStrictModeViolation(penaltyMask, info);
int outstandingInner = sDropboxCallsInFlight.decrementAndGet();
if (LOG_V) Log.d(TAG, "Dropbox complete; in-flight=" + outstandingInner);
});
}
- private static void handleApplicationStrictModeViolation(int violationMaskSubset,
+ private static void handleApplicationStrictModeViolation(int penaltyMask,
ViolationInfo info) {
final int oldMask = getThreadPolicyMask();
try {
@@ -1807,7 +1781,7 @@
Log.w(TAG, "No activity manager; failed to Dropbox violation.");
} else {
am.handleApplicationStrictModeViolation(
- RuntimeInit.getApplicationObject(), violationMaskSubset, info);
+ RuntimeInit.getApplicationObject(), penaltyMask, info);
}
} catch (RemoteException e) {
if (e instanceof DeadObjectException) {
@@ -1894,7 +1868,7 @@
if (looper != null) {
MessageQueue mq = looper.mQueue;
if (policy.classInstanceLimit.size() == 0
- || (sVmPolicy.mask & VM_PENALTY_MASK) == 0) {
+ || (sVmPolicy.mask & PENALTY_ALL) == 0) {
mq.removeIdleHandler(sProcessIdleHandler);
sIsIdlerRegistered = false;
} else if (!sIsIdlerRegistered) {
@@ -1991,6 +1965,11 @@
}
/** @hide */
+ public static boolean vmImplicitDirectBootEnabled() {
+ return (sVmPolicy.mask & DETECT_VM_IMPLICIT_DIRECT_BOOT) != 0;
+ }
+
+ /** @hide */
public static void onSqliteObjectLeaked(String message, Throwable originStack) {
onVmPolicyViolation(new SqliteObjectLeakedViolation(message, originStack));
}
@@ -2062,6 +2041,11 @@
onVmPolicyViolation(new UntaggedSocketViolation());
}
+ /** @hide */
+ public static void onImplicitDirectBoot() {
+ onVmPolicyViolation(new ImplicitDirectBootViolation());
+ }
+
// Map from VM violation fingerprint to uptime millis.
private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<>();
@@ -2075,7 +2059,9 @@
final boolean penaltyDropbox = (sVmPolicy.mask & PENALTY_DROPBOX) != 0;
final boolean penaltyDeath = ((sVmPolicy.mask & PENALTY_DEATH) != 0) || forceDeath;
final boolean penaltyLog = (sVmPolicy.mask & PENALTY_LOG) != 0;
- final ViolationInfo info = new ViolationInfo(violation, sVmPolicy.mask);
+
+ final int penaltyMask = (sVmPolicy.mask & PENALTY_ALL);
+ final ViolationInfo info = new ViolationInfo(violation, penaltyMask);
// Erase stuff not relevant for process-wide violations
info.numAnimationsRunning = 0;
@@ -2104,16 +2090,14 @@
sLogger.log(info);
}
- int violationMaskSubset = PENALTY_DROPBOX | (ALL_VM_DETECT_BITS & sVmPolicy.mask);
-
if (penaltyDropbox) {
if (penaltyDeath) {
- handleApplicationStrictModeViolation(violationMaskSubset, info);
+ handleApplicationStrictModeViolation(PENALTY_DROPBOX, info);
} else {
// Common case for userdebug/eng builds. If no death and
// just dropboxing, we can do the ActivityManager call
// asynchronously.
- dropboxViolationAsync(violationMaskSubset, info);
+ dropboxViolationAsync(PENALTY_DROPBOX, info);
}
}
@@ -2188,7 +2172,7 @@
* Binder for its current (native) thread-local policy value and synchronize it to libcore's
* (Java) thread-local policy value.
*/
- private static void onBinderStrictModePolicyChange(int newPolicy) {
+ private static void onBinderStrictModePolicyChange(@ThreadPolicyMask int newPolicy) {
setBlockGuardPolicy(newPolicy);
}
@@ -2506,8 +2490,8 @@
/** Memoized stack trace of full violation. */
@Nullable private String mStackTrace;
- /** The strict mode policy mask at the time of violation. */
- private final int mPolicy;
+ /** The strict mode penalty mask at the time of violation. */
+ private final int mPenaltyMask;
/** The wall time duration of the violation, when known. -1 when not known. */
public int durationMillis = -1;
@@ -2538,9 +2522,9 @@
public long numInstances = -1;
/** Create an instance of ViolationInfo initialized from an exception. */
- ViolationInfo(Violation tr, int policy) {
+ ViolationInfo(Violation tr, int penaltyMask) {
this.mViolation = tr;
- this.mPolicy = policy;
+ this.mPenaltyMask = penaltyMask;
violationUptimeMillis = SystemClock.uptimeMillis();
this.numAnimationsRunning = ValueAnimator.getCurrentAnimationsCount();
Intent broadcastIntent = ActivityThread.getIntentBeingBroadcast();
@@ -2569,7 +2553,10 @@
}
}
- /** Equivalent output to {@link ApplicationErrorReport.CrashInfo#stackTrace}. */
+ /**
+ * Equivalent output to
+ * {@link android.app.ApplicationErrorReport.CrashInfo#stackTrace}.
+ */
public String getStackTrace() {
if (mStackTrace == null) {
StringWriter sw = new StringWriter();
@@ -2590,6 +2577,10 @@
return mStackTrace;
}
+ public Class<? extends Violation> getViolationClass() {
+ return mViolation.getClass();
+ }
+
/**
* Optional message describing this violation.
*
@@ -2600,18 +2591,8 @@
return mViolation.getMessage();
}
- /**
- * Policy mask at time of violation.
- *
- * @hide
- */
- @TestApi
- public int getPolicyMask() {
- return mPolicy;
- }
-
boolean penaltyEnabled(int p) {
- return (mPolicy & p) != 0;
+ return (mPenaltyMask & p) != 0;
}
/**
@@ -2624,51 +2605,6 @@
mBinderStack.addFirst(t.getStackTrace());
}
- /**
- * Retrieve the type of StrictMode violation.
- *
- * @hide
- */
- @TestApi
- public int getViolationBit() {
- if (mViolation instanceof DiskWriteViolation) {
- return DETECT_DISK_WRITE;
- } else if (mViolation instanceof DiskReadViolation) {
- return DETECT_DISK_READ;
- } else if (mViolation instanceof NetworkViolation) {
- return DETECT_NETWORK;
- } else if (mViolation instanceof CustomViolation) {
- return DETECT_CUSTOM;
- } else if (mViolation instanceof ResourceMismatchViolation) {
- return DETECT_RESOURCE_MISMATCH;
- } else if (mViolation instanceof UnbufferedIoViolation) {
- return DETECT_UNBUFFERED_IO;
- } else if (mViolation instanceof SqliteObjectLeakedViolation) {
- return DETECT_VM_CURSOR_LEAKS;
- } else if (mViolation instanceof LeakedClosableViolation) {
- return DETECT_VM_CLOSABLE_LEAKS;
- } else if (mViolation instanceof InstanceCountViolation) {
- return DETECT_VM_INSTANCE_LEAKS;
- } else if (mViolation instanceof IntentReceiverLeakedViolation) {
- return DETECT_VM_REGISTRATION_LEAKS;
- } else if (mViolation instanceof ServiceConnectionLeakedViolation) {
- return DETECT_VM_REGISTRATION_LEAKS;
- } else if (mViolation instanceof FileUriExposedViolation) {
- return DETECT_VM_FILE_URI_EXPOSURE;
- } else if (mViolation instanceof CleartextNetworkViolation) {
- return DETECT_VM_CLEARTEXT_NETWORK;
- } else if (mViolation instanceof ContentUriWithoutPermissionViolation) {
- return DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION;
- } else if (mViolation instanceof UntaggedSocketViolation) {
- return DETECT_VM_UNTAGGED_SOCKET;
- } else if (mViolation instanceof ExplicitGcViolation) {
- return DETECT_EXPLICIT_GC;
- } else if (mViolation instanceof NonSdkApiUsedViolation) {
- return DETECT_VM_NON_SDK_API_USAGE;
- }
- throw new IllegalStateException("missing violation bit");
- }
-
@Override
public int hashCode() {
int result = 17;
@@ -2716,11 +2652,11 @@
}
mBinderStack.add(traceElements);
}
- int rawPolicy = in.readInt();
+ int rawPenaltyMask = in.readInt();
if (unsetGatheringBit) {
- mPolicy = rawPolicy & ~PENALTY_GATHER;
+ mPenaltyMask = rawPenaltyMask & ~PENALTY_GATHER;
} else {
- mPolicy = rawPolicy;
+ mPenaltyMask = rawPenaltyMask;
}
durationMillis = in.readInt();
violationNumThisLoop = in.readInt();
@@ -2746,7 +2682,7 @@
}
}
int start = dest.dataPosition();
- dest.writeInt(mPolicy);
+ dest.writeInt(mPenaltyMask);
dest.writeInt(durationMillis);
dest.writeInt(violationNumThisLoop);
dest.writeInt(numAnimationsRunning);
@@ -2758,8 +2694,8 @@
if (Binder.CHECK_PARCEL_SIZE && total > 10 * 1024) {
Slog.d(
TAG,
- "VIO: policy="
- + mPolicy
+ "VIO: penalty="
+ + mPenaltyMask
+ " dur="
+ durationMillis
+ " numLoop="
@@ -2779,7 +2715,7 @@
/** Dump a ViolationInfo instance to a Printer. */
public void dump(Printer pw, String prefix) {
pw.println(prefix + "stackTrace: " + getStackTrace());
- pw.println(prefix + "policy: " + mPolicy);
+ pw.println(prefix + "penalty: " + mPenaltyMask);
if (durationMillis != -1) {
pw.println(prefix + "durationMillis: " + durationMillis);
}
diff --git a/core/java/android/os/strictmode/ImplicitDirectBootViolation.java b/core/java/android/os/strictmode/ImplicitDirectBootViolation.java
new file mode 100644
index 0000000..d7877ca
--- /dev/null
+++ b/core/java/android/os/strictmode/ImplicitDirectBootViolation.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.strictmode;
+
+import android.content.pm.PackageManager;
+
+/**
+ * Subclass of {@code Violation} that is used when a process implicitly relies
+ * on automatic Direct Boot filtering.
+ *
+ * @see PackageManager#MATCH_DIRECT_BOOT_AUTO
+ */
+public final class ImplicitDirectBootViolation extends Violation {
+ /** @hide */
+ public static final String MESSAGE =
+ "Implicitly relying on automatic Direct Boot filtering; request explicit"
+ + " filtering with PackageManager.MATCH_DIRECT_BOOT flags";
+
+ /** @hide */
+ public ImplicitDirectBootViolation() {
+ super(MESSAGE);
+ }
+}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1794b47..a7fcaff 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6985,8 +6985,9 @@
private static final Validator SELECTED_SPELL_CHECKER_VALIDATOR = COMPONENT_NAME_VALIDATOR;
/**
- * The {@link ComponentName} string of the selected subtype of the selected spell checker
- * service which is one of the services managed by the text service manager.
+ * {@link android.view.textservice.SpellCheckerSubtype#hashCode()} of the selected subtype
+ * of the selected spell checker service which is one of the services managed by the text
+ * service manager.
*
* @hide
*/
@@ -6994,7 +6995,7 @@
"selected_spell_checker_subtype";
private static final Validator SELECTED_SPELL_CHECKER_SUBTYPE_VALIDATOR =
- COMPONENT_NAME_VALIDATOR;
+ ANY_INTEGER_VALIDATOR;
/**
* Whether spell checker is enabled or not.
@@ -7302,7 +7303,7 @@
* see and assist with all of the user's notifications.
*
* @deprecated Use
- * {@link NotificationManager#isNotificationListenerAccessGranted(ComponentName)}.
+ * {@link NotificationManager#isNotificationAssistantAccessGranted(ComponentName)}.
* @hide
*/
@Deprecated
@@ -7318,7 +7319,7 @@
*
* @hide
* @deprecated Use
- * {@link NotificationManager#isNotificationAssistantAccessGranted(ComponentName)}.
+ * {@link NotificationManager#isNotificationListenerAccessGranted(ComponentName)}.
*/
@Deprecated
public static final String ENABLED_NOTIFICATION_LISTENERS = "enabled_notification_listeners";
@@ -9018,6 +9019,14 @@
"location_background_throttle_package_whitelist";
/**
+ * Maximum staleness allowed for last location when returned to clients with only foreground
+ * location permissions.
+ * @hide
+ */
+ public static final String LOCATION_LAST_LOCATION_MAX_AGE_MILLIS =
+ "location_last_location_max_age_millis";
+
+ /**
* Whether TV will switch to MHL port when a mobile device is plugged in.
* (0 = false, 1 = true)
* @hide
@@ -9905,6 +9914,39 @@
public static final String WIFI_SCORE_PARAMS =
"wifi_score_params";
+ /**
+ * Setting to enable logging WifiIsUnusableEvent in metrics
+ * which gets triggered when wifi becomes unusable.
+ * Disabled by default, and setting it to 1 will enable it.
+ * @hide
+ */
+ public static final String WIFI_IS_UNUSABLE_EVENT_METRICS_ENABLED =
+ "wifi_is_unusable_event_metrics_enabled";
+
+ /**
+ * The minimum number of txBad the framework has to observe
+ * to trigger a wifi data stall.
+ * @hide
+ */
+ public static final String WIFI_DATA_STALL_MIN_TX_BAD =
+ "wifi_data_stall_min_tx_bad";
+
+ /**
+ * The minimum number of txSuccess the framework has to observe
+ * to trigger a wifi data stall when rxSuccess is 0.
+ * @hide
+ */
+ public static final String WIFI_DATA_STALL_MIN_TX_SUCCESS_WITHOUT_RX =
+ "wifi_data_stall_min_tx_success_without_rx";
+
+ /**
+ * Setting to enable logging Wifi LinkSpeedCounts in metrics.
+ * Disabled by default, and setting it to 1 will enable it.
+ * @hide
+ */
+ public static final String WIFI_LINK_SPEED_METRICS_ENABLED =
+ "wifi_link_speed_metrics_enabled";
+
/**
* The maximum number of times we will retry a connection to an access
* point for which we have failed in acquiring an IP address from DHCP.
@@ -11056,6 +11098,7 @@
*
* <pre>
* enabled (boolean)
+ * disable_home (boolean)
* disable_tilt_to_wake (boolean)
* disable_touch_to_wake (boolean)
* </pre>
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 01562b3..6f1bd78 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -33,7 +33,6 @@
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
-import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
@@ -487,8 +486,9 @@
* intent. The possible values for this extra are
* {@link TextToSpeech#SUCCESS} and {@link TextToSpeech#ERROR}.
*
- * @deprecated No longer in use. If client ise interested in information about what
- * changed, is should send ACTION_CHECK_TTS_DATA intent to discover available voices.
+ * @deprecated No longer in use. If client is interested in information about what
+ * changed, it should use the ACTION_CHECK_TTS_DATA
+ * intent to discover available voices.
*/
@Deprecated
public static final String EXTRA_TTS_DATA_INSTALLED = "dataInstalled";
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index a0daa07..6b2f802 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -351,8 +351,16 @@
}
/**
- * String.split() returns [''] when the string to be split is empty. This returns []. This does
- * not remove any empty strings from the result. For example split("a,", "," ) returns {"a", ""}.
+ *
+ * This method yields the same result as {@code text.split(expression, -1)} except that if
+ * {@code text.isEmpty()} then this method returns an empty array whereas
+ * {@code "".split(expression, -1)} would have returned an array with a single {@code ""}.
+ *
+ * The {@code -1} means that trailing empty Strings are not removed from the result; for
+ * example split("a,", "," ) returns {"a", ""}. Note that whether a leading zero-width match
+ * can result in a leading {@code ""} depends on whether your app
+ * {@link android.content.pm.ApplicationInfo#targetSdkVersion targets an SDK version}
+ * {@code <= 28}; see {@link Pattern#split(CharSequence, int)}.
*
* @param text the string to split
* @param expression the regular expression to match
@@ -369,8 +377,16 @@
}
/**
- * Splits a string on a pattern. String.split() returns [''] when the string to be
- * split is empty. This returns []. This does not remove any empty strings from the result.
+ * Splits a string on a pattern. This method yields the same result as
+ * {@code pattern.split(text, -1)} except that if {@code text.isEmpty()} then this method
+ * returns an empty array whereas {@code pattern.split("", -1)} would have returned an array
+ * with a single {@code ""}.
+ *
+ * The {@code -1} means that trailing empty Strings are not removed from the result;
+ * Note that whether a leading zero-width match can result in a leading {@code ""} depends
+ * on whether your app {@link android.content.pm.ApplicationInfo#targetSdkVersion targets
+ * an SDK version} {@code <= 28}; see {@link Pattern#split(CharSequence, int)}.
+ *
* @param text the string to split
* @param pattern the regular expression to match
* @return an array of strings. The array will be empty if text is empty
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index ec045b1..6b7b89c 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -41,6 +41,7 @@
DEFAULT_FLAGS.put("settings_bluetooth_while_driving", "false");
DEFAULT_FLAGS.put("settings_audio_switcher", "true");
DEFAULT_FLAGS.put("settings_systemui_theme", "true");
+ DEFAULT_FLAGS.put("settings_dynamic_homepage", "false");
}
/**
diff --git a/core/java/android/util/TimestampedValue.java b/core/java/android/util/TimestampedValue.java
index 75fa18d..1289e4d 100644
--- a/core/java/android/util/TimestampedValue.java
+++ b/core/java/android/util/TimestampedValue.java
@@ -126,4 +126,12 @@
dest.writeLong(timestampedValue.mReferenceTimeMillis);
dest.writeValue(timestampedValue.mValue);
}
+
+ /**
+ * Returns the difference in milliseconds between two instance's reference times.
+ */
+ public static long referenceTimeDifference(
+ @NonNull TimestampedValue<?> one, @NonNull TimestampedValue<?> two) {
+ return one.mReferenceTimeMillis - two.mReferenceTimeMillis;
+ }
}
diff --git a/core/java/android/view/DisplayListCanvas.java b/core/java/android/view/DisplayListCanvas.java
index 671532c..df4d5c4 100644
--- a/core/java/android/view/DisplayListCanvas.java
+++ b/core/java/android/view/DisplayListCanvas.java
@@ -180,13 +180,12 @@
///////////////////////////////////////////////////////////////////////////
/**
- * Draws the specified display list onto this canvas. The display list can only
- * be drawn if {@link android.view.RenderNode#isValid()} returns true.
+ * Draws the specified display list onto this canvas.
*
* @param renderNode The RenderNode to draw.
*/
public void drawRenderNode(RenderNode renderNode) {
- nDrawRenderNode(mNativeCanvasWrapper, renderNode.getNativeDisplayList());
+ nDrawRenderNode(mNativeCanvasWrapper, renderNode.mNativeRenderNode);
}
///////////////////////////////////////////////////////////////////////////
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index 7c25fac..e10eeb0 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -139,7 +139,9 @@
RenderNode.class.getClassLoader(), nGetNativeFinalizer(), 1024);
}
- // Do not access directly unless you are ThreadedRenderer
+ /** Not for general use; use only if you are ThreadedRenderer or DisplayListCanvas.
+ * @hide
+ */
final long mNativeRenderNode;
private final View mOwningView;
@@ -159,15 +161,6 @@
}
/**
- * Immediately destroys the RenderNode
- * Only suitable for testing/benchmarking where waiting for the GC/finalizer
- * is not feasible.
- */
- public void destroy() {
- // TODO: Removed temporarily
- }
-
- /**
* Creates a new RenderNode that can be used to record batches of
* drawing operations, and store / apply render properties when drawn.
*
@@ -219,6 +212,14 @@
}
/**
+ * Same as {@link #start(int, int)} but with the RenderNode's width & height
+ */
+ public DisplayListCanvas start() {
+ return DisplayListCanvas.obtain(this,
+ nGetWidth(mNativeRenderNode), nGetHeight(mNativeRenderNode));
+ }
+
+ /**
* Ends the recording for this display list. A display list cannot be
* replayed if recording is not finished. Calling this method marks
* the display list valid and {@link #isValid()} will return true.
@@ -251,13 +252,6 @@
return nIsValid(mNativeRenderNode);
}
- long getNativeDisplayList() {
- if (!isValid()) {
- throw new IllegalStateException("The display list is not valid.");
- }
- return mNativeRenderNode;
- }
-
///////////////////////////////////////////////////////////////////////////
// Matrix manipulation
///////////////////////////////////////////////////////////////////////////
@@ -463,7 +457,6 @@
* @see #setHasOverlappingRendering(boolean)
*/
public boolean hasOverlappingRendering() {
- //noinspection SimplifiableIfStatement
return nHasOverlappingRendering(mNativeRenderNode);
}
@@ -1009,4 +1002,8 @@
private static native float nGetPivotX(long renderNode);
@CriticalNative
private static native float nGetPivotY(long renderNode);
+ @CriticalNative
+ private static native int nGetWidth(long renderNode);
+ @CriticalNative
+ private static native int nGetHeight(long renderNode);
}
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index aa1e407..2f975b6 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -850,7 +850,9 @@
void buildLayer(RenderNode node) {
- nBuildLayer(mNativeProxy, node.getNativeDisplayList());
+ if (node.isValid()) {
+ nBuildLayer(mNativeProxy, node.mNativeRenderNode);
+ }
}
@@ -928,7 +930,7 @@
* not the RenderNode from a View.
**/
public static Bitmap createHardwareBitmap(RenderNode node, int width, int height) {
- return nCreateHardwareBitmap(node.getNativeDisplayList(), width, height);
+ return nCreateHardwareBitmap(node.mNativeRenderNode, width, height);
}
/**
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 276f50a..e4c595b 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -531,7 +531,6 @@
throws IOException {
RenderNode node = RenderNode.create("ViewDebug", null);
profileViewAndChildren(view, node, out, true);
- node.destroy();
}
private static void profileViewAndChildren(View view, RenderNode node, BufferedWriter out,
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 7944319..d0539ae 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -4652,7 +4652,7 @@
* which is added in order to fade it out in its old location should be removed
* once the animation is complete.</p>
*
- * @param view The view to be added
+ * @param view The view to be added. The view must not have a parent.
* @param index The index at which this view should be drawn, must be >= 0.
* This value is relative to the {@link #getChildAt(int) index} values in the normal
* child list of this container, where any transient view at a particular index will
@@ -4661,9 +4661,14 @@
* @hide
*/
public void addTransientView(View view, int index) {
- if (index < 0) {
+ if (index < 0 || view == null) {
return;
}
+ if (view.mParent != null) {
+ throw new IllegalStateException("The specified view already has a parent "
+ + view.mParent);
+ }
+
if (mTransientIndices == null) {
mTransientIndices = new ArrayList<Integer>();
mTransientViews = new ArrayList<View>();
@@ -4683,7 +4688,9 @@
mTransientViews.add(view);
}
view.mParent = this;
- view.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
+ if (mAttachInfo != null) {
+ view.dispatchAttachedToWindow(mAttachInfo, (mViewFlags & VISIBILITY_MASK));
+ }
invalidate(true);
}
@@ -4705,7 +4712,9 @@
mTransientViews.remove(i);
mTransientIndices.remove(i);
view.mParent = null;
- view.dispatchDetachedFromWindow();
+ if (view.mAttachInfo != null) {
+ view.dispatchDetachedFromWindow();
+ }
invalidate(true);
return;
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index dd24185..ea9bd85 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1338,6 +1338,7 @@
renderer.setStopped(mStopped);
}
if (!mStopped) {
+ mNewSurfaceNeeded = true;
scheduleTraversals();
} else {
if (renderer != null) {
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 7e6af49..bb93af5 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -798,10 +798,18 @@
}
/** @hide */
- public void setImeWindowStatus(IBinder imeToken, IBinder startInputToken, int vis,
- int backDisposition) {
+ public void setImeWindowStatus(IBinder imeToken, int vis, int backDisposition) {
try {
- mService.setImeWindowStatus(imeToken, startInputToken, vis, backDisposition);
+ mService.setImeWindowStatus(imeToken, vis, backDisposition);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** @hide */
+ public void reportStartInput(IBinder imeToken, IBinder startInputToken) {
+ try {
+ mService.reportStartInput(imeToken, startInputToken);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1239,7 +1247,7 @@
}
boolean startInputInner(@InputMethodClient.StartInputReason final int startInputReason,
- IBinder windowGainingFocus, int controlFlags, int softInputMode,
+ @Nullable IBinder windowGainingFocus, int controlFlags, int softInputMode,
int windowFlags) {
final View view;
synchronized (mH) {
@@ -1256,6 +1264,20 @@
}
}
+ if (windowGainingFocus == null) {
+ windowGainingFocus = view.getWindowToken();
+ if (windowGainingFocus == null) {
+ Log.e(TAG, "ABORT input: ServedView must be attached to a Window");
+ return false;
+ }
+ controlFlags |= CONTROL_WINDOW_VIEW_HAS_FOCUS;
+ if (view.onCheckIsTextEditor()) {
+ controlFlags |= CONTROL_WINDOW_IS_TEXT_EDITOR;
+ }
+ softInputMode = view.getViewRootImpl().mWindowAttributes.softInputMode;
+ windowFlags = view.getViewRootImpl().mWindowAttributes.flags;
+ }
+
// Now we need to get an input connection from the served view.
// This is complicated in a couple ways: we can't be holding our lock
// when calling out to the view, and we need to make sure we call into
diff --git a/core/java/android/webkit/WebBackForwardList.java b/core/java/android/webkit/WebBackForwardList.java
index 0c34e3c..4d3bbe4 100644
--- a/core/java/android/webkit/WebBackForwardList.java
+++ b/core/java/android/webkit/WebBackForwardList.java
@@ -57,7 +57,8 @@
/**
* Clone the entire object to be used in the UI thread by clients of
* WebView. This creates a copy that should never be modified by any of the
- * webkit package classes.
+ * webkit package classes. On Android 4.4 and later there is no need to use
+ * this, as the object is already a read-only copy of the internal state.
*/
protected abstract WebBackForwardList clone();
}
diff --git a/core/java/android/webkit/WebHistoryItem.java b/core/java/android/webkit/WebHistoryItem.java
index 74db039..b9e7042 100644
--- a/core/java/android/webkit/WebHistoryItem.java
+++ b/core/java/android/webkit/WebHistoryItem.java
@@ -23,7 +23,7 @@
/**
* A convenience class for accessing fields in an entry in the back/forward list
* of a WebView. Each WebHistoryItem is a snapshot of the requested history
- * item. Each history item may be updated during the load of a page.
+ * item.
* @see WebBackForwardList
*/
public abstract class WebHistoryItem implements Cloneable {
@@ -44,8 +44,6 @@
* history item. See getTargetUrl() for the url that is the actual target of
* this history item.
* @return The base url of this history item.
- * Note: The VM ensures 32-bit atomic read/write operations so we don't have
- * to synchronize this method.
*/
public abstract String getUrl();
@@ -60,22 +58,20 @@
/**
* Return the document title of this history item.
* @return The document title of this history item.
- * Note: The VM ensures 32-bit atomic read/write operations so we don't have
- * to synchronize this method.
*/
public abstract String getTitle();
/**
* Return the favicon of this history item or {@code null} if no favicon was found.
* @return A Bitmap containing the favicon for this history item or {@code null}.
- * Note: The VM ensures 32-bit atomic read/write operations so we don't have
- * to synchronize this method.
*/
@Nullable
public abstract Bitmap getFavicon();
/**
- * Clone the history item for use by clients of WebView.
+ * Clone the history item for use by clients of WebView. On Android 4.4 and later
+ * there is no need to use this, as the object is already a read-only copy of the
+ * internal state.
*/
protected abstract WebHistoryItem clone();
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 4eb85ac..d1a0f77 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -41,7 +41,6 @@
import android.os.RemoteException;
import android.os.StrictMode;
import android.print.PrintDocumentAdapter;
-import android.security.KeyChain;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
@@ -143,7 +142,7 @@
* This class is called when something that might impact a
* browser UI happens, for instance, progress updates and
* JavaScript alerts are sent here (see <a
- * href="{@docRoot}guide/developing/debug-tasks.html#DebuggingWebPages">Debugging Tasks</a>).
+ * href="{@docRoot}guide/webapps/debugging.html">Debugging Web Apps</a>).
* </li>
* <li>Creating and setting a {@link android.webkit.WebViewClient} subclass.
* It will be called when things happen that impact the
@@ -1671,9 +1670,8 @@
/**
* Clears the client certificate preferences stored in response
* to proceeding/cancelling client cert requests. Note that WebView
- * automatically clears these preferences when it receives a
- * {@link KeyChain#ACTION_STORAGE_CHANGED} intent. The preferences are
- * shared by all the WebViews that are created by the embedder application.
+ * automatically clears these preferences when the system keychain is updated.
+ * The preferences are shared by all the WebViews that are created by the embedder application.
*
* @param onCleared A runnable to be invoked when client certs are cleared.
* The runnable will be called in UI thread.
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index b12e854..51e481d 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -80,7 +80,7 @@
*
* <p>
* To learn more about Drawables, see: <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.
- * To learn more about working with Bitmaps, see: <a href="{@docRoot}topic/performance/graphics/index.htm">Handling Bitmaps</a>.
+ * To learn more about working with Bitmaps, see: <a href="{@docRoot}topic/performance/graphics/index.html">Handling Bitmaps</a>.
* </p>
*
* @attr ref android.R.styleable#ImageView_adjustViewBounds
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index 929496f..11054c8 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -611,7 +611,6 @@
mRenderer.destroy();
mSurfaceControl.destroy();
mSurfaceSession.kill();
- mBitmapRenderNode.destroy();
mHandler.removeCallbacks(mMagnifierUpdater);
if (mBitmap != null) {
mBitmap.recycle();
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 4ea2ced..9a60065 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -247,6 +247,7 @@
* @attr ref android.R.styleable#TextView_textColorHint
* @attr ref android.R.styleable#TextView_textAppearance
* @attr ref android.R.styleable#TextView_textColorLink
+ * @attr ref android.R.styleable#TextView_textFontWeight
* @attr ref android.R.styleable#TextView_textSize
* @attr ref android.R.styleable#TextView_textScaleX
* @attr ref android.R.styleable#TextView_fontFamily
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index f6a69d9..5778544 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -18,6 +18,9 @@
import android.animation.TimeAnimator;
import android.app.Activity;
+import android.content.ActivityNotFoundException;
+import android.content.ContentResolver;
+import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
@@ -25,12 +28,15 @@
import android.graphics.Path;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
+import android.provider.Settings;
import android.util.Log;
import android.view.MotionEvent;
import android.view.MotionEvent.PointerCoords;
import android.view.View;
import android.widget.FrameLayout;
+import org.json.JSONObject;
+
public class PlatLogoActivity extends Activity {
FrameLayout layout;
TimeAnimator anim;
@@ -87,7 +93,7 @@
darkest = 0;
for (int i=0; i<slots; i++) {
palette[i] = Color.HSVToColor(color);
- color[0] += 360f/slots;
+ color[0] = (color[0] + 360f/slots) % 360f;
if (lum(palette[i]) < lum(palette[darkest])) darkest = i;
}
@@ -178,27 +184,97 @@
bg = new PBackground();
layout.setBackground(bg);
+ final ContentResolver cr = getContentResolver();
+
layout.setOnTouchListener(new View.OnTouchListener() {
+ final String TOUCH_STATS = "touch.stats";
+
final PointerCoords pc0 = new PointerCoords();
final PointerCoords pc1 = new PointerCoords();
+ double pressure_min, pressure_max;
+ int maxPointers;
+ int tapCount;
+
@Override
public boolean onTouch(View v, MotionEvent event) {
+ final float pressure = event.getPressure();
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
+ pressure_min = pressure_max = pressure;
+ // fall through
case MotionEvent.ACTION_MOVE:
- if (event.getPointerCount() > 1) {
+ if (pressure < pressure_min) pressure_min = pressure;
+ if (pressure > pressure_max) pressure_max = pressure;
+ final int pc = event.getPointerCount();
+ if (pc > maxPointers) maxPointers = pc;
+ if (pc > 1) {
event.getPointerCoords(0, pc0);
event.getPointerCoords(1, pc1);
bg.setRadius((float) Math.hypot(pc0.x - pc1.x, pc0.y - pc1.y) / 2f);
}
break;
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ try {
+ final String touchDataJson = Settings.System.getString(cr, TOUCH_STATS);
+ final JSONObject touchData = new JSONObject(
+ touchDataJson != null ? touchDataJson : "{}");
+ if (touchData.has("min")) {
+ pressure_min = Math.min(pressure_min, touchData.getDouble("min"));
+ }
+ if (touchData.has("max")) {
+ pressure_max = Math.max(pressure_max, touchData.getDouble("max"));
+ }
+ touchData.put("min", pressure_min);
+ touchData.put("max", pressure_max);
+ Settings.System.putString(cr, TOUCH_STATS, touchData.toString());
+ } catch (Exception e) {
+ Log.e("PlatLogoActivity", "Can't write touch settings", e);
+ }
+
+ if (maxPointers == 1) {
+ tapCount ++;
+ if (tapCount < 7) {
+ bg.randomizePalette();
+ } else {
+ launchNextStage();
+ }
+ } else {
+ tapCount = 0;
+ }
+ maxPointers = 0;
+ break;
}
return true;
}
});
}
+ private void launchNextStage() {
+ final ContentResolver cr = getContentResolver();
+
+ if (Settings.System.getLong(cr, Settings.System.EGG_MODE, 0) == 0) {
+ // For posterity: the moment this user unlocked the easter egg
+ try {
+ Settings.System.putLong(cr,
+ Settings.System.EGG_MODE,
+ System.currentTimeMillis());
+ } catch (RuntimeException e) {
+ Log.e("PlatLogoActivity", "Can't write settings", e);
+ }
+ }
+ try {
+ startActivity(new Intent(Intent.ACTION_MAIN)
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ .addCategory("com.android.internal.category.PLATLOGO"));
+ } catch (ActivityNotFoundException ex) {
+ Log.e("PlatLogoActivity", "No more eggs.");
+ }
+ finish();
+ }
+
@Override
public void onStart() {
super.onStart();
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
index b591163..f89a9d9 100644
--- a/core/java/com/android/internal/content/FileSystemProvider.java
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -136,7 +136,7 @@
return null;
}
- String mimeType = getTypeForFile(file);
+ String mimeType = getDocumentType(documentId);
if (!MetadataReader.isSupportedMimeType(mimeType)) {
return null;
}
@@ -418,7 +418,19 @@
@Override
public String getDocumentType(String documentId) throws FileNotFoundException {
final File file = getFileForDocId(documentId);
- return getTypeForFile(file);
+ if (file.isDirectory()) {
+ return Document.MIME_TYPE_DIR;
+ } else {
+ final int lastDot = documentId.lastIndexOf('.');
+ if (lastDot >= 0) {
+ final String extension = documentId.substring(lastDot + 1).toLowerCase();
+ final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
+ if (mime != null) {
+ return mime;
+ }
+ }
+ return MIMETYPE_OCTET_STREAM;
+ }
}
@Override
@@ -483,7 +495,7 @@
}
}
- final String mimeType = getTypeForFile(file);
+ final String mimeType = getDocumentType(docId);
final String displayName = file.getName();
if (mimeType.startsWith("image/")) {
flags |= Document.FLAG_SUPPORTS_THUMBNAIL;
@@ -510,31 +522,10 @@
return row;
}
- private static String getTypeForFile(File file) {
- if (file.isDirectory()) {
- return Document.MIME_TYPE_DIR;
- } else {
- return getTypeForName(file.getName());
- }
- }
-
protected boolean typeSupportsMetadata(String mimeType) {
return MetadataReader.isSupportedMimeType(mimeType);
}
- private static String getTypeForName(String name) {
- final int lastDot = name.lastIndexOf('.');
- if (lastDot >= 0) {
- final String extension = name.substring(lastDot + 1).toLowerCase();
- final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
- if (mime != null) {
- return mime;
- }
- }
-
- return MIMETYPE_OCTET_STREAM;
- }
-
protected final File getFileForDocId(String docId) throws FileNotFoundException {
return getFileForDocId(docId, false);
}
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index 6c3a58c..989c58b 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -79,6 +79,11 @@
*/
public static final int ACTION_ROTATE_SCREEN = 6;
+ /*
+ * Time between we get a face acquired signal until we start with the unlock animation
+ */
+ public static final int ACTION_FACE_WAKE_AND_UNLOCK = 6;
+
private static final String[] NAMES = new String[] {
"expand panel",
"toggle recents",
@@ -86,7 +91,8 @@
"check credential",
"check credential unlocked",
"turn on screen",
- "rotate the screen"};
+ "rotate the screen",
+ "face wake-and-unlock" };
private static LatencyTracker sLatencyTracker;
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 9ed1ffb..f76eddf 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -74,8 +74,8 @@
void hideMySoftInput(in IBinder token, int flags);
void showMySoftInput(in IBinder token, int flags);
void updateStatusIcon(in IBinder token, String packageName, int iconId);
- void setImeWindowStatus(in IBinder token, in IBinder startInputToken, int vis,
- int backDisposition);
+ void setImeWindowStatus(in IBinder token, int vis, int backDisposition);
+ void reportStartInput(in IBinder token, in IBinder startInputToken);
void registerSuggestionSpansForNotification(in SuggestionSpan[] spans);
boolean notifySuggestionPicked(in SuggestionSpan span, String originalString, int index);
InputMethodSubtype getCurrentInputMethodSubtype();
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index d294933..80d8063 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1528,7 +1528,7 @@
* @see StrongAuthTracker#isFingerprintAllowedForUser
*/
public boolean isFingerprintAllowedForUser(int userId) {
- return (getStrongAuthForUser(userId) & ~StrongAuthTracker.ALLOWING_FINGERPRINT) == 0;
+ return (getStrongAuthForUser(userId) & ~StrongAuthTracker.ALLOWING_BIOMETRIC) == 0;
}
public boolean isUserInLockdown(int userId) {
@@ -1733,11 +1733,10 @@
public static final int STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN = 0x20;
/**
- * Strong auth flags that do not prevent fingerprint from being accepted as auth.
- *
- * If any other flags are set, fingerprint is disabled.
+ * Strong auth flags that do not prevent biometric methods from being accepted as auth.
+ * If any other flags are set, biometric authentication is disabled.
*/
- private static final int ALLOWING_FINGERPRINT = STRONG_AUTH_NOT_REQUIRED
+ private static final int ALLOWING_BIOMETRIC = STRONG_AUTH_NOT_REQUIRED
| SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
private final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray();
@@ -1784,11 +1783,11 @@
}
/**
- * @return true if unlocking with fingerprint alone is allowed for {@param userId} by the
- * current strong authentication requirements.
+ * @return true if unlocking with a biometric method alone is allowed for {@param userId}
+ * by the current strong authentication requirements.
*/
- public boolean isFingerprintAllowedForUser(int userId) {
- return (getStrongAuthForUser(userId) & ~ALLOWING_FINGERPRINT) == 0;
+ public boolean isBiometricAllowedForUser(int userId) {
+ return (getStrongAuthForUser(userId) & ~ALLOWING_BIOMETRIC) == 0;
}
/**
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 37ea810..22bbc3c 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -431,6 +431,14 @@
return renderNode->stagingProperties().getPivotY();
}
+static jint android_view_RenderNode_getWidth(jlong renderNodePtr) {
+ return reinterpret_cast<RenderNode*>(renderNodePtr)->stagingProperties().getWidth();
+}
+
+static jint android_view_RenderNode_getHeight(jlong renderNodePtr) {
+ return reinterpret_cast<RenderNode*>(renderNodePtr)->stagingProperties().getHeight();
+}
+
// ----------------------------------------------------------------------------
// RenderProperties - Animations
// ----------------------------------------------------------------------------
@@ -648,6 +656,8 @@
{ "nGetPivotX", "(J)F", (void*) android_view_RenderNode_getPivotX },
{ "nGetPivotY", "(J)F", (void*) android_view_RenderNode_getPivotY },
+ { "nGetWidth", "(J)I", (void*) android_view_RenderNode_getWidth },
+ { "nGetHeight", "(J)I", (void*) android_view_RenderNode_getHeight },
};
int register_android_view_RenderNode(JNIEnv* env) {
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 12165d4..caf4e4b4 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -535,17 +535,209 @@
return true;
}
+// Utility routine to specialize a zygote child process.
+static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
+ jint runtime_flags, jobjectArray javaRlimits,
+ jlong permittedCapabilities, jlong effectiveCapabilities,
+ jint mount_external, jstring java_se_info, jstring java_se_name,
+ bool is_system_server, bool is_child_zygote, jstring instructionSet,
+ jstring dataDir) {
+ std::string error_msg;
+
+ auto fail_fn = [env, java_se_name, is_system_server](const std::string& msg)
+ __attribute__ ((noreturn)) {
+ const char* se_name_c_str = nullptr;
+ std::unique_ptr<ScopedUtfChars> se_name;
+ if (java_se_name != nullptr) {
+ se_name.reset(new ScopedUtfChars(env, java_se_name));
+ se_name_c_str = se_name->c_str();
+ }
+ if (se_name_c_str == nullptr && is_system_server) {
+ se_name_c_str = "system_server";
+ }
+ const std::string& error_msg = (se_name_c_str == nullptr)
+ ? msg
+ : StringPrintf("(%s) %s", se_name_c_str, msg.c_str());
+ env->FatalError(error_msg.c_str());
+ __builtin_unreachable();
+ };
+
+ // Keep capabilities across UID change, unless we're staying root.
+ if (uid != 0) {
+ if (!EnableKeepCapabilities(&error_msg)) {
+ fail_fn(error_msg);
+ }
+ }
+
+ if (!SetInheritable(permittedCapabilities, &error_msg)) {
+ fail_fn(error_msg);
+ }
+ if (!DropCapabilitiesBoundingSet(&error_msg)) {
+ fail_fn(error_msg);
+ }
+
+ bool use_native_bridge = !is_system_server && (instructionSet != NULL)
+ && android::NativeBridgeAvailable();
+ if (use_native_bridge) {
+ ScopedUtfChars isa_string(env, instructionSet);
+ use_native_bridge = android::NeedsNativeBridge(isa_string.c_str());
+ }
+ if (use_native_bridge && dataDir == NULL) {
+ // dataDir should never be null if we need to use a native bridge.
+ // In general, dataDir will never be null for normal applications. It can only happen in
+ // special cases (for isolated processes which are not associated with any app). These are
+ // launched by the framework and should not be emulated anyway.
+ use_native_bridge = false;
+ ALOGW("Native bridge will not be used because dataDir == NULL.");
+ }
+
+ if (!MountEmulatedStorage(uid, mount_external, use_native_bridge, &error_msg)) {
+ ALOGW("Failed to mount emulated storage: %s (%s)", error_msg.c_str(), strerror(errno));
+ if (errno == ENOTCONN || errno == EROFS) {
+ // When device is actively encrypting, we get ENOTCONN here
+ // since FUSE was mounted before the framework restarted.
+ // When encrypted device is booting, we get EROFS since
+ // FUSE hasn't been created yet by init.
+ // In either case, continue without external storage.
+ } else {
+ fail_fn(error_msg);
+ }
+ }
+
+ // If this zygote isn't root, it won't be able to create a process group,
+ // since the directory is owned by root.
+ if (!is_system_server && getuid() == 0) {
+ int rc = createProcessGroup(uid, getpid());
+ if (rc != 0) {
+ if (rc == -EROFS) {
+ ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?");
+ } else {
+ ALOGE("createProcessGroup(%d, %d) failed: %s", uid, 0/*pid*/, strerror(-rc));
+ }
+ }
+ }
+
+ if (!SetGids(env, javaGids, &error_msg)) {
+ fail_fn(error_msg);
+ }
+
+ if (!SetRLimits(env, javaRlimits, &error_msg)) {
+ fail_fn(error_msg);
+ }
+
+ if (use_native_bridge) {
+ ScopedUtfChars isa_string(env, instructionSet);
+ ScopedUtfChars data_dir(env, dataDir);
+ android::PreInitializeNativeBridge(data_dir.c_str(), isa_string.c_str());
+ }
+
+ int rc = setresgid(gid, gid, gid);
+ if (rc == -1) {
+ fail_fn(CREATE_ERROR("setresgid(%d) failed: %s", gid, strerror(errno)));
+ }
+
+ // Must be called when the new process still has CAP_SYS_ADMIN, in this case, before changing
+ // uid from 0, which clears capabilities. The other alternative is to call
+ // prctl(PR_SET_NO_NEW_PRIVS, 1) afterward, but that breaks SELinux domain transition (see
+ // b/71859146). As the result, privileged syscalls used below still need to be accessible in
+ // app process.
+ SetUpSeccompFilter(uid);
+
+ rc = setresuid(uid, uid, uid);
+ if (rc == -1) {
+ fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno)));
+ }
+
+ // The "dumpable" flag of a process, which controls core dump generation, is
+ // overwritten by the value in /proc/sys/fs/suid_dumpable when the effective
+ // user or group ID changes. See proc(5) for possible values. In most cases,
+ // the value is 0, so core dumps are disabled for zygote children. However,
+ // when running in a Chrome OS container, the value is already set to 2,
+ // which allows the external crash reporter to collect all core dumps. Since
+ // only system crashes are interested, core dump is disabled for app
+ // processes. This also ensures compliance with CTS.
+ int dumpable = prctl(PR_GET_DUMPABLE);
+ if (dumpable == -1) {
+ ALOGE("prctl(PR_GET_DUMPABLE) failed: %s", strerror(errno));
+ RuntimeAbort(env, __LINE__, "prctl(PR_GET_DUMPABLE) failed");
+ }
+ if (dumpable == 2 && uid >= AID_APP) {
+ if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1) {
+ ALOGE("prctl(PR_SET_DUMPABLE, 0) failed: %s", strerror(errno));
+ RuntimeAbort(env, __LINE__, "prctl(PR_SET_DUMPABLE, 0) failed");
+ }
+ }
+
+ if (NeedsNoRandomizeWorkaround()) {
+ // Work around ARM kernel ASLR lossage (http://b/5817320).
+ int old_personality = personality(0xffffffff);
+ int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE);
+ if (new_personality == -1) {
+ ALOGW("personality(%d) failed: %s", new_personality, strerror(errno));
+ }
+ }
+
+ if (!SetCapabilities(permittedCapabilities, effectiveCapabilities, permittedCapabilities,
+ &error_msg)) {
+ fail_fn(error_msg);
+ }
+
+ if (!SetSchedulerPolicy(&error_msg)) {
+ fail_fn(error_msg);
+ }
+
+ const char* se_info_c_str = NULL;
+ ScopedUtfChars* se_info = NULL;
+ if (java_se_info != NULL) {
+ se_info = new ScopedUtfChars(env, java_se_info);
+ se_info_c_str = se_info->c_str();
+ if (se_info_c_str == NULL) {
+ fail_fn("se_info_c_str == NULL");
+ }
+ }
+ const char* se_name_c_str = NULL;
+ ScopedUtfChars* se_name = NULL;
+ if (java_se_name != NULL) {
+ se_name = new ScopedUtfChars(env, java_se_name);
+ se_name_c_str = se_name->c_str();
+ if (se_name_c_str == NULL) {
+ fail_fn("se_name_c_str == NULL");
+ }
+ }
+ rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
+ if (rc == -1) {
+ fail_fn(CREATE_ERROR("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid,
+ is_system_server, se_info_c_str, se_name_c_str));
+ }
+
+ // Make it easier to debug audit logs by setting the main thread's name to the
+ // nice name rather than "app_process".
+ if (se_name_c_str == NULL && is_system_server) {
+ se_name_c_str = "system_server";
+ }
+ if (se_name_c_str != NULL) {
+ SetThreadName(se_name_c_str);
+ }
+
+ delete se_info;
+ delete se_name;
+
+ // Unset the SIGCHLD handler, but keep ignoring SIGHUP (rationale in SetSignalHandlers).
+ UnsetChldSignalHandler();
+
+ env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags,
+ is_system_server, is_child_zygote, instructionSet);
+ if (env->ExceptionCheck()) {
+ fail_fn("Error calling post fork hooks.");
+ }
+}
+
// Utility routine to fork zygote and specialize the child process.
-static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
- jint runtime_flags, jobjectArray javaRlimits,
- jlong permittedCapabilities, jlong effectiveCapabilities,
- jint mount_external,
- jstring java_se_info, jstring java_se_name,
- bool is_system_server, jintArray fdsToClose,
- jintArray fdsToIgnore, bool is_child_zygote,
- jstring instructionSet, jstring dataDir) {
+static pid_t ForkCommon(JNIEnv* env, jstring java_se_name, bool is_system_server,
+ jintArray fdsToClose, jintArray fdsToIgnore) {
SetSignalHandlers();
+ // Block SIGCHLD prior to fork.
sigset_t sigchld;
sigemptyset(&sigchld);
sigaddset(&sigchld, SIGCHLD);
@@ -602,6 +794,7 @@
pid_t pid = fork();
if (pid == 0) {
+ // The child process.
PreApplicationInit();
// Clean up any descriptors which must be closed immediately
@@ -614,187 +807,11 @@
if (!gOpenFdTable->ReopenOrDetach(&error_msg)) {
fail_fn(error_msg);
}
+ }
- if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) {
- fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)));
- }
-
- // Keep capabilities across UID change, unless we're staying root.
- if (uid != 0) {
- if (!EnableKeepCapabilities(&error_msg)) {
- fail_fn(error_msg);
- }
- }
-
- if (!SetInheritable(permittedCapabilities, &error_msg)) {
- fail_fn(error_msg);
- }
- if (!DropCapabilitiesBoundingSet(&error_msg)) {
- fail_fn(error_msg);
- }
-
- bool use_native_bridge = !is_system_server && (instructionSet != NULL)
- && android::NativeBridgeAvailable();
- if (use_native_bridge) {
- ScopedUtfChars isa_string(env, instructionSet);
- use_native_bridge = android::NeedsNativeBridge(isa_string.c_str());
- }
- if (use_native_bridge && dataDir == NULL) {
- // dataDir should never be null if we need to use a native bridge.
- // In general, dataDir will never be null for normal applications. It can only happen in
- // special cases (for isolated processes which are not associated with any app). These are
- // launched by the framework and should not be emulated anyway.
- use_native_bridge = false;
- ALOGW("Native bridge will not be used because dataDir == NULL.");
- }
-
- if (!MountEmulatedStorage(uid, mount_external, use_native_bridge, &error_msg)) {
- ALOGW("Failed to mount emulated storage: %s (%s)", error_msg.c_str(), strerror(errno));
- if (errno == ENOTCONN || errno == EROFS) {
- // When device is actively encrypting, we get ENOTCONN here
- // since FUSE was mounted before the framework restarted.
- // When encrypted device is booting, we get EROFS since
- // FUSE hasn't been created yet by init.
- // In either case, continue without external storage.
- } else {
- fail_fn(error_msg);
- }
- }
-
- // If this zygote isn't root, it won't be able to create a process group,
- // since the directory is owned by root.
- if (!is_system_server && getuid() == 0) {
- int rc = createProcessGroup(uid, getpid());
- if (rc != 0) {
- if (rc == -EROFS) {
- ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?");
- } else {
- ALOGE("createProcessGroup(%d, %d) failed: %s", uid, pid, strerror(-rc));
- }
- }
- }
-
- std::string error_msg;
- if (!SetGids(env, javaGids, &error_msg)) {
- fail_fn(error_msg);
- }
-
- if (!SetRLimits(env, javaRlimits, &error_msg)) {
- fail_fn(error_msg);
- }
-
- if (use_native_bridge) {
- ScopedUtfChars isa_string(env, instructionSet);
- ScopedUtfChars data_dir(env, dataDir);
- android::PreInitializeNativeBridge(data_dir.c_str(), isa_string.c_str());
- }
-
- int rc = setresgid(gid, gid, gid);
- if (rc == -1) {
- fail_fn(CREATE_ERROR("setresgid(%d) failed: %s", gid, strerror(errno)));
- }
-
- // Must be called when the new process still has CAP_SYS_ADMIN, in this case, before changing
- // uid from 0, which clears capabilities. The other alternative is to call
- // prctl(PR_SET_NO_NEW_PRIVS, 1) afterward, but that breaks SELinux domain transition (see
- // b/71859146). As the result, privileged syscalls used below still need to be accessible in
- // app process.
- SetUpSeccompFilter(uid);
-
- rc = setresuid(uid, uid, uid);
- if (rc == -1) {
- fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno)));
- }
-
- // The "dumpable" flag of a process, which controls core dump generation, is
- // overwritten by the value in /proc/sys/fs/suid_dumpable when the effective
- // user or group ID changes. See proc(5) for possible values. In most cases,
- // the value is 0, so core dumps are disabled for zygote children. However,
- // when running in a Chrome OS container, the value is already set to 2,
- // which allows the external crash reporter to collect all core dumps. Since
- // only system crashes are interested, core dump is disabled for app
- // processes. This also ensures compliance with CTS.
- int dumpable = prctl(PR_GET_DUMPABLE);
- if (dumpable == -1) {
- ALOGE("prctl(PR_GET_DUMPABLE) failed: %s", strerror(errno));
- RuntimeAbort(env, __LINE__, "prctl(PR_GET_DUMPABLE) failed");
- }
- if (dumpable == 2 && uid >= AID_APP) {
- if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1) {
- ALOGE("prctl(PR_SET_DUMPABLE, 0) failed: %s", strerror(errno));
- RuntimeAbort(env, __LINE__, "prctl(PR_SET_DUMPABLE, 0) failed");
- }
- }
-
- if (NeedsNoRandomizeWorkaround()) {
- // Work around ARM kernel ASLR lossage (http://b/5817320).
- int old_personality = personality(0xffffffff);
- int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE);
- if (new_personality == -1) {
- ALOGW("personality(%d) failed: %s", new_personality, strerror(errno));
- }
- }
-
- if (!SetCapabilities(permittedCapabilities, effectiveCapabilities, permittedCapabilities,
- &error_msg)) {
- fail_fn(error_msg);
- }
-
- if (!SetSchedulerPolicy(&error_msg)) {
- fail_fn(error_msg);
- }
-
- const char* se_info_c_str = NULL;
- ScopedUtfChars* se_info = NULL;
- if (java_se_info != NULL) {
- se_info = new ScopedUtfChars(env, java_se_info);
- se_info_c_str = se_info->c_str();
- if (se_info_c_str == NULL) {
- fail_fn("se_info_c_str == NULL");
- }
- }
- const char* se_name_c_str = NULL;
- ScopedUtfChars* se_name = NULL;
- if (java_se_name != NULL) {
- se_name = new ScopedUtfChars(env, java_se_name);
- se_name_c_str = se_name->c_str();
- if (se_name_c_str == NULL) {
- fail_fn("se_name_c_str == NULL");
- }
- }
- rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
- if (rc == -1) {
- fail_fn(CREATE_ERROR("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid,
- is_system_server, se_info_c_str, se_name_c_str));
- }
-
- // Make it easier to debug audit logs by setting the main thread's name to the
- // nice name rather than "app_process".
- if (se_name_c_str == NULL && is_system_server) {
- se_name_c_str = "system_server";
- }
- if (se_name_c_str != NULL) {
- SetThreadName(se_name_c_str);
- }
-
- delete se_info;
- delete se_name;
-
- // Unset the SIGCHLD handler, but keep ignoring SIGHUP (rationale in SetSignalHandlers).
- UnsetChldSignalHandler();
-
- env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags,
- is_system_server, is_child_zygote, instructionSet);
- if (env->ExceptionCheck()) {
- fail_fn("Error calling post fork hooks.");
- }
- } else if (pid > 0) {
- // the parent process
-
- // We blocked SIGCHLD prior to a fork, we unblock it here.
- if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) {
- fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)));
- }
+ // We blocked SIGCHLD prior to a fork, we unblock it here.
+ if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) {
+ fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)));
}
return pid;
}
@@ -881,22 +898,27 @@
// available.
capabilities &= GetEffectiveCapabilityMask(env);
- return ForkAndSpecializeCommon(env, uid, gid, gids, runtime_flags,
- rlimits, capabilities, capabilities, mount_external, se_info,
- se_name, false, fdsToClose, fdsToIgnore, is_child_zygote == JNI_TRUE,
- instructionSet, appDataDir);
+ pid_t pid = ForkCommon(env, se_name, false, fdsToClose, fdsToIgnore);
+ if (pid == 0) {
+ SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
+ capabilities, capabilities,
+ mount_external, se_info, se_name, false,
+ is_child_zygote == JNI_TRUE, instructionSet, appDataDir);
+ }
+ return pid;
}
static jint com_android_internal_os_Zygote_nativeForkSystemServer(
JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
jint runtime_flags, jobjectArray rlimits, jlong permittedCapabilities,
jlong effectiveCapabilities) {
- pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
- runtime_flags, rlimits,
- permittedCapabilities, effectiveCapabilities,
- MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL,
- NULL, false, NULL, NULL);
- if (pid > 0) {
+ pid_t pid = ForkCommon(env, NULL, true, NULL, NULL);
+ if (pid == 0) {
+ SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
+ permittedCapabilities, effectiveCapabilities,
+ MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true,
+ false, NULL, NULL);
+ } else if (pid > 0) {
// The zygote process checks whether the child process has died or not.
ALOGI("System server process %d has been created", pid);
gSystemServerPid = pid;
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 39e65ca..5f6b6cc 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -71,6 +71,12 @@
(section).args = "getprop"
];
+ optional string kernel_version = 1002 [
+ (section).type = SECTION_FILE,
+ (section).args = "/proc/version",
+ (privacy).dest = DEST_AUTOMATIC
+ ];
+
// Device Logs
optional android.util.EventLogTagMapProto event_log_tag_map = 1100 [
(section).type = SECTION_FILE,
@@ -182,7 +188,7 @@
];
// System Services
- optional com.android.server.fingerprint.FingerprintServiceDumpProto fingerprint = 3000 [
+ optional com.android.server.biometrics.fingerprint.FingerprintServiceDumpProto fingerprint = 3000 [
(section).type = SECTION_DUMPSYS,
(section).args = "fingerprint --proto --incident"
];
diff --git a/core/proto/android/server/face.proto b/core/proto/android/server/face.proto
new file mode 100644
index 0000000..6ecf328
--- /dev/null
+++ b/core/proto/android/server/face.proto
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+package com.android.server.biometrics.face;
+
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
+option java_multiple_files = true;
+option java_outer_classname = "FaceServiceProto";
+
+message FaceServiceDumpProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ // Each log may include multiple user_id for different users.
+ repeated FaceUserStatsProto users = 1;
+}
+
+message FaceUserStatsProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ // Refer to the UserHandle documentation.
+ optional int32 user_id = 1;
+
+ // The number of faces registered to this user.
+ optional int32 num_faces = 2;
+
+ // Normal face authentications stats (e.g. lockscreen).
+ optional FaceActionStatsProto normal = 3;
+
+ // Crypto authentications (e.g. to unlock password storage, make secure
+ // purchases, etc).
+ optional FaceActionStatsProto crypto = 4;
+}
+
+message FaceActionStatsProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ // Number of accepted faces.
+ optional int32 accept = 1;
+
+ // Number of rejected faces.
+ optional int32 reject = 2;
+
+ // Total number of acquisitions. Should be >= accept+reject due to poor
+ // image acquisition in some cases (too high, too low, poor gaze, etc.)
+ optional int32 acquire = 3;
+
+ // Total number of lockouts.
+ optional int32 lockout = 4;
+
+ // Total number of permanent lockouts.
+ optional int32 lockout_permanent = 5;
+}
diff --git a/core/proto/android/server/fingerprint.proto b/core/proto/android/server/fingerprint.proto
index 2a7fbc3..c5eb85c 100644
--- a/core/proto/android/server/fingerprint.proto
+++ b/core/proto/android/server/fingerprint.proto
@@ -15,7 +15,7 @@
*/
syntax = "proto2";
-package com.android.server.fingerprint;
+package com.android.server.biometrics.fingerprint;
import "frameworks/base/libs/incident/proto/android/privacy.proto";
@@ -46,7 +46,7 @@
optional PerformanceStatsProto crypto = 4;
}
-// A com.android.server.fingerprint.FingerpintService.PerformanceStats object.
+// A com.android.server.biometrics.fingerprint.FingerpintService.PerformanceStats object.
message PerformanceStatsProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e33ecb8..e2a5c57 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -262,6 +262,7 @@
<protected-broadcast android:name="android.intent.action.HEADSET_PLUG" />
<protected-broadcast android:name="android.media.action.HDMI_AUDIO_PLUG" />
+ <protected-broadcast android:name="android.media.action.MICROPHONE_MUTE_CHANGED" />
<protected-broadcast android:name="android.media.AUDIO_BECOMING_NOISY" />
<protected-broadcast android:name="android.media.RINGER_MODE_CHANGED" />
@@ -598,6 +599,8 @@
<protected-broadcast android:name="android.app.action.AFFILIATED_PROFILE_TRANSFER_OWNERSHIP_COMPLETE" />
<protected-broadcast android:name="android.app.action.DATA_SHARING_RESTRICTION_CHANGED" />
<protected-broadcast android:name="android.app.action.STATSD_STARTED" />
+ <protected-broadcast android:name="com.android.server.biometrics.fingerprint.ACTION_LOCKOUT_RESET" />
+ <protected-broadcast android:name="com.android.server.biometrics.face.ACTION_LOCKOUT_RESET" />
<!-- For IdleController -->
<protected-broadcast android:name="android.intent.action.DOCK_IDLE" />
@@ -821,6 +824,9 @@
android:label="@string/permgrouplab_location"
android:description="@string/permgroupdesc_location"
android:request="@string/permgrouprequest_location"
+ android:requestDetail="@string/permgrouprequestdetail_location"
+ android:backgroundRequest="@string/permgroupbackgroundrequest_location"
+ android:backgroundRequestDetail="@string/permgroupbackgroundrequestdetail_location"
android:priority="400" />
<!-- Allows an app to access precise location.
@@ -831,6 +837,7 @@
android:permissionGroup="android.permission-group.LOCATION"
android:label="@string/permlab_accessFineLocation"
android:description="@string/permdesc_accessFineLocation"
+ android:backgroundPermission="android.permission.ACCESS_BACKGROUND_LOCATION"
android:protectionLevel="dangerous|instant" />
<!-- Allows an app to access approximate location.
@@ -841,6 +848,7 @@
android:permissionGroup="android.permission-group.LOCATION"
android:label="@string/permlab_accessCoarseLocation"
android:description="@string/permdesc_accessCoarseLocation"
+ android:backgroundPermission="android.permission.ACCESS_BACKGROUND_LOCATION"
android:protectionLevel="dangerous|instant" />
<!-- Allows an app to access location in the background. If you
@@ -2251,7 +2259,8 @@
android:description="@string/permdesc_install_shortcut"
android:protectionLevel="normal"/>
- <!--This permission is no longer supported.
+ <!-- <p class="caution"><strong>Don't use this permission in your app.</strong><br>This
+ permission is no longer supported.
-->
<permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT"
android:label="@string/permlab_uninstall_shortcut"
@@ -3037,6 +3046,15 @@
<permission android:name="android.permission.INSTALL_PACKAGE_UPDATES"
android:protectionLevel="signature|privileged" />
+ <!-- Allows an application to install existing system packages. This is a limited
+ version of {@link android.Manifest.permission#INSTALL_PACKAGES}.
+ <p>Not for use by third-party applications.
+ TODO(b/80204953): remove this permission once we have a long-term solution.
+ @hide
+ -->
+ <permission android:name="com.android.permission.INSTALL_EXISTING_PACKAGES"
+ android:protectionLevel="signature|privileged" />
+
<!-- @SystemApi Allows an application to clear user data.
<p>Not for use by third-party applications
@hide
@@ -3629,6 +3647,14 @@
<permission android:name="android.permission.RESET_FINGERPRINT_LOCKOUT"
android:protectionLevel="signature" />
+ <!-- Allows managing (adding, removing) facial templates. Reserved for the system. @hide -->
+ <permission android:name="android.permission.MANAGE_FACE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an app to reset face authentication attempt counter. Reserved for the system. @hide -->
+ <permission android:name="android.permission.RESET_FACE_LOCKOUT"
+ android:protectionLevel="signature" />
+
<!-- Allows an application to control keyguard. Only allowed for system processes.
@hide -->
<permission android:name="android.permission.CONTROL_KEYGUARD"
@@ -3989,6 +4015,11 @@
<permission android:name="android.permission.DISABLE_HIDDEN_API_CHECKS"
android:protectionLevel="signature" />
+ <!-- Allows an application to read emergency info name.
+ @hide <p>Not for use by third-party applications. -->
+ <permission android:name="com.android.emergency.permission.READ_EMERGENCY_INFO_NAME"
+ android:protectionLevel="signature" />
+
<application android:process="system"
android:persistent="true"
android:hasCode="false"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index fe52e9c..5be78cf 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Ligging"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"toegang te verkry tot hierdie toestel se ligging"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Gee <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> toegang tot hierdie toestel se ligging?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Die program sal net toegang tot die ligging hê terwyl jy die program gebruik."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Gee <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> altyd toegang tot toestelligging?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Die program sal altyd toegang tot die ligging hê, selfs wanneer jy nie die program gebruik nie."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalender"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"by jou kalender in te gaan"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Gee <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> toegang tot jou kalender?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Hierdie program kan kalendergebeurtenisse op jou foon byvoeg, verwyder of verander. Hierdie program kan boodskappe stuur wat lyk of dit van kalendereienaars af kom of gebeurtenisse verander sonder om hul eienaars in te lig."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"Kry toegang tot ekstra liggingverskaffer-bevele"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Gee die program toegang tot ekstra liggingverskaffer-bevele. Dit kan die program dalk toelaat om in te meng met die werking van die GPS of ander liggingbronne."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"kry net op die voorgrond toegang tot presiese ligging"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Hierdie program kan jou presiese ligging kry net wanneer dit op die voorgrond is. Hierdie liggingdienste moet aangeskakel wees en op jou foon beskikbaar wees sodat die program hulle kan gebruik. Dit kan veroorsaak dat meer batterykrag gebruik word."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"verkry toegang tot benaderde ligging (netwerkgegrond)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Hierdie program kan jou ligging kry op grond van jou netwerkhulpbronne soos selfoontorings en Wi-Fi-netwerke. Hierdie liggingdienste moet aangeskakel en op jou tablet beskikbaar wees sodat die program hulle kan gebruik."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Vingerafdrukikoon"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"bestuur gesigstawinghardeware"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Laat program toe om metodes te benut om gesigtemplate vir gebruik by te voeg en uit te vee."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"gebruik gesigstawinghardeware"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Laat die program toe om gesigstawinghardeware vir stawing te gebruik"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Kon nie gesig verwerk nie. Probeer weer."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Gesig is te helder. Probeer met minder lig."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Gesig is te donker. Maak ligbron oop."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Beweeg sensor verder weg van gesig af."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Bring sensor nader aan gesig."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Beweeg sensor na bo."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Beweeg sensor na onder."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Beweeg sensor na regs."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Beweeg sensor na links."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Kyk na die sensor."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Geen gesig bespeur nie."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Hou gesig stil voor toestel."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Gesighardeware is nie beskikbaar nie."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Gesiguittelling is bereik. Probeer weer."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Gesig kan nie geberg word nie."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Gesighandeling is gekanselleer."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Te veel pogings. Probeer later weer."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Te veel pogings. Gesigstawingsensor is gedeaktiveer."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Probeer weer."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Geen gesigte is geregistreer nie."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Hierdie toestel het nie \'n gesigstawingsensor nie"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Gesig <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Gesig-ikoon"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"lees sinkroniseer-instellings"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Laat die program toe om die sinkroniseringinstellings van \'n rekening te lees. Byvoorbeeld, dit kan bepaal of die People-program met \'n rekening gesinkroniseer is."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"wissel tussen sinkronisasie aan en af"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi‑Fi het geen internettoegang nie"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tik vir opsies"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Veranderings aan jou warmkolinstellings"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Jou warmkolband het verander."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Hierdie toestel steun nie jou voorkeur vir net 5 GHz nie. Hierdie toestel sal in plaas daarvan die 5 GHz-band gebruik wanneer dit beskikbaar is."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Het oorgeskakel na <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Toestel gebruik <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wanneer <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> geen internettoegang het nie. Heffings kan geld."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Het oorgeskakel van <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 58f63bc..4c6a469 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"መገኛ አካባቢ"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"የዚህን መሣሪያ አካባቢ ይድረሱበት"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> የዚህ መሣሪያ አካባቢን እንዲደርስ ይፈቀድለት?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"መተግበሪያው እርስዎ ሲጠቀሙበት ብቻ ነው የአካባቢው መዳረሻ የሚኖረው።"</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"ሁልጊዜ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> የዚህ መሣሪያ አካባቢን እንዲደርስ ይፈቀድለት?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"መተግበሪያው ሁልጊዜ የአካባቢው መዳረሽ ይኖረዋል፣ እርስዎ መተግበሪያውን እየተጠቀሙ ባይሆኑም እንኳ።"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"ቀን መቁጠሪያ"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"የእርስዎን ቀን መቁጠሪያ ይድረሱበት"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ቀን መቁጠሪያዎን እንዲደርስ ይፈቀድለት?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"ይህ መተግበሪያ በእርስዎ ስልክ ላይ የቀን መቁጠሪያ ክስተቶችን ሊያክል፣ ሊያስወግድ ወይም ሊለውጥ ይችላል። ይህ መተግበሪያ ከቀን መቁጠሪያ የመጡ መስለው የሚታዩ መልእክቶችን ሊልክ ወይም ባለቤቶቹን ሳያሳውቅ ክስተቶችን ሊለውጥ ይችላል።"</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"ተጨማሪ ሥፍራ አቅራቢ ትዕዛዞችን ድረስ።"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"መተግበሪያው ተጨማሪ የአካባቢ አቅራቢ ትእዛዞችን እንዲደርስ ይፈቅድለታል። ይሄ መተግበሪያው በጂፒኤስ ወይም ሌላ የአካባቢ ምንጮች ስራ ላይ ጣልቃ እንዲገባ ሊፈቅድለት ይችላል።"</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"መዳረሻ ከፊት ለፊት ብቻ ትክክለኛ ነው"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"ይህ መተግበሪያ ከፊት ላይ ሆኖ ሲበራ ብቻ ትክክለኛውን መገኛ አካባቢ ማግኘት ይችላል። እነዚህ የመገኛ አካባቢ አገልግሎቶች መተግበሪያው መጠቀም እንዲችል ሊበሩ እና በእርስዎ ስልክ ላይ ሊገኙ የሚችሉ መሆን አለባቸው።"</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"ግምታዊ አካባቢን መድረስ (በአውታረ መረብ ላይ የተመሰረተ)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"ይህ መተግበሪያ እንደ የሕዋስ ማማዎች እና የWi-Fi አውታረ መረቦች ከመሳሰሉ የአውታረ መረብ ምንጮች ላይ በመመርኮዝ የእርስዎን መገኛ አካባቢ ማግኘት ይችላል። እነዚህ የመገኛ አካባቢ አገልግሎቶች መተግበሪያው መጠቀም እንዲችል ሊበሩ እና በእርስዎ ጡባዊ ላይ ሊገኙ የሚችሉ መሆን አለባቸው።"</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"የጣት አሻራ አዶ"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"የማረጋገጫ ሃርድዌር ፊትን ያስተዳድሩ"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"መተግበሪያው ጥቅም ላይ እንዲውሉ የፊት ቅንብር ደንቦችን ለማከል እና ለመሰረዝ የሚያስችሉ ስልቶችን እንዲያስጀምር ያስችለዋል።"</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"የፊት ማረጋገጫ ሃርድዌር ይጠቀሙ"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"መተግበሪያው የማረጋገጫ ሃርድዌር ለማረጋገጥ ሥራ እንዲጠቀም ያስችለዋል"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"ፊትን መሥራት አልተቻለም። እባክዎ እንደገና ይሞክሩ።"</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"ፊት ከልክ በላይ ብሩህ ነው። እባክዎ በዝቅተኛ ብርሃን ውስጥ ይሞክሩት።"</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"ፊት ከልክ በላይ ጨለም ያለ ነው። እባክዎ የብርሃን ምንጩን ይግለጹት።"</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"እባክዎ ዳሳሹን ከፊት አሁንም ያርቁት።"</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"እባክዎ ዳሳሹን ወደ ፊት ያስጠጉት።"</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"እባክዎ ዳሳሽን ከፍ ያድርጉት።"</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"እባክዎ ዳሳሽን ዝቅ ያድርጉት።"</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"እባክዎ ዳስሽን ወደ ቀኝ ያንቀሳቅሱት።"</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"እባክዎ ዳስሽን ወደ ግራ ያንቀሳቅሱት።"</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"እባክዎ ዳሳሹ ላይ ይመልከቱ።"</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"ምንም መልክ አልተገኘም።"</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"ፊትዎትን ከመሣሪያው ፊት ለፊት ሳያነቃንቁ ያቆዩት።"</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"የፊት ሃርድዌር አይገኝም።"</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"የፊት ማብቂያ ጊዜ ደርሷል። እንደገና ይሞክሩ።"</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"ፊት ሊከማች አይችልም።"</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"የፊት ሥርዓተ ክወና ተሰርዟል።"</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"ከልክ በላይ ብዙ ሙከራዎች። በኋላ ላይ እንደገና ይሞክሩ።"</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"በጣም ብዙ ሙከራዎች። የፊት ማረጋገጫ ተሰናክሏል።"</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"እንደገና ይሞክሩ።"</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"ምንም ፊት አልተመዘገበም።"</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"ይህ መሣሪያ የፊት ማረጋገጫ ዳሳሽ የለውም"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"ፊት <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"የፊት አዶ"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"የሥምሪያ ቅንብሮች አንብብ"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"መተግበሪያው የአንድ መለያ የማመሳሰል ቅንብሮችን እንዲያነብ ይፈቅድለታል። ለምሳሌ ይህ የሰዎች መተግበሪያ ከመለያ ጋር መመሳሰሉን አለመመሳሰሉን ሊወስን ይችላል።"</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ማመሳሰያ በማብራትና በማጥፋት መካከል ቀያይር"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi በይነመረብ መዳረሻ የለውም"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ለአማራጮች መታ ያድርጉ"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"በእርስዎ ሆትስፖት ቅንብሮች ላይ ለውጦች"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"የእርስዎ ሆትስፖት ባንድ ተለውጧል።"</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"ይህ መሣሪያ የእርስዎን ምርጫ ለ5GHz ብቻ አይደግፍም። በምትኩ፣ ይህ መሣሪያ ሲገኝ 5GHz ባንድ ይጠቀማል።"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"ወደ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ተቀይሯል"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ምንም ዓይነት የበይነመረብ ግንኙነት በማይኖረው ጊዜ መሣሪያዎች <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ን ይጠቀማሉ። ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ።"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"ከ<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ወደ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ተቀይሯል"</string>
@@ -1792,7 +1828,7 @@
<string name="work_mode_turn_on" msgid="2062544985670564875">"አብራ"</string>
<string name="deprecated_target_sdk_message" msgid="1449696506742572767">"ይህ መተግበሪያ ለቆየ የAndroid ስሪት ነው የተገነባው፣ እና በአግባቡ ላይሰራ ይችላል። ዝማኔዎች ካሉ ለመመልከት ይሞክሩ፣ ወይም ደግሞ ገንቢውን ያነጋግሩ።"</string>
<string name="deprecated_target_sdk_app_store" msgid="5032340500368495077">"ዝማኔ ካለ አረጋግጥ"</string>
- <string name="new_sms_notification_title" msgid="8442817549127555977">"አዲስ መልእክቶች አለዎት"</string>
+ <string name="new_sms_notification_title" msgid="8442817549127555977">"አዲስ መልዕክቶች አለዎት"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"ለመመልከት የኤስኤምኤስ መተግበሪያ ይክፈቱ"</string>
<string name="user_encrypted_title" msgid="9054897468831672082">"አንዳንድ ተግባሮች የተገደቡ ሊሆኑ ይችላሉ"</string>
<string name="user_encrypted_message" msgid="4923292604515744267">"ለመክፈት መታ ያድርጉ"</string>
@@ -1849,7 +1885,7 @@
<string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"ረጋ ይበሉና በአቅራቢያ ያለ መጠለያ ይፈልጉ።"</string>
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"ወዲያውኑ ከባህር ዳርቻ አካባቢዎች እና የወንዝ ዳርቻ አካባቢዎች ይውጡና እንደ ከፍ ያለ መሬት ያሉ ከአደጋ የተሻለ ደህንነት ወዳቸው ቦታዎች ይሂዱ።"</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"ረጋ ይበሉና በአቅራቢያ ያለ መጠለያ ይፈልጉ።"</string>
- <string name="etws_primary_default_message_test" msgid="2709597093560037455">"የአስቸኳይ አደጋ መልእክቶች ሙከራ"</string>
+ <string name="etws_primary_default_message_test" msgid="2709597093560037455">"የአስቸኳይ አደጋ መልዕክቶች ሙከራ"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"ምላሽ ስጥ"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="5767701075994754356">"ሲም ለድምጽ አይፈቀድም"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 492def8..4c3aa00 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -288,6 +288,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"الموقع الجغرافي"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"الوصول إلى موقع هذا الجهاز"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"هل تريد السماح لتطبيق <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> بالوصول إلى الموقع الجغرافي لهذا الجهاز؟"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"لن يكون بإمكان التطبيق الوصول إلى الموقع الجغرافي إلا عند استخدامك لهذا التطبيق."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"هل تريد السماح دائمًا لتطبيق <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> بالوصول إلى الموقع الجغرافي لهذا الجهاز؟"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"سيكون بإمكان التطبيق دائمًا الوصول إلى الموقع الجغرافي، حتى عند عدم استخدامك لهذا التطبيق."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"التقويم"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"الوصول تقويمك"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"هل تريد السماح لتطبيق <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> بالدخول إلى التقويم؟"</string>
@@ -414,8 +417,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"يمكن لهذا التطبيق إضافة أحداث تقويم أو إزالتها أو تغييرها على الهاتف. كما يمكنه إرسال رسائل يبدو أنها واردة من مالكي التقويم، ويمكنه كذلك تغيير الأحداث بدون إشعار مالكيها."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"الدخول إلى المزيد من أوامر موفر الموقع"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"للسماح للتطبيق بالدخول إلى أوامر إضافية لموفر الموقع. قد يتيح هذا للتطبيق التداخل مع تشغيل تقنية نظام تحديد المواقع العالمي (GPS) أو مصادر الموقع الأخرى."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"الوصول إلى الموقع الجغرافي الدقيق في الواجهة الأمامية فقط"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"لا يمكن لهذا التطبيق معرفة موقعك الجغرافي بالضبط إلا عندما يعمل في الخلفية. ويجب تفعيل خدمات الموقع الجغرافي هذه وأن تكون متاحة على الهاتف حتى يتمكن التطبيق من استخدامها. وقد يؤدي هذا إلى زيادة استهلاك طاقة البطارية."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"الوصول إلى الموقع التقريبي (استنادًا إلى الشبكة)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"يمكن لهذا التطبيق معرفة موقعك من خلال مصادر الشبكات مثل أبراج الجوّال وشبكات Wi-Fi. ويجب تشغيل خدمات المواقع هذه وأن تكون متاحة على الجهاز اللوحي حتى يتمكن التطبيق من استخدامها."</string>
@@ -530,6 +532,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"رمز بصمة الإصبع"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"إدارة أجهزة مصادقة الوجه"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"السماح للتطبيق باستدعاء طرق لإضافة نماذج من الوجوه وحذفها"</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"استخدام أجهزة مصادقة الوجه"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"السماح للتطبيق باستخدام أجهزة مصادقة الوجه"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"تعذَّر التعرُّف على الوجه. يُرجى إعادة المحاولة."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"الوجه ساطع جدًا. يُرجى إعادة المحاولة بإضاءة أقل."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"الوجه مظلم جدًا. يُرجى الاستعانة بمصدر إضاءة."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"يُرجى إبعاد جهاز الاستشعار عن الوجه."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"يُرجى تقريب جهاز الاستشعار من الوجه."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"يُرجى تحريك جهاز الاستشعار للأعلى."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"يُرجى تحريك جهاز الاستشعار للأسفل."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"يُرجى تحريك جهاز الاستشعار جهة اليمين."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"يُرجى تحريك جهاز الاستشعار جهة اليسار."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"يُرجى النظر إلى جهاز الاستشعار."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"لم يتم رصد أي وجه."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"يُرجى جعل الوجه ثابتًا أمام الجهاز."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"أجهزة مصادقة الوجه غير متاحة."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"انتهت مهلة التعرُّف على الوجه. أعِد المحاولة."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"يتعذَّر حفظ الوجه."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"تمّ إلغاء عملية مصادقة الوجه."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"تمّ إجراء محاولات كثيرة. أعِد المحاولة لاحقًا."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"تمّ إجراء محاولات كثيرة. ميزة مصادقة الوجه متوقفة."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"يُرجى إعادة المحاولة."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"ليس هناك وجه مسجّل."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"لا يحتوي هذا الجهاز على جهاز استشعار مصادقة الوجه."</string>
+ <string name="face_name_template" msgid="7004562145809595384">"الوجه <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"رمز الوجه"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"قراءة إعدادات المزامنة"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"للسماح للتطبيق بقراءة الإعدادات المتزامنة لحساب ما. على سبيل المثال، يمكن أن يؤدي هذا إلى تحديد ما إذا تمت مزامنة تطبيق \"الأشخاص\" مع حساب ما."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"التبديل بين تشغيل المزامنة وإيقافها"</string>
@@ -1191,7 +1224,7 @@
<string name="android_start_title" product="default" msgid="4536778526365907780">"جارٍ بدء تشغيل الهاتف…"</string>
<string name="android_start_title" product="tablet" msgid="4929837533850340472">"جارٍ بدء تشغيل الجهاز اللوحي…"</string>
<string name="android_start_title" product="device" msgid="7467484093260449437">"جارٍ بدء تشغيل الجهاز…"</string>
- <string name="android_upgrading_fstrim" msgid="8036718871534640010">"جارٍ تحسين السعة التخزينية."</string>
+ <string name="android_upgrading_fstrim" msgid="8036718871534640010">"جارٍ تحسين سعة التخزين."</string>
<string name="android_upgrading_notification_title" product="default" msgid="1511552415039349062">"جارٍ إنهاء تحديث النظام…"</string>
<string name="app_upgrading_toast" msgid="3008139776215597053">"جارٍ ترقية <xliff:g id="APPLICATION">%1$s</xliff:g>…"</string>
<string name="android_upgrading_apk" msgid="7904042682111526169">"جارٍ تحسين التطبيق <xliff:g id="NUMBER_0">%1$d</xliff:g> من <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
@@ -1266,6 +1299,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"شبكة Wi-Fi غير متصلة بالإنترنت"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"انقر للحصول على الخيارات."</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"التغييرات التي طرأت على إعدادات نقطة الاتصال"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"تمّ تغيير نطاق نقطة الاتصال الخاصة بك."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"لا يتوافق هذا الجهاز مع إعدادك المفضّل الخاص باستخدام النطاق 5 غيغاهرتز فقط. وسيستخدم الجهاز بدلاً من ذلك النطاق 5 غيغاهرتز عندما يكون متاحًا."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"تم التبديل إلى <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"يستخدم الجهاز <xliff:g id="NEW_NETWORK">%1$s</xliff:g> عندما لا يتوفر اتصال بالإنترنت في شبكة <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>، ويمكن أن يتم فرض رسوم مقابل ذلك."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"تم التبديل من <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> إلى <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1533,7 +1569,7 @@
<string name="action_menu_overflow_description" msgid="2295659037509008453">"المزيد من الخيارات"</string>
<string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s، %2$s"</string>
<string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s، %2$s، %3$s"</string>
- <string name="storage_internal" msgid="3570990907910199483">"السعة التخزينية المشتركة الداخلية"</string>
+ <string name="storage_internal" msgid="3570990907910199483">"سعة التخزين المشتركة الداخلية"</string>
<string name="storage_sd_card" msgid="3282948861378286745">"بطاقة SD"</string>
<string name="storage_sd_card_label" msgid="6347111320774379257">"بطاقة SD من <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb_drive" msgid="6261899683292244209">"محرك أقراص USB"</string>
@@ -1954,7 +1990,7 @@
<string name="app_category_news" msgid="7496506240743986873">"الأخبار والمجلات"</string>
<string name="app_category_maps" msgid="5878491404538024367">"الخرائط والتنقل"</string>
<string name="app_category_productivity" msgid="3742083261781538852">"الإنتاجية"</string>
- <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"السعة التخزينية للجهاز"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"سعة التخزين للجهاز"</string>
<string name="adb_debugging_notification_channel_tv" msgid="5537766997350092316">"تصحيح أخطاء USB"</string>
<string name="time_picker_hour_label" msgid="2979075098868106450">"ساعة"</string>
<string name="time_picker_minute_label" msgid="5168864173796598399">"دقيقة"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 5e6dccc..edd4f88 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"অৱস্থান"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"এই ডিভাইচৰ অৱস্থান ব্যৱহাৰ কৰিব পাৰে"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ক এই ডিভাইচটোৰ অৱস্থান জানিবলৈ অনুমতি দিবনে?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"আপুনি এই এপ্ ব্য়ৱহাৰ কৰি থাকোঁতে ই সদায় অৱস্থান চাব পাৰে।"</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ক সদায় এই ডিভাইচৰ অৱস্থান চাবলৈ অনুমতি দিবনে?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"আপুনি এই এপ্ ব্য়ৱহাৰ কৰি থকা নাই যদিও ই সদায় অৱস্থান চাব পাৰে।"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"কেলেণ্ডাৰ"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"আপোনাৰ কেলেণ্ডাৰ ব্যৱহাৰ কৰিব পাৰে"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ক আপোনাৰ কেলেণ্ডাৰ চাবলৈ অনুমতি দিবনে?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"এই এপে আপোনাৰ ফ\'নৰ কেলেণ্ডাৰত কার্যক্ৰম যোগ দিব, আঁতৰাব বা সলনি কৰিব পাৰে। ই এনে বাৰ্তা পঠিয়াব পাৰে যিবোৰ কেলেণ্ডাৰৰ গৰাকীৰ পৰা অহা যেন লাগে বা ই গৰাকীক নজনোৱাকৈ কাৰ্যক্ৰম সলনি কৰিব পাৰে৷"</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"অতিৰিক্ত অৱস্থান দেখুওৱা নির্দেশত প্ৰৱেশ কৰক"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"অৱস্থানৰ অতিৰিক্ত নির্দেশনাসমূহত প্ৰৱেশ কৰিবলৈ এপক অনুমতি দিয়ে। ইয়ে এপটোক জিপিএছ বা অন্য অৱস্থান উৎসসমূহৰ কাৰ্যকলাপত হস্তক্ষেপ কৰাৰ সুযোগ দিব পাৰে।"</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"কেৱল অগ্ৰভূমিত অৱস্থানৰ সঠিক তথ্য় পাওক"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"এই এপটোৱে যেতিয়া ই নেপথ্যত চলি থাকে তেতিয়া আপোনাৰ সঠিক অৱস্থান নিৰ্ণয় কৰিব পাৰে। এপটোৱে ব্যৱহাৰ কৰিব পৰাকৈ এই অৱস্থান সেৱাসমূহ অন হৈ থাকিবই লাগিব আৰু আপোনাৰ ফ\'নত উপলব্ধ হ\'ব লাগিব। ইয়াৰ ফলত বেটাৰিৰ খৰচ বাঢ়িব পাৰে।"</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"অনুমানিক অৱস্থান (নেটৱর্ক ভিত্তিক) ব্যৱহাৰ কৰিব পাৰে"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"চেল টাৱাৰ আৰু ৱাই-ফাই নেটৱর্কৰ দৰে নেটৱর্কৰ উৎসসমূহক ভিত্তি কৰি এই এপটোৱে আপোনাৰ অৱস্থান নিৰ্ণয় কৰিব পাৰে। এই অৱস্থানৰ সেৱাসমূহ অন হৈ থাকিলে আৰু আপোনাৰ টেবলেটটোত উপলব্ধ হ\'লেহে এপটোৱে সেইবোৰ ব্যৱহাৰ কৰিবলৈ সক্ষম হ\'ব।"</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"ফিংগাৰপ্ৰিণ্ট আইকন"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"মুখমণ্ডল সত্যাপন হাৰ্ডৱেৰ পৰিচালনা কৰক"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"মুখমণ্ডলৰ টেম্প্লেট যোগ কৰাৰ বা মচাৰ পদ্ধতি কামত লগাবলৈ আহ্বান কৰিবলৈ এপটোক অনুমতি দিয়ে।"</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"মুখমণ্ডল সত্যাপন হাৰ্ডৱেৰ ব্যৱহাৰ কৰক"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"বিশ্বাসযোগ্য়তা প্ৰমাণীকৰণৰ বাবে এপক মুখমণ্ডল সত্যাপন হাৰ্ডৱেৰ ব্য়ৱহাৰ কৰিবলৈ অনুমতি দিয়ে"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"মুখমণ্ডল চিনাক্ত কৰিব পৰা নাই; আকৌ চেষ্টা কৰক।"</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"মুখমণ্ডল অত্যন্ত উজ্জ্বল হৈছে। অনুগ্ৰহ কৰি পোহৰ কম থকা ঠাইত চেষ্টা কৰক।"</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"মুখমণ্ডল অত্যন্ত আন্ধাৰ হৈছে। অনুগ্ৰহ কৰি পোহৰ থকা ঠাইলৈ যাওক।"</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"অনুগ্ৰহ কৰি মুখৰ পৰা ছেন্সৰ অলপ দূৰত ৰাখক।"</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"অনুগ্ৰহ কৰি ছেন্সৰটো মুখৰ ওচৰলৈ আনক।"</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"অনুগ্ৰহ কৰি ছেন্সৰটো ওপৰলৈ নিয়ক।"</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"অনুগ্ৰহ কৰি ছেন্সৰটো তললৈ নিয়ক।"</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"অনুগ্ৰহ কৰি ছেন্সৰটো সোঁফাললৈ নিয়ক।"</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"অনুগ্ৰহ কৰি ছেন্সৰটো বাওঁফাললৈ নিয়ক।"</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"অনুগ্ৰহ কৰি ছেন্সৰটোলৈ চাওক।"</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"কোনো মুখমণ্ডল চিনাক্ত কৰিব পৰা নগ’ল।"</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"ডিভাইচৰ আগত মুখখন স্থিৰ কৰি ৰাখক।"</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"মুখমণ্ডলৰ হাৰ্ডৱেৰ উপলব্ধ নহয়।"</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"মুখমণ্ডল গ্ৰহণৰ সময়সীমা উকলি গৈছে। আকৌ চেষ্টা কৰক।"</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"মুখমণ্ডল সঞ্চয় কৰিব নোৱাৰি।"</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"মুখমণ্ডলৰ প্ৰক্ৰিয়া বাতিল কৰা হ’ল।"</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"অত্যধিক ভুল প্ৰয়াস। কিছুসময়ৰ পাছত আকৌ চেষ্টা কৰক।"</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"অত্যধিক প্ৰয়াস। মুখমণ্ডলৰ জৰিয়তে সত্যাপন অক্ষম কৰা হ’ল।"</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"আকৌ চেষ্টা কৰক।"</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"কোনো মুখমণ্ডল যোগ কৰা নহ’ল।"</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"এই ডিভাইচটোত মুখমণ্ডল সত্যাপন ছেন্সৰ নাই।"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"মুখমণ্ডল <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"মুখমণ্ডলৰ আইকন"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"ছিংকৰ ছেটিংসমূহ পঢ়ক"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"একাউণ্টৰ ছিংক ছেটিংবোৰ পঢ়িবলৈ এপক অনুমতি দিয়ে। যেনে, People এপ কোনো একাউণ্টত ছিংক কৰা হৈছে নে নাই সেয়া নির্ধাৰণ কৰিব পাৰে।"</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ছিংকক অন আৰু অফ ট\'গল কৰক"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"ৱাই-ফাইত ইন্টাৰনেট নাই"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"অধিক বিকল্পৰ বাবে টিপক"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"আপোনাৰ হটস্পট ছেটিংসমূহত কৰা সালসলনি"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"আপোনাৰ হটস্পটৰ বেণ্ড সলনি কৰা হ’ল।"</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"আপোনাৰ কেৱল ৫গিগাহাৰ্টজৰ প্ৰতি অগ্ৰাধিকাৰ এই ডিভাচইচটোৱে সমৰ্থন নকৰে। ইয়াৰ পৰিৱৰ্তে, ডিভাচইচটোৱে যেতিয়া ৫গিগাহাৰ্টজ বেণ্ড উপলব্ধ হ’ব তেতিয়া সেইয়া ব্যৱহাৰ কৰিব।"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>লৈ সলনি কৰা হ\'ল"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"যেতিয়া <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>ত ইণ্টাৰনেট নাথাকে, তেতিয়া ডিভাইচে <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ক ব্যৱহাৰ কৰে। মাচুল প্ৰযোজ্য হ\'ব পাৰে।"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>ৰ পৰা <xliff:g id="NEW_NETWORK">%2$s</xliff:g> লৈ সলনি কৰা হ\'ল"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 6c9fb75..645c5ca 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Yer"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"cihazın yerini bilmək"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> tətbiqinə bu cihazın məkanına daxil olmaq icazəsi verilsin?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Tətbiq yalnız ondan istifadə etiyiniz zaman məkanı əldə edə bilər."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> tətbiqinə bu cihazın məkanına daxil olmaq icazəsi verilsin?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Tətbiq hətta ondan istifadə etmədiyiniz zaman belə məkanı əldə edə bilər."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Təqvim"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"təqvimə daxil olun"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> tətbiqinə təqvimə daxil olmaq icazəsi verilsin?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Bu tətbiq telefonunuzda təqvim tədbirləri əlavə edə, silə və ya dəyişiklik edə bilər. Həmçinin bu tətbiq təqvim sahiblərindən gəlmə ehtimalı olan mesajları göndərə və ya sahiblərinə bildirmədən tədbirlərdə dəyişiklik edə bilər."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"əlavə məkan provayderi əmrlərinə çıxış"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Tətbiqə ekstra məkan provayder əmrlərinə girişə imkan verir. Bu, tətbiqə GPS və ya digər lokal mənbələrlə əməliyyata müdaxiləyə imkan verə bilər."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"yalnız ön planda dəqiq məkana daxil olun"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Bu tətbiq yalnız ön fonda olduqda dəqiq məkanınızı əldə edə bilər. Tətbiqin bunlardan istifadə etməsi üçün bu məkan xidmətləri aktiv edilməlidir və telefonda əlçatan olmalıdır. Bu, batareya sərfiyyatını artıra bilər."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"təxmini məkana (şəbəkə əsaslı) giriş"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Bu tətbiq mobil qüllələr və Wi-Fi şəbəkələri kimi şəbəkə mənbələrinin əassında əkanınızı əldə edə bilər. Bu məkan xidmətləri aktiv edilməlidir və planşetdə tətbiq tərəfindən istifadə üçün əlçatan olmalıdır."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Barmaq izi ikonası"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"üz identifikasiyası proqramını idarə edin"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Proqramdan istifadə üçün barmaq izi şablonlarını əlavə etmək və silmək məqsədilə üsullara müraciət etməyə imkan verir."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"üz identifikasiyası proqramından istifadə edin"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Tətbiqin üz identifikasiyası proqramından identifikasiya zamanı istifadə etməsinə icazə verir"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Üz tanınmadı. Yenidən cəhd edin."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Üz çox parlaqdır. Daha zəif işıqda sınayın."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Üz çox tünddür. İşığı ortaya çıxarın."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Sensoru üzdən kənara gətirin."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Sensoru üzə biraz da yaxınlaşdırın."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Sensoru daha yuxarı gətirin."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Sensoru daha aşağı gətirin."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Sensoru sağa gətirin."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Sensoru sola gətirin."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Sensora baxın."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Üz aşkarlanmadı."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Üzü cihazın qarşısında sabit saxlayın."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Üz proqramı əlçatan deyil."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Üz proqramı taymerinin vaxtı bitdi. Yenidən cəhd edin."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Üz bərpa edilmədi."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Üz əməliyyatı ləğv edildi."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Həddindən çox cəhd. Sonraya saxlayın."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Həddindən çox cəhd. Üz identifikasiyası deaktiv edildi."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Yenidən cəhd edin."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Üz qeydə alınmayıb."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Bu cihazda üz identifikasiyası sensoru yoxdur."</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Üz <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Üz işarəsi"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"sinx ayarlarını oxu"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Tətbiqə hesablar üçün sinxronizasiya nizamlarını oxuma icazəsi verir. Məsələn, bu Şəxslər tətbiqinin sinxronizə olunub-olunmadığını təyin edə bilər."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"sinxronizasiyaya davam edir və onu söndürür"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi şəbəkəsinin internetə girişi yoxdur"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Seçimlər üçün tıklayın"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Hotspot ayarlarınızda dəyişiklik"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Hotspot qrupu dəyişdi."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Bu cihaz yalnız 5GHz üçün tərcihinizi dəstəkləmir. Əvəzinə əlçatan olduqda bu cihaz 5GHz qrupundan istifadə edəcək."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> şəbəkə növünə keçirildi"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> şəbəkəsinin internetə girişi olmadıqda, cihaz <xliff:g id="NEW_NETWORK">%1$s</xliff:g> şəbəkəsini istifadə edir. Xidmət haqqı tutula bilər."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> şəbəkəsindən <xliff:g id="NEW_NETWORK">%2$s</xliff:g> şəbəkəsinə keçirildi"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 386c8ca..a1310a2 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -279,6 +279,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Lokacija"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"pristupi lokaciji ovog uređaja"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Želite li da omogućite da <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> pristupa lokaciji ovog uređaja?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Aplikacija će imati pristup lokaciji samo dok koristite aplikaciju."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Želite li da omogućite da <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> pristupa lokaciji ovog uređaja?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Aplikacija će uvek imati pristup lokaciji, čak i kada ne koristite aplikaciju."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalendar"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"pristupi kalendaru"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Želite li da omogućite da <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> pristupa kalendaru?"</string>
@@ -405,8 +408,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Ova aplikaciji može da dodaje, uklanja ili menja događaje iz kalendara na telefonu. Ova aplikacija može da šalje poruke koje izgledaju kao da ih šalju vlasnici kalendara ili da menja događaje bez znanja vlasnika."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"pristup dodatnim komandama dobavljača lokacije"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Omogućava aplikaciji da pristupa dodatnim komandama davaoca usluga lokacije. To može da omogući aplikaciji da utiče na rad GPS-a ili drugih izvora lokacije."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"pristup preciznoj lokaciji samo u prvom planu"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Ova aplikacija može da odredi vašu tačnu lokaciju samo kada radi u prvom planu. Ove usluge lokacije moraju da budu uključene i dostupne na telefonu da bi aplikacija mogla da ih koristi. To može da poveća potrošnju baterije."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"pristup približnoj lokaciji (utvrđena preko mreže)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Ova aplikacija može da pristupi vašoj lokaciji pomoću izvora mreže, kao što su mobilni predajnici i Wi-Fi mreže. Ove usluge lokacije moraju da budu uključene i dostupne na tabletu da bi aplikacija mogla da ih koristi."</string>
@@ -521,6 +523,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Ikona otiska prsta"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"upravljanje hardv. za potvrdu identiteta pomoću lica"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Dozvoljava da aplikacija aktivira metode za dodavanje i brisanje šablona lica radi korišćenja."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"korišćenje hardv. za potvrdu identiteta pomoću lica"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Dozvoljava da aplikacija koristi hardver za potvrdu identiteta pomoću lica"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Obrada lica nije uspela. Probajte ponovo."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Lice je presvetlo. Probajte sa slabijim osvetljenjem."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Lice je isuviše tamno. Otkrijte izvor svetla."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Udaljite senzor od lica."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Približite senzor licu."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Pomerite senzor naviše."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Pomerite senzor naniže."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Pomerite senzor udesno."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Pomerite senzor ulevo."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Gledajte u senzor."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Nije otkriveno nijedno lice."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Zadržite lice ispred uređaja bez pomeranja."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Harvder za lice nije dostupan."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Isteklo je vreme za proveru lica. Probajte ponovo."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Nije moguće sačuvati lice."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Obrada lica je otkazana."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Previše pokušaja. Probajte ponovo kasnije."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Više pokušaja. Potvrda identiteta je onemogućena."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Probajte ponovo."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Nije registrovano nijedno lice."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Ovaj uređaj nema senzor za potvrdu identiteta pomoću lica"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Lice <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Ikona lica"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"čitanje podešavanja sinhronizacije"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Dozvoljava aplikaciji da čita podešavanja sinhronizacije za nalog. Na primer, ovako može da se utvrdi da li je aplikacija Ljudi sinhronizovana sa nalogom."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"uključivanje i isključivanje sinhronizacije"</string>
@@ -1200,6 +1233,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi nema pristup internetu"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Dodirnite za opcije"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Promene podešavanja za hotspot"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Opseg hotspota je promenjen."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Ovaj uređaj ne podržava podešavanje samo za 5 GHz. Uređaj će koristiti opseg od 5 GHz kada bude dostupan."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Prešli ste na tip mreže <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Uređaj koristi tip mreže <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kada tip mreže <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu. Možda će se naplaćivati troškovi."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Prešli ste sa tipa mreže <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na tip mreže <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index eb6b7c0..f990bef 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -282,6 +282,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Месцазнаходжанне"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"атрымліваць доступ да месцазнаходжання гэтай прылады"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Дазволіць праграме <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> доступ да звестак аб месцазнаходжанні гэтай прылады?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Праграма будзе мець доступ да звестак пра месцазнаходжанне, толькі калі яна выкарыстоўваецца."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Дазволіць праграме <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> мець доступ да месцазнаходжання?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Праграма заўсёды будзе мець доступ да звестак пра месцазнаходжанне, нават калі яна не выкарыстоўваецца."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Каляндар"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"атрымліваць доступ да вашага календара"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Дазволіць праграме <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> доступ да вашага календара?"</string>
@@ -408,8 +411,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Гэта праграма можа дадаваць, выдаляць або змяняць падзеі календара на вашым тэлефоне. Гэта праграма можа адпраўляць паведамленні, якія могуць здавацца адпраўленымі ўладальнікамі календара, або змяняць падзеі без апавяшчэння іх уладальнікаў."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"доступ да дадатковых камандаў пастаўшчыка месцазнаходжання"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Дазваляе праграме атрымліваць доступ да дадатковых каманд службаў вызначэння месцазнаходжання. Гэта можа дазволіць праграме ўмешвацца ў функцыянаванне GPS або іншых крыніц даных аб месцазнаходжаннi."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"доступ да дакладнага месцазнаходжання толькі ў асноўным рэжыме"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Гэта праграма можа атрымліваць звесткі пра ваша дакладнае месцазнаходжанне толькі ў асноўным рэжыме. Службы геалакацыі павінны быць уключаны і даступныя на вашым тэлефоне, каб праграма магла імі карыстацца. Гэта можа павялічыць спажыванне зараду акумулятара."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"атрымліваць доступ да прыблізнага месцазнаходжання (на аснове даных сеткі)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Гэта праграма можа атрымліваць звесткі пра ваша месцазнаходжанне на падставе даных сеткавых крыніц, такіх як вышкі сотавай сувязі і сеткі Wi-Fi. Гэтыя сэрвісы вызначэння месцазнаходжання павінны быць уключаны i даступныя на вашым планшэце, каб праграма магла іх выкарыстоўваць."</string>
@@ -524,6 +526,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Значок адбіткаў пальцаў"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"кіраваць абсталяваннем для распазнавання твару"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Праграма зможа дадаваць і выдаляць шаблоны твару."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"карыстацца абсталяваннем для распазнавання твару"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Праграма зможа выкарыстоўваць абсталяванне распазнавання твару для аўтэнтыфікацыі"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Не ўдалося распазнаць твар. Паўтарыце спробу."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Твар занадта светлы. Паспрабуйце зменшыць святло."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Твар занадта цёмны. Павялічце асвятленне."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Перамясціце датчык далей ад твару."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Наблізьце датчык да твару."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Падыміце датчык вышэй."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Апусціце датчык ніжэй."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Перамясціце датчык управа."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Перамясціце датчык улева."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Глядзіце на датчык."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Твар не знойдзены."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Трымайце твар перад прыладай."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Абсталяванне для распазнавання твару недаступнае."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Час чакання твару выйшаў. Паўтарыце спробу."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Не ўдалося захаваць твар."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Распазнаванне твару скасавана."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Занадта шмат спроб. Паўтарыце спробу пазней."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Занадта шмат спроб. Аўтэнтыфікацыя твару адключана"</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Паўтарыце спробу."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Твар не зарэгістраваны."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"На гэтай прыладзе адсутнічае датчык аўтэнтыфікацыі твару"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Твар <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Значок твару"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"чытаць параметры сінхранізацыі"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Дазваляе прыкладанням чытаць параметры сінхранізацыі для ўліковага запісу. Напрыклад, яны могуць вызначыць, цi сiнхранiзавана з улiковым запiсам прыкладанне \"Кантакты\"."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"уключэнне ці адключэнне сінхранізацыi"</string>
@@ -1222,6 +1255,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"У Wi-Fi няма доступу да інтэрнэту"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Дакраніцеся, каб убачыць параметры"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Змяненні ў наладах хот-спота"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Частата хот-спота змянілася."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Прылада не можа працаваць толькі на частаце 5 ГГц. Гэта частата будзе выкарыстоўвацца, калі гэта магчыма."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Выкананы пераход да <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Прылада выкарыстоўвае сетку <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, калі ў сетцы <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> няма доступу да інтэрнэту. Можа спаганяцца плата."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Выкананы пераход з <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> да <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 176239f..3142833 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Местоположение"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"получи достъп до местоположението на това устройство"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Да се разреши ли на <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> да осъществява достъп до местоположението на това устройство?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Само когато използвате приложението, то ще има достъп до местоположението."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Да се разреши ли на <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> достъп до местопол. на у-вото?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Дори когато не използвате приложението, то винаги ще има достъп до местоположението."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Календар"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"има достъп до календара ви"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Да се разреши ли на <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> да осъществява достъп до календара ви?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Това приложение може да добавя, премахва или променя събития в календара на телефона ви. То е в състояние да изпраща съобщения от името на собственици на календари или да променя събития, без да уведомява собствениците."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"достъп до допълнителни команди на доставчика на местоположение"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Разрешава на приложението достъп до допълнителни команди на доставчика на местоположение. Това може да позволи на приложението да смущава работата на GPS или на другите източници на местоположение."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"достъп до точното местоположение само на преден план"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Приложението може да получава данни за точното ви местоположение само когато работи на преден план. Тези услуги за местоположение трябва да са включени и налице на телефона ви, за да могат да се използват от приложението. Това може да увеличи потреблението на батерията."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"достъп до приблизителното местоположение (въз основа на мрежата)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Приложението може да получава данни за местоположението ви въз основа на мрежови източници, като клетъчни кули и Wi-Fi. Тези услуги за местоположение трябва да са включени и налице на таблета ви, за да могат да се използват от приложението."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Икона за отпечатък"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"управление на хардуера за удостоверяване с лице"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Разрешава на прил. да извиква методи за добавяне и изтриване на лицеви шаблони за ползване"</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"използване на хардуера за удостоверяване с лице"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Разрешава на приложението при необходимост да използва хардуера за удостоверяване с лице"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Лицето не можа да се обработи. Опитайте отново."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Лицето е твърде осветено. Oпитайте на по-тъмно."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Лицето е твърде тъмно. Моля, осветете го по-добре."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Моля, отдалечете сензора от лицето си."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Моля, приближете сензора към лицето си."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Моля, повдигнете сензора."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Моля, преместете сензора надолу."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Моля, преместете сензора надясно."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Моля, преместете сензора наляво."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Моля, гледайте към сензора."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Не е открито лице."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Задръжте лицето си неподвижно пред устройството."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Няма достъп до хардуера за лице."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Времето за изчакване изтече. Опитайте отново."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Лицето не може да бъде съхранено."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Операцията с лице е анулирана."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Твърде много опити. Опитайте отново по-късно."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Твърде много опити. Удост. с лице е деактивирано."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Опитайте отново."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Няма регистрирано лице."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Това устройство няма сензор за удостоверяване с лице"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Лице <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Икона на лице"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"четене на настройките за синхронизиране"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Разрешава на приложението да чете настройките за синхронизиране на профил. Например това може да определи дали приложението Хора е синхронизирано с даден профил."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"включване и изключване на синхронизирането"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi мрежата няма достъп до интернет"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Докоснете за опции"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Промени в настройките ви за точка за достъп"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Честотната лента на точката ви за достъп е променена."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Това устройство не поддържа предпочитанието ви за използване само на честотната лента от 5 ГХц. Вместо това то ще я ползва, когато е възможно."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Превключи се към <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Устройството използва <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, когато <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> няма достъп до интернет. Възможно е да бъдете таксувани."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Превключи се от <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> към <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 0bca847..410d2c6 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"লোকেশন"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"এই ডিভাইসের লোকেশন অ্যাক্সেস"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>-কে এই ডিভাইসের লোকেশন অ্যাক্সেস করতে দেবেন?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"আপনি এই অ্যাপটি ব্যবহার করার সময়েই সেটি আপনার লোকেশন অ্যাক্সেস করতে পারবে।"</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>কে সবসময় এই ডিভাইসের লোকেশন অ্যাক্সেস করতে দেবেন?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"এই অ্যাপটি সবসময় আপনার লোকেশন অ্যাক্সেস করতে পারবে, এমনকি আপনি অ্যাপটি ব্যবহার না করার সময়েও।"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"ক্যালেন্ডার"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"আপনার ক্যালেন্ডারে অ্যাক্সেস"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>-কে আপনার ক্যালেন্ডারে অ্যাক্সেস দেবেন?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"এই অ্যাপটি আপনার ফোনে ক্যালেন্ডার ইভেন্টগুলি যোগ করতে, সরাতে বা পরিবর্তিত করতে পারে৷ এই অ্যাপটি মেসেজ পাঠাতে পারে যা ক্যালেন্ডারের মাললিকের থেকে এসেছে বলে মনে হয় বা ইভেন্টগুলিকে তাদের মালিকদের না জানিয়েই পরিবর্তিত করতে পারে৷"</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"অতিরিক্ত লোকেশন প্রদানকারী কমান্ডগুলি অ্যাক্সেস করে"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"লোকেশনের সাথে সম্পর্কিত তথ্য প্রদানকারীর অতিরিক্ত কম্যান্ডগুলিকে অ্যাপ্লিকেশানটিকে মঞ্জুর করে৷ এটি অ্যাপ্লিকেশানটিকে GPS অথবা অন্যান্য লোকেশন নির্ণয়ের সাথে সম্পর্কিত উৎসগুলির ক্রিয়াপ্রণালীর নিয়ন্ত্রণকে মঞ্জুর করতে পারে৷"</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"শুধুমাত্র অ্যাপটি খোলা থাকলে আপনার যথাযথ লোকেশন অ্যাক্সেস করা"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"এই অ্যাপটি ফোরগ্রাউন্ডে চলতে থাকলে যেকোনও সময়ে আপনার যথাযথ লোকেশন জানতে পারবে। এই লোকেশন পরিষেবাগুলি অবশ্যই চালু রাখতে হবে এবং আপনার ফোনে সেগুলি উপলভ্য থাকতে হবে যাতে অ্যাপটি সেগুলি ব্যবহার করতে পারে। এর জন্য অতিরিক্ত ব্যাটারি খরচ হতে পারে।"</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"আনুমানিক লোকেশন (নেটওয়ার্ক-ভিত্তিক) অ্যাক্সেস করুন"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"মোবাইল টাওয়ার এবং ওয়াই-ফাই নেটওয়ার্কগুলির মত নেটওয়ার্ক উৎসগুলির উপর ভিত্তি করে এই অ্যাপটি আপনার লোকেশন শনাক্ত করতে পারে৷ এই লোকেশন পরিষেবাগুলি অবশ্যই চালু রাখতে হবে এবং অ্যাপটি যাতে সেগুলি ব্যবহার করতে পারে সেইজন্য সেগুলিকে আপনার ট্যাবলেটে উপলব্ধ করে রাখতে হবে৷"</string>
@@ -518,6 +520,64 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"আঙ্গুলের ছাপ আইকন"</string>
+ <!-- no translation found for permlab_manageFace (2137540986007309781) -->
+ <skip />
+ <!-- no translation found for permdesc_manageFace (8919637120670185330) -->
+ <skip />
+ <!-- no translation found for permlab_useFaceAuthentication (8996134460546804535) -->
+ <skip />
+ <!-- no translation found for permdesc_useFaceAuthentication (5011118722951833089) -->
+ <skip />
+ <!-- no translation found for face_acquired_insufficient (5901287247766106330) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_bright (610606792381297174) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_dark (7229162716976778371) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_close (1980310037427755293) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_far (4494571381828850007) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_high (228411096134808372) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_low (4539774649296349109) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_right (1650292067226118760) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_left (2712489669456176505) -->
+ <skip />
+ <!-- no translation found for face_acquired_poor_gaze (8344973502980415859) -->
+ <skip />
+ <!-- no translation found for face_acquired_not_detected (5707782294589511391) -->
+ <skip />
+ <!-- no translation found for face_acquired_not_steady (3722829465011040042) -->
+ <skip />
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <!-- no translation found for face_error_hw_not_available (6255891785768984615) -->
+ <skip />
+ <!-- no translation found for face_error_timeout (4014326147867150054) -->
+ <skip />
+ <!-- no translation found for face_error_no_space (8224993703466381314) -->
+ <skip />
+ <!-- no translation found for face_error_canceled (283945501061931023) -->
+ <skip />
+ <!-- no translation found for face_error_lockout (3407426963155388504) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_permanent (8198354656746088890) -->
+ <skip />
+ <!-- no translation found for face_error_unable_to_process (238761109287767270) -->
+ <skip />
+ <!-- no translation found for face_error_not_enrolled (9166792142679691323) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (4737289254517095671) -->
+ <skip />
+ <!-- no translation found for face_name_template (7004562145809595384) -->
+ <skip />
+ <string-array name="face_error_vendor">
+ </string-array>
+ <!-- no translation found for face_icon_content_description (4024817159806482191) -->
+ <skip />
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"সিঙ্ক সেটিংস পড়ে"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"অ্যাপ্লিকেশানটিকে একটি অ্যাকাউন্টের জন্য সিঙ্ক সেটিংস পড়ার অনুমতি দেয়৷ উদাহরণস্বরূপ, \'পিপল\' অ্যাপ্লিকেশানটি কোনো অ্যাকাউন্টের সাথে সিঙ্ক করা আছে কিনা তা নির্ধারণ করতে পারে৷"</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"সমন্বয় চালু এবং বন্ধ করা টগল করুন"</string>
@@ -1178,6 +1238,12 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"ওয়াই-ফাই এ ইন্টারনেট অ্যাক্সেস নেই"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"বিকল্পগুলির জন্য আলতো চাপুন"</string>
+ <!-- no translation found for wifi_softap_config_change (8475911871165857607) -->
+ <skip />
+ <!-- no translation found for wifi_softap_config_change_summary (7601233252456548891) -->
+ <skip />
+ <!-- no translation found for wifi_softap_config_change_detailed (8022936822860678033) -->
+ <skip />
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> এ পাল্টানো হয়েছে"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> এ ইন্টারনেট অ্যাক্সেস না থাকলে <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ব্যবহার করা হয়৷ ডেটা চার্জ প্রযোজ্য৷"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> থেকে <xliff:g id="NEW_NETWORK">%2$s</xliff:g> এ পাল্টানো হয়েছে"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 151dc076..fa354ae 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -279,6 +279,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Lokacija"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"pristupa lokaciji ovog uređaja"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Dozvoliti aplikaciji <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> pristup lokaciji ovog uređaja?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Ova aplikacija će moći pristupiti lokaciji uređaja samo kada je koristite."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Uvijek dozvoliti da <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> pristupi lokaciji uređaja?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Ova aplikacija će uvijek moći pristupiti lokaciji uređaja, čak i kada je ne koristite."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalendar"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"pristupa vašem kalendaru"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Dozvoliti aplikaciji <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> da pristupi vašem kalendaru?"</string>
@@ -405,8 +408,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Ova aplikacija može dodavati, uklanjati ili mijenjati događaje u kalendaru na vašem telefonu. Aplikacija može slati poruke koje mogu izgledati kao da dolazi od vlasnika kalendara ili promijeniti događaje bez obavještenja vlasnika."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"pristup dodatnim informacijama o lokaciji"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Dozvoljava aplikaciji pristup dodatnim naredbama pružatelja lokacija. Ovim se aplikaciji može dozvoliti da ometa rad GPS-a ili drugih izvora lokacija."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"pristup tačnoj lokaciji samo u prvom planu"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Ova aplikacija može odrediti vašu tačnu lokaciju samo kada je u prvom planu. Ove usluge lokacije moraju biti uključene i dostupne na vašem telefonu da ih aplikacija može koristiti. To može dovesti do povećane potrošnje baterije."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"pristup približnoj lokaciji (utvrđena preko mreže)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Ova aplikacija može odrediti vašu lokaciju na osnovu izvora mreže kao što su predajnici za mobilnu mrežu i WiFi mreže. Ove usluge za određivanje lokacije moraju biti uključene i omogućene na vašem tabletu kako bi ih aplikacija mogla koristiti."</string>
@@ -521,6 +523,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Ikona za otisak prsta"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"upravljanje hardverom za autentifikaciju licem"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Omogućava aplikaciji da koristi metode za dodavanje i brisanje šablona lica za upotrebu."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"upotreba hardvera za autentifikaciju licem"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Omogućava aplikaciji da za autentifikaciju koristi hardver za autentifikaciju licem"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Obrada lica nije uspjela. Pokušajte ponovo."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Lice je presvijetlo. Pokušajte s manje svjetla."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Lice je pretamno. Pojačajte izvor svjetlosti."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Odmaknite senzor od lica."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Približite senzor licu."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Pomjerite senzor prema gore."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Pomjerite senzor prema dolje."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Pomjerite senzor udesno."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Pomjerite senzor ulijevo."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Gledajte u senzor."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Nije pronađeno lice."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Mirno držite lice ispred uređaja."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Hardver za prepoznavanje lica nije dostupan."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Isteklo vrijeme za prepoznavanje. Pokušajte ponovo."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Nije moguće pohraniti lice."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Prepoznavanje lica je otkazano."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Previše pokušaja. Pokušajte ponovo kasnije."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Previše pokušaja. Autentifikacija lica onemogućena."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Pokušajte ponovo."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Nije prijavljeno nijedno lice."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Ovaj uređaj nema senzor za autentifikaciju lica"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Lice <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Ikona lica"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"čitanje postavki za sinhroniziranje"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Omogućava aplikaciji čitanje postavki sinhroniziranja za račun. Naprimjer, ovim se može utvrditi da li je aplikacija People sinhronizirana sa računom."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"aktiviranje/deaktiviranje sinhroniziranja"</string>
@@ -1202,6 +1235,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"WiFi nema pristup internetu"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Dodirnite za opcije"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Promjene postavki vaše pristupne tačke"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Opseg vaše pristupne tačke je promijenjen."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Ovaj uređaj ne podržava vašu postavku za mreže od isključivo 5GHz. Uređaj će koristiti opseg of 5GHz kada je dostupan."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Prebačeno na: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Kada <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu, uređaj koristi mrežu <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Moguća je naplata usluge."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Prebačeno iz mreže <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> u <xliff:g id="NEW_NETWORK">%2$s</xliff:g> mrežu"</string>
@@ -1226,7 +1262,7 @@
<string name="accept" msgid="1645267259272829559">"Prihvati"</string>
<string name="decline" msgid="2112225451706137894">"Odbijte"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Pozivnica poslana"</string>
- <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Poziv za povezivanje"</string>
+ <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Pozivnica za povezivanje"</string>
<string name="wifi_p2p_from_message" msgid="570389174731951769">"Pošiljalac:"</string>
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Prima:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Unesite potrebni PIN:"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 99b4715..ee1673b 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Ubicació"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"accedir a la ubicació del dispositiu"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Vols permetre que <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> accedeixi a la ubicació del dispositiu?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"L\'aplicació només tindrà accés a la ubicació quan l\'estiguis utilitzant."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Vols permetre que <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> accedeixi sempre a la ubicació del dispositiu?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"L\'aplicació tindrà accés sempre a la ubicació, fins i tot quan no l\'estiguis utilitzant."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Calendari"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"accedir al calendari"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Vols permetre que <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> accedeixi al calendari?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Aquesta aplicació pot afegir, suprimir i canviar esdeveniments del calendari al telèfon. També pot enviar missatges que sembli que provenen dels propietaris del calendari o canviar esdeveniments sense notificar-los-ho."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"accedir a ordres del proveïdor d\'ubicació addicionals"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Permet que l\'aplicació accedeixi a ordres addicionals del proveïdor d\'ubicacions; per tant, és possible que l\'aplicació pugui interferir en el funcionament del GPS o d\'altres fonts d\'ubicacions."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"accedeix a la ubicació exacta només en primer pla"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Aquesta aplicació pot obtenir la teva ubicació exacta només quan està en primer pla. Aquests serveis d\'ubicació han d\'estar activats i disponibles al telèfon perquè l\'aplicació els pugui utilitzar, i això pot fer que el consum de bateria augmenti."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"accedir a la ubicació aproximada (basada en la xarxa)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Aquesta aplicació pot obtenir la teva ubicació a partir de fonts de xarxa, com ara torres de telefonia mòbil i xarxes Wi-Fi. Aquests serveis d\'ubicació han d\'estar activats i disponibles a la tauleta perquè l\'aplicació els pugui utilitzar."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Icona d\'empremta digital"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"gestiona el maquinari d\'autenticació facial"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Permet que l\'aplicació afegeixi i suprimeixi plantilles de cares que es puguin fer servir."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"utilitza el maquinari d\'autenticació facial"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Permet que l\'aplicació faci servir maquinari d\'autenticació facial"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Error en processar la cara. Torna-ho a provar."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"La cara brilla massa. Prova amb menys llum."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"La cara és massa fosca. Prova amb més llum."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Allunya el sensor de la cara."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Apropa el sensor a la cara."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Puja el sensor més amunt."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Baixa el sensor més avall."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Mou el sensor cap a la dreta."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Mou el sensor cap a l\'esquerra."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Mira el sensor."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"No s\'ha detectat cap cara."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Mantén la cara quieta davant del dispositiu."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Maquinari de reconeixement facial no disponible."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"S\'ha esgotat el temps d\'espera. Torna-ho a provar."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"La cara no es pot desar."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"S\'ha cancel·lat el reconeixement facial."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Massa intents. Torna-ho a provar més tard."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Massa intents. Autenticació facial desactivada."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Torna-ho a provar."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"No s\'ha registrat cap cara."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Aquest dispositiu no té sensor d\'autenticació facial"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Cara <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Icona facial"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"llegir la configuració de sincronització"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Permet que l\'aplicació llegeixi la configuració de sincronització d\'un compte. Per exemple, això pot determinar que l\'aplicació Persones estigui sincronitzada amb un compte."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"activar o desactivar la sincronització"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"La Wi-Fi no té accés a Internet"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toca per veure les opcions"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Canvis en la configuració del punt d\'accés Wi-Fi"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Ha canviat la teva banda del punt d\'accés Wi-Fi."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Aquest dispositiu no admet utilitzar exclusivament una banda de 5 GHz. El dispositiu utilitzarà una banda de 5 GHz quan estigui disponible."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Actualment en ús: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"El dispositiu utilitza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> en cas que <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tingui accés a Internet. És possible que s\'hi apliquin càrrecs."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Abans es feia servir la xarxa <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>; ara s\'utilitza <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index a57059c..0d67679 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -282,6 +282,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Poloha"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"přístup k poloze tohoto zařízení"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Povolit aplikaci <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> přístup k poloze tohoto zařízení?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Aplikace bude mít přístup k poloze, pouze když ji budete používat."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Povolit aplikaci <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> přístup k poloze tohoto zařízení?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Aplikace bude mít přístup k poloze vždy, i když ji nebudete používat."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalendář"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"přístup ke kalendáři"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Povolit aplikaci <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> přístup ke kalendáři?"</string>
@@ -408,8 +411,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Tato aplikace může přidat, odstranit či změnit události v kalendáři uložené v telefonu. Může také odesílat zprávy, které budou zdánlivě přicházet od vlastníka kalendáře, nebo upravovat události bez vědomí vlastníka."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"přístup k dalším příkazům poskytovatele polohy"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Umožňuje aplikaci přístup k dalším příkazům poskytovatele polohy. To aplikaci umožní zasahovat do fungování systému GPS a dalších zdrojů polohy."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"přístup k přesné poloze jen na popředí"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Tato aplikace může zjistit vaši přesnou polohu, jen když běží na popředí. Aby tyto služby určování polohy mohla aplikace používat, musí být v telefonu dostupné a musí být zapnuté. Tyto služby mohou způsobit rychlejší vybíjení baterie."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"přístup k přibližné poloze (pomocí sítě)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Tato aplikace může zjistit vaši polohu podle zdrojů sítě, jako jsou vysílací věže nebo sítě Wi-Fi. Aby tyto služby určování polohy mohla aplikace používat, musí být v tabletu dostupné a musí být zapnuté."</string>
@@ -524,6 +526,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Ikona otisku prstů"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"správa hardwaru k ověření obličeje"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Umožňuje aplikaci volat metody k přidání a smazání šablon obličeje, které budou použity."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"použití hardwaru k ověření obličeje"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Umožňuje aplikaci provést ověření pomocí hardwaru k ověření obličeje"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Zpracování obličeje se nezdařilo. Zkuste to znovu."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Obličej je moc jasný. Zkuste to v menším světle."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Obličej je moc tmavý. Odkryjte zdroj světla."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Oddalte senzor od obličeje."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Posuňte senzor blíž k obličeji."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Posuňte senzor výš."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Posuňte senzor níž."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Posuňte senzor doprava."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Posuňte senzor doleva."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Podívejte se do senzoru."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Nebyl rozpoznán žádný obličej."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Držte obličej nehybně před zařízením."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Není k dispozici hardware ke snímání obličeje."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Limit ověření obličeje vypršel. Zkuste to znovu."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Obličej nelze uložit."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Operace snímání obličeje byla zrušena."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Příliš mnoho pokusů. Zkuste to později."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Příliš mnoho pokusů. Ověření obličeje je zakázáno."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Zkuste to znovu."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Není zaregistrován žádný obličej."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Toto zařízení nemá snímač ověření obličeje"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Obličej <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Ikona obličeje"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"čtení nastavení synchronizace"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Umožňuje aplikaci číst nastavení synchronizace v účtu. Může například určit, zda je s účtem synchronizována aplikace Lidé."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"vypnutí nebo zapnutí synchronizace"</string>
@@ -1222,6 +1255,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi nemá přístup k internetu"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Klepnutím zobrazíte možnosti"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Změny nastavení hotspotu"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Pásmo hotspotu se změnilo."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Toto zařízení nepodporuje vaše nastavení jen 5GHz pásma. Zařízení použije pásmo 5 GHz, jen když bude dostupné."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Přechod na síť <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Když síť <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nebude mít přístup k internetu, zařízení použije síť <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Mohou být účtovány poplatky."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Přechod ze sítě <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na síť <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 4fabf17..7f4409b6 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Placering"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"få adgang til enhedens placering"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Vil du give <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> adgang til enhedens placering?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Appen har kun adgang til placeringen, når du bruger appen."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Skal <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> altid have adgang til enhedens placering?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Appen har altid adgang til placeringen, også selvom du ikke bruger appen."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalender"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"have adgang til din kalender"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Vil du give <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> adgang til din kalender?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Denne app kan tilføje, fjerne eller ændre kalenderbegivenheder på din telefon. Denne app kan sende meddelelser, der kan se ud, som om de kommer fra kalenderejere, eller ændre begivenheder uden at give ejeren besked."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"få adgang til yderligere kommandoer for placeringsudbyder"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Tillader, at appen kan få adgang til yderligere kommandoer for placeringsudbydere. Dette kan gøre det muligt for appen at forstyrre GPS-funktionen eller andre placeringskilder."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"få kun adgang til nøjagtig placering i forgrunden"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Denne app kan kun få din nøjagtige placering, når den er i forgrunden. Disse placeringstjenester skal være aktiverede og tilgængelige på din telefon, før appen kan bruge dem. Dette kan øge batteriforbruget."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"få adgang til omtrentlig placering (netværksbaseret)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Denne app kan bestemme din placering ved hjælp af netværkskilder, som f.eks. mobilmaster og Wi-Fi-netværk. Disse placeringstjenester skal være aktiverede og tilgængelige på din tablet, før appen kan bruge dem."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Ikon for fingeraftryk"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"administrer hardware til ansigtsgenkendelse"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Tillader, at appen kan køre metoder til at tilføje og slette ansigtsskabeloner."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"brug hardware til ansigtsgenkendelse"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Tillader, at appen kan bruge hardware til ansigtsgenkendelse"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Ansigtet kunne ikke behandles. Prøv igen."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Ansigtet er for lyst. Prøv i svagere belysning."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Ansigtet er for mørkt. Ryk nærmere en lyskilde."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Flyt sensoren længere væk fra ansigtet."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Ryk sensoren tættere på ansigtet."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Flyt sensoren højere op."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Flyt sensoren længere ned."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Flyt sensoren til højre."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Flyt sensoren til venstre."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Kig på sensoren."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Der er ikke registreret noget ansigt."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Hold ansigtet stille foran enheden."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Hardwaren til ansigtsregistrering er ikke klar."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Ansigtsgenkendelse fik timeout. Prøv igen."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Ansigtet kan ikke gemmes."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Ansigtshandlingen blev annulleret."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Du har prøvet for mange gange. Prøv igen senere."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"For mange forsøg – Ansigtsgenkendelse deaktiveret."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Prøv igen."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Der er ikke registreret nogen ansigter."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Denne enhed har ingen sensor til ansigtsgenkendelse"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Ansigt <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Ansigt"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"læse indstillinger for synkronisering"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Tillader, at appen kan læse synkroniseringsindstillingerne for en konto. Denne tilladelse kan f.eks. fastslå, om appen Personer er synkroniseret med en konto."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"slå synkronisering til og fra"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi-netværket har ikke internetadgang"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tryk for at se valgmuligheder"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Ændringer af dine indstillinger for hotspot"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Dit hotspotbånd er ændret."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Denne enhed understøtter ikke din præferencer om kun 5 GHz. Denne enhed vil i stedet bruge 5 GHz-båndet, når det er muligt."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Der blev skiftet til <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Enheden benytter <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, når der ikke er internetadgang via <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Der opkræves muligvis betaling."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Der blev skiftet fra <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> til <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 5b1e45f..26c0fab 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Standort"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"auf den Standort deines Geräts zugreifen"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> erlauben, den Gerätestandort abzurufen?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Die App hat nur Zugriff auf den Gerätestandort, wenn du sie verwendest."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> immer erlauben, den Gerätestandort abzurufen?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Die App hat immer Zugriff auf den Gerätestandort, auch wenn du sie gerade nicht verwendest."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalender"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"auf deinen Kalender zugreifen"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> Zugriff auf deinen Kalender erlauben?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Diese App kann Kalendertermine auf deinem Smartphone hinzufügen, entfernen oder ändern. Diese App kann Nachrichten senden, die scheinbar von Kalendereigentümern stammen, oder Termine ohne Benachrichtigung der Eigentümer ändern."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"Auf zusätzliche Dienstanbieterbefehle für Standort zugreifen"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Ermöglicht der App, auf zusätzliche Standortanbieterbefehle zuzugreifen. Damit könnte die App die Funktionsweise von GPS oder anderen Standortquellen beeinträchtigen."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"Nur bei Ausführung im Vordergrund auf den genauen Standort zugreifen"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Diese App kann deinen genauen Standort nur dann ermitteln, wenn sie im Vordergrund ausgeführt wird. Die App kann diese Standortdienste nur verwenden, wenn sie auf deinem Smartphone aktiviert und verfügbar sind. Hierdurch kann sich der Akkuverbrauch erhöhen."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"Auf den ungefähren Standort zugreifen (netzwerkbasiert)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Diese App kann deinen Standort mithilfe von Netzwerkquellen wie Mobilfunkmasten und WLAN ermitteln. Die App kann diese Standortdienste nur verwenden, wenn sie auf deinem Tablet aktiviert und verfügbar sind."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Fingerabdruck-Symbol"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"Gesichtserkennungshardware verwalten"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Ermöglicht der App, Methoden zum Hinzufügen oder Entfernen von Gesichtsvorlagen anzuwenden."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"Gesichtserkennungshardware verwenden"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Ermöglicht der App, für die Authentifizierung Gesichtserkennungshardware zu verwenden"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Kann Gesicht nicht verarbeiten. Versuch es erneut."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Gesicht zu hell. Bei weniger Licht versuchen."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Gesicht zu dunkel. Bei mehr Licht versuchen."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Sensor weiter weg vom Gesicht halten."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Sensor näher an das Gesicht halten."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Sensor höher halten."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Sensor niedriger halten."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Sensor nach rechts bewegen."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Sensor nach links bewegen."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Blick auf den Sensor richten."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Kein Gesicht erkannt."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Gerät vor das Gesicht halten und nicht bewegen."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Hardware zur Gesichtserkennung nicht verfügbar."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Zeitüberschreitung für Gesicht. Versuch es erneut."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Gesicht kann nicht gespeichert werden."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Gesichtserkennung abgebrochen."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Zu viele Versuche. Versuch es später noch einmal."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Zu viele Versuche. Gesichtserkennung deaktiviert."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Versuch es noch einmal."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Kein Gesicht erfasst."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Dieses Gerät hat keinen Gesichtserkennungssensor"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Gesicht <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Gesichtssymbol"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"Synchronisierungseinstellungen lesen"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Ermöglicht der App, die Synchronisierungseinstellungen eines Kontos zu lesen. Beispielsweise kann damit festgestellt werden, ob Kontakte mit einem Konto synchronisiert werden."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"Synchronisierung aktivieren oder deaktivieren"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"WLAN hat keinen Internetzugriff"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Für Optionen tippen"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Änderungen an deinen Hotspot-Einstellungen"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Dein Hotspot-Band hat sich geändert."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Dieses Gerät unterstützt die ausschließliche Nutzung von 5 GHz nicht. Es greift aber immer auf das 5-GHz-Band zurück, wenn dieses verfügbar ist."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Zu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> gewechselt"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Auf dem Gerät werden <xliff:g id="NEW_NETWORK">%1$s</xliff:g> genutzt, wenn über <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> kein Internet verfügbar ist. Eventuell fallen Gebühren an."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Von \"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>\" zu \"<xliff:g id="NEW_NETWORK">%2$s</xliff:g>\" gewechselt"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 43f7ec3..6fa6723 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Τοποθεσία"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"έχει πρόσβαση στην τοποθεσία της συσκευής"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Να επιτρέπεται στην εφαρμογή <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> να έχει πρόσβαση στην τοποθεσία αυτής της συσκευής;"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Η εφαρμογή θα έχει πρόσβαση στην τοποθεσία μόνο κατά τη διάρκεια χρήσης της εφαρμογής."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Να επιτρέπεται πάντα στην εφαρμογή <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> να έχει πρόσβαση στην τοποθεσία αυτής της συσκευής;"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Η εφαρμογή θα έχει πάντα πρόσβαση στην τοποθεσία, ακόμα και όταν δεν χρησιμοποιείτε την εφαρμογή."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Ημερολόγιο"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"έχει πρόσβαση στο ημερολόγιό σας"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Να επιτρέπεται στην εφαρμογή <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> να έχει πρόσβαση στο ημερολόγιό σας;"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Αυτή η εφαρμογή μπορεί να προσθέσει, να καταργήσει ή να αλλάξει συμβάντα ημερολογίου στο τηλέφωνό σας. Αυτή η εφαρμογή μπορεί να στέλνει μηνύματα τα οποία μπορεί να φαίνεται ότι προέρχονται από κατόχους ημερολογίου ή να αλλάζει συμβάντα χωρίς να ειδοποιεί τους κατόχους."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"έχει πρόσβαση σε επιπλέον εντολές παρόχου τοποθεσίας"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Επιτρέπει στην εφαρμογή την πρόσβαση σε επιπλέον εντολές παρόχου τοποθεσίας. Αυτό μπορεί να δώσει τη δυνατότητα στην εφαρμογή να παρέμβει στη λειτουργία του GPS ή άλλων πηγών τοποθεσίας."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"πρόσβαση στην ακριβή τοποθεσία μόνο στο προσκήνιο"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Αυτή η εφαρμογή μπορεί να ανιχνεύσει την ακριβή τοποθεσία σας όταν βρίσκεται στο προσκήνιο. Αυτές οι υπηρεσίες τοποθεσίας θα πρέπει να είναι ενεργοποιημένες και διαθέσιμες στο τηλέφωνό σας, προκειμένου να μπορεί να τις χρησιμοποιήσει η εφαρμογή. Με την ενεργοποίηση αυτής της ρύθμισης, μπορεί να αυξηθεί η κατανάλωση μπαταρίας."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"έχει πρόσβαση στην τοποθεσία κατά προσέγγιση (με βάση το δίκτυο)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Αυτή η εφαρμογή μπορεί να ανιχνεύσει την τοποθεσία σας βάσει πηγών δικτύου, όπως κεραίες κινητής τηλεφωνίας και δίκτυα Wi-Fi. Αυτές οι υπηρεσίες τοποθεσίας θα πρέπει να είναι ενεργοποιημένες και διαθέσιμες στο tablet που χρησιμοποιείτε, προκειμένου να μπορεί να τις χρησιμοποιήσει η εφαρμογή."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Εικονίδιο δακτυλικών αποτυπωμάτων"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"διαχείριση υλικολογισμ. ελέγχου ταυτότ. προσώπου"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Επιτρέπει στην εφαρμογή να επικαλείται μεθόδους προσθήκης/διαγραφής προτύπων για χρήση."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"χρήση υλικολογισμικού ελέγχου ταυτότητας προσώπου"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί υλικολογισμικό για έλεγχο ταυτότητας"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Αδυναμία επεξεργασίας προσώπου. Δοκιμάστε ξανά."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Υψηλή φωτεινότητα. Δοκιμάστε χαμηλότερο φωτισμό."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Πολύ σκοτεινό πρόσωπο. Ξεσκεπάστε την πηγή φωτός."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Μετακινήστε τον αισθητήρα πιο μακριά."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Τοποθετήστε τον αισθητήρα πιο κοντά στο πρόσωπο."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Μετακινήστε τον αισθητήρα ψηλότερα."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Μετακινήστε τον αισθητήρα χαμηλότερα."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Μετακινήστε τον αισθητήρα προς τα δεξιά."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Μετακινήστε τον αισθητήρα προς τα αριστερά."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Κοιτάξτε στον αισθητήρα."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Δεν εντοπίστηκε κάποιο πρόσωπο."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Διατηρήστε το πρόσωπο σταθερό μπροστά στη συσκευή."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Το υλικολογισμικό προσώπου δεν είναι διαθέσιμο."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Λήξη χρονικού ορίου προσώπου. Δοκιμάστε ξανά."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Δεν είναι δυνατή η αποθήκευση του προσώπου."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Η ενέργεια προσώπου ακυρώθηκε."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Πάρα πολλές προσπάθειες. Δοκιμάστε ξανά αργότερα."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Πολλές προσπάθειες. Αποτυχία ελέγ. ταυτ. προσώπου."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Δοκιμάστε ξανά."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Δεν έχει καταχωριστεί κάποιο πρόσωπο."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Η συσκευή δεν διαθέτει αισθητήρα ελέγχου ταυτότητας προσώπου"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Πρόσωπο <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Εικ. προσ."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"διαβάζει τις ρυθμίσεις συγχρονισμού"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Επιτρέπει στην εφαρμογή την ανάγνωση των ρυθμίσεων συγχρονισμού για έναν λογαριασμό. Για παράδειγμα, αυτό μπορεί να καθορίσει εάν η εφαρμογή \"Άτομα\" είναι συγχρονισμένη με έναν λογαριασμό."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ενεργοποιεί/απενεργοποιεί τον συγχρονισμό"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Το Wi-Fi δεν έχει πρόσβαση στο διαδίκτυο"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Πατήστε για να δείτε τις επιλογές"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Αλλαγές στις ρυθμίσεις σημείου πρόσβασης Wi-Fi"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Το εύρος σημείου πρόσβασης Wi-Fi άλλαξε."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Αυτή η συσκευή δεν υποστηρίζει την προτίμησή σας για τη ζώνη 5 GHz μόνο. Αντ\' αυτού, αυτή η συσκευή θα χρησιμοποιεί τη ζώνη 5 GHz όταν είναι διαθέσιμη."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Μετάβαση σε δίκτυο <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Η συσκευή χρησιμοποιεί το δίκτυο <xliff:g id="NEW_NETWORK">%1$s</xliff:g> όταν το δίκτυο <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> δεν έχει πρόσβαση στο διαδίκτυο. Μπορεί να ισχύουν χρεώσεις."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Μετάβαση από το δίκτυο <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> στο δίκτυο <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 0c0fd74..aca8fe5 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Location"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"access this device\'s location"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Allow <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> to access this device\'s location?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"The app will only have access to the location while you’re using the app."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Always allow <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> to access this device’s location?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"The app will always have access to the location, even when you’re not using the app."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Calendar"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"access your calendar"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Allow <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> to access your calendar?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"This app can add, remove or change calendar events on your phone. This app can send messages that may appear to come from calendar owners or change events without notifying their owners."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"access extra location provider commands"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Allows the app to access extra location provider commands. This may allow the app to interfere with the operation of the GPS or other location sources."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"access precise location only in the foreground"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"This app can get your exact location only when it is in the foreground. These location services must be turned on and available on your phone for the app to be able to use them. This may increase battery consumption."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"access approximate location (network-based)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"This app can pick up your location based on network sources such as phone masts and Wi-Fi networks. These location services must be turned on and available on your tablet for the app to be able to use them."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Fingerprint icon"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"manage face authentication hardware"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Allows the app to invoke methods to add and delete facial templates for use."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"use face authentication hardware"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Allows the app to use face authentication hardware for authentication"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Couldn’t process face. Please try again."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Face is too bright. Please try in lower light."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Face is too dark. Please uncover light source."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Please move sensor farther away from face."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Please bring sensor closer to face."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Please move sensor higher."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Please move sensor lower."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Please move sensor to the right."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Please move sensor to the left."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Please look at the sensor."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"No face detected."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Keep face steady in front of device."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Face hardware not available."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Face time out reached. Try again."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Face can’t be stored."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Face operation cancelled."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Too many attempts. Try again later."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Too many attempts. Facial authentication disabled."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Try again."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"No face enrolled."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"This device does not have a face authentication sensor"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Face <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Face icon"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"read sync settings"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Allows the app to read the sync settings for an account. For example, this can determine whether the People app is synced with an account."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"toggle sync on and off"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi has no Internet access"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tap for options"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Changes to your hotspot settings"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Your hotspot band has changed."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"This device doesn’t support your preference for 5 GHz only. Instead, this device will use the 5 GHz band when available."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index c5f059e..f80eae0 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Location"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"access this device\'s location"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Allow <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> to access this device\'s location?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"The app will only have access to the location while you’re using the app."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Always allow <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> to access this device’s location?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"The app will always have access to the location, even when you’re not using the app."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Calendar"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"access your calendar"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Allow <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> to access your calendar?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"This app can add, remove or change calendar events on your phone. This app can send messages that may appear to come from calendar owners or change events without notifying their owners."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"access extra location provider commands"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Allows the app to access extra location provider commands. This may allow the app to interfere with the operation of the GPS or other location sources."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"access precise location only in the foreground"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"This app can get your exact location only when it is in the foreground. These location services must be turned on and available on your phone for the app to be able to use them. This may increase battery consumption."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"access approximate location (network-based)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"This app can pick up your location based on network sources such as phone masts and Wi-Fi networks. These location services must be turned on and available on your tablet for the app to be able to use them."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Fingerprint icon"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"manage face authentication hardware"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Allows the app to invoke methods to add and delete facial templates for use."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"use face authentication hardware"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Allows the app to use face authentication hardware for authentication"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Couldn’t process face. Please try again."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Face is too bright. Please try in lower light."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Face is too dark. Please uncover light source."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Please move sensor farther away from face."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Please bring sensor closer to face."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Please move sensor higher."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Please move sensor lower."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Please move sensor to the right."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Please move sensor to the left."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Please look at the sensor."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"No face detected."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Keep face steady in front of device."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Face hardware not available."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Face time out reached. Try again."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Face can’t be stored."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Face operation cancelled."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Too many attempts. Try again later."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Too many attempts. Facial authentication disabled."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Try again."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"No face enrolled."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"This device does not have a face authentication sensor"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Face <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Face icon"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"read sync settings"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Allows the app to read the sync settings for an account. For example, this can determine whether the People app is synced with an account."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"toggle sync on and off"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi has no Internet access"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tap for options"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Changes to your hotspot settings"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Your hotspot band has changed."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"This device doesn’t support your preference for 5 GHz only. Instead, this device will use the 5 GHz band when available."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 0c0fd74..aca8fe5 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Location"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"access this device\'s location"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Allow <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> to access this device\'s location?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"The app will only have access to the location while you’re using the app."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Always allow <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> to access this device’s location?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"The app will always have access to the location, even when you’re not using the app."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Calendar"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"access your calendar"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Allow <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> to access your calendar?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"This app can add, remove or change calendar events on your phone. This app can send messages that may appear to come from calendar owners or change events without notifying their owners."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"access extra location provider commands"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Allows the app to access extra location provider commands. This may allow the app to interfere with the operation of the GPS or other location sources."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"access precise location only in the foreground"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"This app can get your exact location only when it is in the foreground. These location services must be turned on and available on your phone for the app to be able to use them. This may increase battery consumption."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"access approximate location (network-based)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"This app can pick up your location based on network sources such as phone masts and Wi-Fi networks. These location services must be turned on and available on your tablet for the app to be able to use them."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Fingerprint icon"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"manage face authentication hardware"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Allows the app to invoke methods to add and delete facial templates for use."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"use face authentication hardware"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Allows the app to use face authentication hardware for authentication"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Couldn’t process face. Please try again."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Face is too bright. Please try in lower light."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Face is too dark. Please uncover light source."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Please move sensor farther away from face."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Please bring sensor closer to face."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Please move sensor higher."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Please move sensor lower."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Please move sensor to the right."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Please move sensor to the left."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Please look at the sensor."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"No face detected."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Keep face steady in front of device."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Face hardware not available."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Face time out reached. Try again."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Face can’t be stored."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Face operation cancelled."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Too many attempts. Try again later."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Too many attempts. Facial authentication disabled."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Try again."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"No face enrolled."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"This device does not have a face authentication sensor"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Face <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Face icon"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"read sync settings"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Allows the app to read the sync settings for an account. For example, this can determine whether the People app is synced with an account."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"toggle sync on and off"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi has no Internet access"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tap for options"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Changes to your hotspot settings"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Your hotspot band has changed."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"This device doesn’t support your preference for 5 GHz only. Instead, this device will use the 5 GHz band when available."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 0c0fd74..aca8fe5 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Location"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"access this device\'s location"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Allow <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> to access this device\'s location?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"The app will only have access to the location while you’re using the app."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Always allow <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> to access this device’s location?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"The app will always have access to the location, even when you’re not using the app."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Calendar"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"access your calendar"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Allow <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> to access your calendar?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"This app can add, remove or change calendar events on your phone. This app can send messages that may appear to come from calendar owners or change events without notifying their owners."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"access extra location provider commands"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Allows the app to access extra location provider commands. This may allow the app to interfere with the operation of the GPS or other location sources."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"access precise location only in the foreground"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"This app can get your exact location only when it is in the foreground. These location services must be turned on and available on your phone for the app to be able to use them. This may increase battery consumption."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"access approximate location (network-based)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"This app can pick up your location based on network sources such as phone masts and Wi-Fi networks. These location services must be turned on and available on your tablet for the app to be able to use them."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Fingerprint icon"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"manage face authentication hardware"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Allows the app to invoke methods to add and delete facial templates for use."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"use face authentication hardware"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Allows the app to use face authentication hardware for authentication"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Couldn’t process face. Please try again."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Face is too bright. Please try in lower light."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Face is too dark. Please uncover light source."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Please move sensor farther away from face."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Please bring sensor closer to face."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Please move sensor higher."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Please move sensor lower."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Please move sensor to the right."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Please move sensor to the left."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Please look at the sensor."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"No face detected."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Keep face steady in front of device."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Face hardware not available."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Face time out reached. Try again."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Face can’t be stored."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Face operation cancelled."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Too many attempts. Try again later."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Too many attempts. Facial authentication disabled."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Try again."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"No face enrolled."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"This device does not have a face authentication sensor"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Face <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Face icon"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"read sync settings"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Allows the app to read the sync settings for an account. For example, this can determine whether the People app is synced with an account."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"toggle sync on and off"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi has no Internet access"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tap for options"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Changes to your hotspot settings"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Your hotspot band has changed."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"This device doesn’t support your preference for 5 GHz only. Instead, this device will use the 5 GHz band when available."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 3968012..55c3e9d 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Location"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"access this device\'s location"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Allow <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> to access this device\'s location?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"The app will only have access to the location while you’re using the app."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Always allow <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> to access this device’s location?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"The app will always have access to the location, even when you’re not using the app."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Calendar"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"access your calendar"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Allow <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> to access your calendar?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"This app can add, remove, or change calendar events on your phone. This app can send messages that may appear to come from calendar owners, or change events without notifying their owners."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"access extra location provider commands"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Allows the app to access extra location provider commands. This may allow the app to interfere with the operation of the GPS or other location sources."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"access precise location only in the foreground"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"This app can get your exact location only when it is in the foreground. These location services must be turned on and available on your phone for the app to be able to use them. This may increase battery consumption."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"access approximate location (network-based)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"This app can get your location based on network sources such as cell towers and Wi-Fi networks. These location services must be turned on and available on your tablet for the app to be able to use them."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Fingerprint icon"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"manage face authentication hardware"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Allows the app to invoke methods to add and delete facial templates for use."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"use face authentication hardware"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Allows the app to use face authentication hardware for authentication"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Couldn’t process face. Please try again."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Face is too bright. Please try in lower light."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Face is too dark. Please uncover light source."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Please move sensor farther from face."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Please bring sensor closer to face."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Please move sensor higher."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Please move sensor lower."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Please move sensor to the right."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Please move sensor to the left."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Please look at the sensor."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"No face detected."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Keep face steady infront of device."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Face hardware not available."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Face time out reached. Try again."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Face can’t be stored."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Face operation canceled."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Too many attempts. Try again later."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Too many attempts. Facial authentication disabled."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Try again."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"No face enrolled."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"This device does not have a face authentication sensor"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Face <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Face icon"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"read sync settings"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Allows the app to read the sync settings for an account. For example, this can determine whether the People app is synced with an account."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"toggle sync on and off"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi has no internet access"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tap for options"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Changes to your hotspot settings"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Your hotspot band has changed."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"This device doesn’t support your preference for 5GHz only. Instead, this device will use the 5GHz band when available."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no internet access. Charges may apply."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 75a3f24..aa4978a 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Ubicación"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"acceder a la ubicación de este dispositivo"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"¿Permitir que <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> acceda a la ubicación de este dispositivo?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"La app solo tendrá acceso a la ubicación cuando la uses."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"¿Permitir que <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> acceda a la ubicación?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"La app siempre tendrá acceso a la ubicación, incluso cuando no la uses."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Calendario"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"acceder al calendario"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"¿Permitir que <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> acceda a tu calendario?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Esta app puede agregar, quitar o cambiar eventos del calendario en tu teléfono. Puede enviar mensajes que parecen proceder de propietarios del calendario o cambiar eventos sin notificarlos."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"acceder a comandos adicionales del proveedor del lugar"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Permite que la aplicación acceda a comandos adicionales del proveedor de ubicación. Esto puede permitirle a la aplicación interferir con el funcionamiento del GPS o de otras fuentes de ubicación."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"acceder a la ubicación exacta solo en primer plano"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Esta app puede obtener tu ubicación exacta solo cuando está en primer plano. Los servicios de ubicación deben estar activados y disponibles en el teléfono para que la app pueda usarlos. Es posible que aumente el consumo de batería."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"acceder a la ubicación aproximada (según la red)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Esta app puede obtener tu ubicación a través de fuentes de red, como torres de telefonía móvil y redes Wi-Fi. Estos servicios de ubicación deben estar activados y disponibles en tu tablet para que la app pueda usarlos."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Ícono de huella digital"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"administrar el hardware de autenticación facial"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Permite que la app emplee métodos para agregar y borrar plantillas de rostros para su uso."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"usar el hardware de autenticación facial"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Permite que la app use el hardware de autenticación facial para reconocerte"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Error al procesar el rostro. Vuelve a intentarlo."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"El rostro se ve muy claro. Prueba con menos luz."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"El rostro se ve muy oscuro. Prueba con más luz."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Aleja el sensor del rostro."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Acerca el sensor al rostro."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Coloca el sensor más arriba."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Coloca el sensor más abajo."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Mueve el sensor hacia la derecha."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Mueve el sensor hacia la izquierda."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Mira al sensor."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"No se detectó ningún rostro."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Mantén el rostro fijo enfrente del dispositivo."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Hardware de reconocimiento facial no disponible"</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Se agotó el tiempo. Vuelve a intentarlo."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"No se puede almacenar el rostro."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Se canceló el reconocimiento facial."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Demasiados intentos. Inténtalo de nuevo más tarde."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Demasiados intentos. Autent. facial inhabilitada."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Vuelve a intentarlo."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"No registraste ningún rostro."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Este dispositivo no tiene sensor de autenticación facial"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Rostro <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Ícono cara"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"leer la configuración de sincronización"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Este permiso permite que la aplicación consulte la configuración de sincronización de una cuenta. Esto permite, por ejemplo, determinar si la aplicación Personas está sincronizada con una cuenta."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"activar y desactivar la sincronización"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"La red Wi-Fi no tiene acceso a Internet"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Presiona para ver opciones"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Cambios en la configuración de tu hotspot"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Cambió la banda de tu hotspot."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Si bien este dispositivo no admite la opción para conectarse exclusivamente a bandas de 5 GHz, las usará cuando estén disponibles."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Se cambió a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"El dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cuando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tiene acceso a Internet. Es posible que se apliquen cargos."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Se cambió de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 41c9251..95f4412 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Ubicación"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"acceder a la ubicación de este dispositivo"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"¿Quieres permitir que <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> acceda a la ubicación de este dispositivo?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"La aplicación solo podrá acceder a la ubicación cuando estés usando la aplicación."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"¿Permites que <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> acceda a ubic. del disp.?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"La aplicación siempre podrá acceder a la ubicación, aunque no estés usando la aplicación."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Calendario"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"acceder a tu calendario"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"¿Quieres permitir que <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> acceda a tu calendario?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Esta aplicación puede añadir, quitar o cambiar eventos de calendario almacenados en tu teléfono. También puede enviar mensajes que parecen provenir del propietario del calendario o cambiar eventos sin notificárselo a su propietario."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"acceder a comandos de proveedor de ubicación adicional"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Permite que la aplicación acceda a otros comandos del proveedor de ubicación. De esta forma, la aplicación podrá interferir en el funcionamiento del GPS o de otras fuentes de ubicación."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"acceder a la ubicación exacta solo en primer plano"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Esta aplicación solo puede obtener tu ubicación exacta cuando está en primer plano. Estos servicios de ubicación deben estar activados y disponibles en tu teléfono para que la aplicación pueda utilizarlos. Es posible que aumente el consumo de batería."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"acceder a tu ubicación aproximada (basada en red)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Esta aplicación puede obtener tu ubicación a partir de fuentes de red como las antenas de telefonía móvil y las redes Wi-Fi. Estos servicios de ubicación deben estar activados y disponibles en tu tablet para que la aplicación pueda usarlos."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Icono de huella digital"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"gestionar el hardware de autenticación facial"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Permite a la app invocar métodos para añadir y eliminar plantillas de caras y utilizarlas."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"usar el hardware de autenticación facial"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Permite que la aplicación utilice el hardware de autenticación facial para autenticarte"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"No se ha reconocido la cara. Vuelve a intentarlo."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"La cara se ve muy clara. Inténtalo con menos luz."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"La cara se ve muy oscura. Inténtalo con más luz."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Aleja más la cara del sensor."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Acerca más la cara al sensor."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Coloca el sensor más arriba."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Coloca el sensor más abajo."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Mueve el sensor hacia la derecha."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Mueve el sensor hacia la izquierda."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Mira al sensor."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"No se ha detectado ninguna cara."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Mantén la cara fija enfrente del dispositivo."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Hardware de reconocimiento facial no disponible."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Has sobrepasado el tiempo. Inténtalo de nuevo."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"No se pueden registrar más caras."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Se ha cancelado el reconocimiento facial."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Demasiados intentos. Inténtalo de nuevo más tarde."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Demasiados intentos. Autent. facial inhabilitada."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Inténtalo de nuevo."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"No has registrado ninguna cara."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Este dispositivo no tiene sensor de autenticación facial"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Cara <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Icono cara"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"leer la configuración de sincronización"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Permite que la aplicación consulte la configuración de sincronización de una cuenta. La aplicación puede utilizar este permiso, por ejemplo, para determinar si la aplicación Contactos está sincronizada con una cuenta."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"activar y desactivar la sincronización"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"La red Wi-Fi no tiene acceso a Internet"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toca para ver opciones"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Cambios en los ajustes de tu punto de acceso"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"La banda de tu punto de acceso ha cambiado."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Este dispositivo no admite la opción de conectarse exclusivamente a bandas de 5 GHz, pero las usará cuando estén disponibles."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Se ha cambiado a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"El dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cuando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tiene acceso a Internet. Es posible que se apliquen cargos."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Se ha cambiado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index e966040..6155011 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Asukoht"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"pääseda juurde selle seadme asukohale"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Kas lubada rakendusele <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> juurdepääs selle seadme asukohale?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Rakendusel on juurdepääs asukohale vaid siis, kui rakendust kasutate."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Kas lubada rak. <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> alati juurdepääs seadme asukohale?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Rakendusel on alati juurdepääs asukohale isegi siis, kui te rakendust ei kasuta."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalender"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"juurdepääs kalendrile"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Kas lubada rakendusele <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> juurdepääs teie kalendrile?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"See rakendus võib teie telefoni kalendrisündmusi lisada, neid eemaldada või muuta. See rakendus võib saata sõnumeid, mis näivad pärinevat kalendri omanikelt, või muuta sündmusi ilma omanikke teavitamata."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"juurdepääs asukohapakkuja lisakäskudele"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Võimaldab rakendusel juurde pääseda asukohapakkuja erikäskudele. See võib lubada rakendusel mõjutada GPS-i või muude asukohaallikate tööd."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"juurdepääs täpsele asukohale ainult esiplaanil"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"See rakendus hangib teie täpse asukoha ainult siis, kui see töötab esiplaanil. Need asukohateenused peavad olema sisse lülitatud ja teie telefonis saadaval, et rakendus saaks neid kasutada. See võib suurendada akutoite tarbimist."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"juurdepääs ligikaudsele asukohale (võrgupõhine)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"See rakendus näeb võrguallikate (nt mobiilimastid ja WiFi-võrgud) abil teie asukohta. Need asukohateenused peavad olema sisse lülitatud ja teie tahvelarvutis saadaval, et rakendus neid kasutada saaks."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Sõrmejälje ikoon"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"hallata näo autentimise riistvara"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Lubab rakendusel tühistada meetodid kasutatavate näomallide lisamiseks ja kustutamiseks."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"kasutada näo autentimise riistvara"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Võimaldab rakendusel autentimiseks kasutada näo autentimise riistvara"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Nägu ei õnnestunud töödelda. Proovige uuesti."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Nägu on liiga hele. Proovige hämaramas."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Nägu on liiga tume. Kasutage valgusallikat."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Liigutage andur näost kaugemale."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Liigutage andur näole lähemale."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Liigutage andurit kõrgemale."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Liigutage andurit madalamale."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Liigutage andurit paremale."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Liigutage andurit vasakule."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Vaadake andurit."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Nägu ei tuvastatud."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Hoidke nägu seadme ees paigal."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Näotuvastuse riistvara pole saadaval."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Näotuvastuse taimeri ajalõpp. Proovige uuesti."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Nägu ei saa salvestada."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Näotuvastuse toiming tühistati."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Liiga palju katseid. Proovige hiljem uuesti."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Liiga palju katseid. Näotuvastus on keelatud."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Proovige uuesti."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Nägu pole registreeritud."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Sellel seadmel pole näotuvastuse andurit"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Nägu <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Näoikoon"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"loe sünkroonimisseadeid"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Võimaldab rakendusel lugeda konto sünkroonimisseadeid. Näiteks võib see määrata, kas rakendus Inimesed on kontoga sünkroonitud."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"lülitage sünkroonimine sisse ja välja"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"WiFi-võrgul pole juurdepääsu Internetile"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Puudutage valikute nägemiseks"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Muudatused teie leviala seadetes"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Teie leviala riba on muutunud."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"See seade ei toeta teie eelistatud ainult 5 GHz riba. Seade kasutab 5 GHz riba ainult siis, kui see on saadaval."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Lülitati võrgule <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Seade kasutab võrku <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, kui võrgul <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> puudub juurdepääs Internetile. Rakenduda võivad tasud."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Lülitati võrgult <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> võrgule <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 43d1483..bdf5e6a 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Kokapena"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"atzitu gailuaren kokapena"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> aplikazioari gailuaren kokapena atzitzea baimendu nahi diozu?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Aplikazioa erabiltzen ari zarenean soilik atzituko du aplikazioak kokapena."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> aplikazioari gailuaren kokapena beti atzitzea baimendu?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Aplikazioak beti atzituko du kokapena, baita aplikazioa erabiltzen ari ez bazara ere."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Egutegia"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"atzitu egutegia"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> aplikazioari egutegia atzitzea baimendu nahi diozu?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Telefonoko gertaerak gehitzeko, kentzeko edo aldatzeko aukera du aplikazioak. Gainera, egutegien jabeenak diruditen mezuak bidal ditzake, eta gertaerak alda ditzake jabeei beraiei jakinarazi gabe."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"atzitu kokapen-hornitzaileen komando gehigarriak"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Kokapen-hornitzailearen agindu gehigarriak atzitzea baimentzen die aplikazioei. Horrela, agian aplikazioek GPSaren edo bestelako kokapenaren iturburuen funtzionamenduan eragina izan dezakete."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"lortu kokapen zehatza aurreko planoan bakarrik"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Aplikazioak zure kokapen zehatza lor dezake aurreko planoan funtzionatzen duenean bakarrik. Kokapen-zerbitzu horiek aktibatuta eta erabilgarri izan behar dituzu telefonoan, aplikazioak erabil ditzan. Baliteke bateria gehiago erabiltzea."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"atzitu gutxi gorabeherako kokapena (sarean oinarrituta)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Aplikazioak zure kokapenaren berri izan dezake sareen iturburuak (adibidez, telefonia mugikorreko dorreak eta Wi-Fi sareak) erabilita. Kokapen-zerbitzu horiek aktibatuta eta erabilgarri izan behar dituzu tabletan, aplikazioak erabil ditzan."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Hatz-markaren ikonoa"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"kudeatu aurpegi bidez autentifikatzeko hardwarea"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Aurpegi-txantiloiak gehitu eta ezabatzeko metodoei dei egitea baimentzen dio aplikazioari."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"erabili aurpegi bidez autentifikatzeko hardwarea"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Aurpegi bidez autentifikatzeko hardwarea erabiltzea baimentzen dio aplikazioari"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Ezin izan da prozesatu aurpegia. Saiatu berriro."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Aurpegiak distira gehiegi du. Jarri argi gutxiago."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Aurpegia ilunegi dago. Estalgabetu argi-iturburua."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Urrundu sentsorea aurpegitik."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Hurbildu sentsorea aurpegira."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Eraman sentsorea gora."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Eraman sentsorea behera."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Eraman sentsorea eskuinera."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Eraman sentsorea ezkerrera."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Begiratu sentsorea."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Ez dugu hauteman aurpegirik."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Egon geldi, aurpegia gailuaren aurrean jarrita."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Aurpegiaren hardwarea ez dago erabilgarri."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Gainditu da aurpegiak prozesatzeko denbora-muga. Saiatu berriro."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Ezin da gorde aurpegia."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Utzi da aurpegiaren bidezko eragiketa."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Saiakera gehiegi egin dituzu. Saiatu berriro geroago."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Saiakera gehiegi egin dituzu. Desgaitu da aurpegiaren autentifikazioa."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Saiatu berriro."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Ez dago aurpegirik erregistratuta."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Gailu honek ez du aurpegia autentifikatzeko sentsorerik"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"<xliff:g id="FACEID">%d</xliff:g> aurpegia"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Aurpegiaren ikonoa"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"irakurri sinkronizazio-ezarpenak"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Kontu baten sinkronizazio-ezarpenak irakurtzeko baimena ematen die aplikazioei. Adibidez, Jendea aplikazioa konturen batekin sinkronizatuta dagoen zehatz dezake."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"aktibatu eta desaktibatu sinkronizazioa"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Ezin da konektatu Internetera Wi-Fi bidez"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Sakatu aukerak ikusteko"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Aldaketak sare publiko eramangarriaren ezarpenetan"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Aldatu da sare eramangarriaren banda."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Gailuak ez du onartzen 5 GHz-ko banda soilik erabiltzeko hobespena. Horren ordez, erabilgarri dagoen bakoitzean erabiliko da 5 GHz-ko banda."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> erabiltzen ari zara orain"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> Internetera konektatzeko gauza ez denean, <xliff:g id="NEW_NETWORK">%1$s</xliff:g> erabiltzen du gailuak. Agian kostuak ordaindu beharko dituzu."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> erabiltzen ari zinen, baina <xliff:g id="NEW_NETWORK">%2$s</xliff:g> erabiltzen ari zara orain"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 32be39a..7c32d33 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"مکان"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"دسترسی به موقعیت مکانی این دستگاه"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"به <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> اجازه داده شود به مکان این دستگاه دسترسی پیدا کند؟"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"این برنامه تنها هنگامی که از آن استفاده میکنید، به مکان دسترسی خواهد داشت."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"همیشه به <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> اجازه داده شود به مکان این دستگاه دسترسی داشته باشد؟"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"این برنامه همیشه به مکان دسترسی خواهد داشت، حتی اگر از آن استفاده نکنید."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"تقویم"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"دسترسی به تقویم شما"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"به <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> اجازه داده شود به تقویم شما دسترسی پیدا کند؟"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"این برنامه میتواند در تلفن شما رویدادهای تقویم اضافه کند، آنها را حذف کند یا تغییر دهد. این برنامه میتواند پیامهایی ارسال کند که گویی از طرف مالکان تقویم هستند یا رویدادها را بدون اطلاع مالکان تغییر دهد."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"دسترسی به فرمانهای بیشتر ارائه دهنده مکان"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"به برنامه اجازه میدهد به دستورات ارائهدهنده مکان تکمیلی دسترسی داشته باشد. این کار ممکن است به برنامه امکان دهد با کارکرد GPS یا منابع دیگر مکان تداخل داشته باشد."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"دسترسی به مکان دقیق فقط در پیشزمینه"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"این برنامه فقط زمانی میتواند موقعیت مکانی دقیق شما را دریافت کند که در پیشزمینه باشد. برای اینکه برنامه بتواند از خدمات مکان استفاده کند، این خدمات باید در تلفنتان روشن و دردسترس باشد. ممکن است با این کار مصرف باتری افزایش یابد."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"دسترسی به مکان تقریبی (مبتنی بر شبکه)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"این برنامه میتواند براساس منابع شبکه مانند دکلهای مخابراتی و شبکههای Wi-Fi، مکان شما را تشخیص دهد. این خدمات مکان باید روشن و در رایانه لوحی شما دردسترس باشند تا برنامه بتواند از آنها استفاده کند."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"نماد اثر انگشت"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"مدیریت سختافزار احراز هویت با چهره"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"به برنامه امکان میدهد روشهایی را برای افزودن و حذف الگوهای چهره جهت استفاده فرابخواند."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"استفاده از سختافزار احراز هویت با چهره"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"به برنامه امکان میدهد از سختافزار احراز هویت با چهره برای احراز هویت استفاده کند"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"چهره پردازش نشد. لطفاً دوباره امتحان کنید."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"چهره خیلی روشن است. لطفاً در نور کمتری دوباره امتحان کنید."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"چهره خیلی تاریک است. لطفاً منبع نور را نپوشانید."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"لطفاً حسگر را از صورتتان دورتر کنید."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"لطفاً حسگر را به صورتتان نزدیکتر کنید."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"لطفاً حسگر را بالاتر ببرید."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"لطفاً حسگر را پایینتر بیاورید."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"لطفاً حسگر را به راست حرکت دهید."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"لطفاً حسگر را به چپ حرکت دهید."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"لطفاً به حسگر نگاه کنید."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"چهرهای شناسایی نشد."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"صورتتان را ثابت در جلوی دستگاه نگه دارید."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"سختافزار چهره دردسترس نیست."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"مهلت زمانی شناسایی چهره تمام شد. دوباره امتحان کنید"</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"نمیتوان چهره را ذخیره کرد."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"عملیات شناسایی چهره لغو شد."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"تعداد زیادی تلاش ناموفق. بعداً دوباره امتحان کنید."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"چندین تلاش ناموفق. احراز هویت با چهره غیرفعال شد."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"دوباره امتحان کنید."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"هیچ چهرهای ثبت نشده است."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"این دستگاه حسگر احراز هویت با چهره ندارد."</string>
+ <string name="face_name_template" msgid="7004562145809595384">"چهره <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"نماد چهره"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"خواندن تنظیمات همگامسازی"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"به برنامه اجازه میدهد تنظیمات را برای یک حساب بخواند. بهعنوان مثال، این ویژگی میتواند تعیین کند آیا حساب «افراد» شما با یک حساب همگامسازی شده است."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"تغییر وضعیت همگامسازی بین فعال و غیرفعال"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi به اینترنت دسترسی ندارد"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"برای گزینهها ضربه بزنید"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"تغییرات در تنظیمات نقطه اتصال"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"نوار نقطه اتصال شما تغییر کرد."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"این دستگاه از اولویت فقط ۵ گیگاهرتز شما پشتیبانی نمیکند. هرزمان نوار ۵ گیگاهرتزی دردسترس باشد این دستگاه از آن استفاده خواهد کرد."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"به <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> تغییر کرد"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"وقتی <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> به اینترنت دسترسی نداشته باشد، دستگاه از <xliff:g id="NEW_NETWORK">%1$s</xliff:g> استفاده میکند. ممکن است هزینههایی اعمال شود."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"از <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> به <xliff:g id="NEW_NETWORK">%2$s</xliff:g> تغییر کرد"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 30509b0..e7a56c4 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Sijainti"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"käyttää laitteen sijaintia"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Saako <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> tämän laitteen sijainnin käyttöoikeuden?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Sovellus saa sijainnin käyttöoikeuden vain jos käytät sovellusta."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Saako <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> tämän laitteen sijainnin käyttöoikeuden?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Sovellus saa sijainnin käyttöoikeuden aina, vaikka et käyttäisi sovellusta."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalenteri"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"käyttää kalenteria"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Saako <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> kalenterisi käyttöoikeuden?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Tämä sovellus voi lisätä, poistaa tai muuttaa puhelimen kalenteritapahtumia. Sovellus voi lähettää viestejä, jotka näyttävät tulevan kalenterin omistajilta, tai muuttaa kalenteritapahtumia ilmoittamatta omistajille."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"käytä lisää sijainnintarjoajakomentoja"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Antaa sovelluksen käyttää ylimääräisiä sijaintipalvelukomentoja. Sovellus saattaa tällöin häiritä GPS:n tai muiden sijaintilähteiden toimintaa."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"käyttää tarkkaa sijaintia vain etualalla"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Tämä sovellus saa tarkat sijaintitietosi käyttöönsä vain etualalla. Näiden sijaintipalveluiden tulee olla käytössä ja käytettävissä puhelimellasi, jotta sovellus voi käyttää niitä. Tämä voi lisätä akun kulutusta."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"käyttää likimääräistä sijaintia (verkkopohjainen)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Tämä sovellus voi määrittää sijaintisi matkapuhelinverkon tukiasemien, Wi-Fi-verkkojen ja muiden verkkolähteiden perusteella. Näiden sijaintipalveluiden tulee olla käytössä ja käytettävissä tabletillasi, jotta sovellus voi käyttää niitä."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Sormenjälkikuvake"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"hallinnoida kasvojentodennuslaitteistoa"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Sallii sovelluksen käyttää menetelmiä, joilla voidaan lisätä tai poistaa kasvomalleja."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"käyttää kasvojentodennuslaitteistoa"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Sallii sovelluksen käyttää todennuslaitteistoa todennukseen"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Kasvojen käsittely epäonnistui. Yritä uudelleen."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Kasvokuva on liian kirkas. Kokeile hämärää valoa."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Kasvokuva on liian tumma. Älä peitä valonlähdettä."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Siirrä anturia kauemmas kasvoista."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Tuo anturi lähemmäs kasvoja."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Siirrä anturia korkeammalle."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Siirrä anturia alemmas."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Siirrä anturia oikealle."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Siirrä anturia vasemmalle."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Katso anturia."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Kasvoja ei havaittu."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Pidä kasvot paikoillaan laitteen edessä."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Kasvolaitteisto ei ole käytettävissä."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Kasvotoiminto aikakatkaistiin. Yritä uudelleen."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Kasvoja ei voi tallentaa."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Kasvotoiminto peruutettu"</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Liian monta yritystä. Yritä myöhemmin uudelleen."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Liikaa yrityksiä. Kasvojentodennus ei käytössä."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Yritä uudelleen."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Kasvoja ei ole otettu käyttöön."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Laitteessa ei ole kasvojentodennusanturia."</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Kasvot <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Kasvokuvake"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"lue synkronointiasetuksia"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Antaa sovelluksen lukea tilien synkronointiasetuksia. Sovellus voi esimerkiksi määrittää, onko Henkilöt-sovellus synkronoitu tilin kanssa."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ota synkronointi käyttöön tai poista se käytöstä"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi ei ole yhteydessä internetiin"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Näytä vaihtoehdot napauttamalla."</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Hotspot-asetustesi muutokset"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Hotspot-taajuutesi on muuttunut."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Tämä laite ei tue asetustasi (vain 5 GHz). Sen sijaan laite käyttää 5 GHz:n taajuutta sen ollessa käytettävissä."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> otettiin käyttöön"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> otetaan käyttöön, kun <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ei voi muodostaa yhteyttä internetiin. Veloitukset ovat mahdollisia."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> poistettiin käytöstä ja <xliff:g id="NEW_NETWORK">%2$s</xliff:g> otettiin käyttöön."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 2ae1b62..f0d7776 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -272,22 +272,25 @@
<string name="managed_profile_label" msgid="8947929265267690522">"Passer au profil professionnel"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacts"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"accéder à vos contacts"</string>
- <string name="permgrouprequest_contacts" msgid="6032805601881764300">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à accéder à vos contacts?"</string>
+ <string name="permgrouprequest_contacts" msgid="6032805601881764300">"Autoriser <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> à accéder à vos contacts?"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Localisation"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"accéder à la position de cet appareil"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Autoriser <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> à accéder à la position de cet appareil?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"L\'application aura uniquement accès à la position lorsque vous l\'utilisez."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Toujours autoriser <xliff:g id="APP_NAME">%1$s</xliff:g> à accéder à la position de cet appareil?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"L\'application aura toujours accès à la position, même lorsque vous ne l\'utilisez pas."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Agenda"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"accéder à votre agenda"</string>
- <string name="permgrouprequest_calendar" msgid="289900767793189421">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à accéder à votre agenda?"</string>
+ <string name="permgrouprequest_calendar" msgid="289900767793189421">"Autoriser <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> à accéder à votre agenda?"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"Messagerie texte"</string>
<string name="permgroupdesc_sms" msgid="4656988620100940350">"envoyer et afficher des messages texte"</string>
- <string name="permgrouprequest_sms" msgid="7168124215838204719">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à envoyer et à afficher des messages texte?"</string>
+ <string name="permgrouprequest_sms" msgid="7168124215838204719">"Autoriser <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> à envoyer et à afficher des messages texte?"</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"Stockage"</string>
<string name="permgroupdesc_storage" msgid="637758554581589203">"accéder aux photos, aux contenus multimédias et aux fichiers sur votre appareil"</string>
<string name="permgrouprequest_storage" msgid="7885942926944299560">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à accéder aux photos, aux médias et aux fichiers de votre appareil?"</string>
<string name="permgrouplab_microphone" msgid="171539900250043464">"Microphone"</string>
<string name="permgroupdesc_microphone" msgid="4988812113943554584">"enregistrer des fichiers audio"</string>
- <string name="permgrouprequest_microphone" msgid="9167492350681916038">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à enregistrer de l\'audio?"</string>
+ <string name="permgrouprequest_microphone" msgid="9167492350681916038">"Autoriser <b><xliff:g id="APP_NAME">%1$s</xliff:g></b&gt à enregistrer l\'audio?"</string>
<string name="permgrouplab_camera" msgid="4820372495894586615">"Appareil photo"</string>
<string name="permgroupdesc_camera" msgid="3250611594678347720">"prendre des photos et filmer des vidéos"</string>
<string name="permgrouprequest_camera" msgid="1299833592069671756">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à prendre des photos et à filmer des vidéos?"</string>
@@ -296,7 +299,7 @@
<string name="permgrouprequest_calllog" msgid="8487355309583773267">"Autoriser <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> à accéder à vos journaux d\'appels?"</string>
<string name="permgrouplab_phone" msgid="5229115638567440675">"Téléphone"</string>
<string name="permgroupdesc_phone" msgid="6234224354060641055">"faire et gérer des appels téléphoniques"</string>
- <string name="permgrouprequest_phone" msgid="9166979577750581037">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à faire et à gérer les appels téléphoniques?"</string>
+ <string name="permgrouprequest_phone" msgid="9166979577750581037">"Autoriser <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> à faire et à gérer les appels téléphoniques?"</string>
<string name="permgrouplab_sensors" msgid="416037179223226722">"Capteurs corporels"</string>
<string name="permgroupdesc_sensors" msgid="7147968539346634043">"accéder aux données des capteurs sur vos signes vitaux"</string>
<string name="permgrouprequest_sensors" msgid="6349806962814556786">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à accéder aux données des capteurs pour vos signes vitaux?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Cette application peut ajouter, supprimer et modifier des événements d\'agenda sur votre téléphone. Elle peut aussi envoyer des messages qui pourraient sembler venir des propriétaires d\'agenda en question ou modifier des événements sans avertir leur propriétaire."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"accéder aux commandes de fournisseur de position géographique supplémentaires"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Permet à l\'application d\'accéder à des commandes de localisation supplémentaires offertes par le fournisseur. Elle est ainsi susceptible d\'interférer avec le bon fonctionnement du GPS ou de toute autre source de localisation."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"accéder à votre position précise seulement en avant-plan"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Cette application peut obtenir votre position exacte seulement lorsqu\'elle fonctionne en avant-plan. Ces services de localisation doivent être activés et accessibles sur votre téléviseur pour que l\'application puisse les utiliser. Cela peut entraîner une utilisation accrue de la pile."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"accéder à votre position approximative (réseau)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Cette application peut déterminer votre position à l\'aide de différentes sources de localisation sur le réseau, comme les tours de téléphonie cellulaire et les réseaux Wi-Fi. Ces services de localisation doivent être activés et accessibles sur votre tablette pour que l\'application puisse les utiliser."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Icône d\'empreinte digitale"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"gérer le matériel d\'authentification de visage"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Permet à l\'appli d\'employer des méthodes d\'aj. et de suppr. de modèles de reconn. visage."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"utiliser le matériel d\'authentification de visage"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Permet à l\'appli d\'utiliser du matériel de reconnaissance du visage pour l\'authentification"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Impossible de traiter le visage. Réessayez."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Visage trop lumineux. Essayez avec moins de lumière."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Visage trop sombre. Essayez avec plus de lumière."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Veuillez éloigner le capteur du visage."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Veuillez rapprocher le capteur du visage."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Veuillez déplacer le capteur plus haut."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Veuillez déplacer le capteur plus bas."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Veuillez déplacer le capteur vers la droite."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Veuillez déplacer le capteur vers la gauche."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Veuillez regarder le capteur."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Aucun visage détecté."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Gardez le visage stable devant l\'appareil."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Matériel de reconnaissance du visage indisponible."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Temps de reconn. visage écoulé. Veuillez réessayer."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Impossible de stocker le visage."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Opération de reconnaissance du visage annulée."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Trop de tentatives. Veuillez réessayer plus tard."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Trop de tentatives. Capt. reconn. visage désactivé."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Réessayez."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Aucun visage inscrit."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Cet appareil ne possède pas de capteur de reconn. du visage"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Visage <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Icône visage"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"lire les paramètres de synchronisation"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Permet à l\'application d\'accéder aux paramètres de synchronisation d\'un compte. Par exemple, cette autorisation peut permettre de déterminer si l\'application Contacts est synchronisée avec un compte ou non."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"activer ou désactiver la synchronisation"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Le réseau Wi-Fi ne dispose d\'aucun accès à Internet"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Touchez pour afficher les options"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Modifications apportées à vos paramètres de point d\'accès"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"La bande de votre point d\'accès a changé."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Cet appareil ne prend pas en charge votre préférence pour le 5 GHz seulement. Au lieu de cela, cet appareil utilisera la bande de 5 GHz lorsqu\'elle sera disponible."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Passé au réseau <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"L\'appareil utilise <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quand <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> n\'a pas d\'accès à Internet. Des frais peuvent s\'appliquer."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Passé du réseau <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> au <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 4af3faa..a402285 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Localisation"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"accéder à la position de l\'appareil"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Permettre à <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> d\'accéder à la position de cet appareil ?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"L\'application n\'a accès à la position de l\'appareil que lorsqu\'elle est en cours d\'utilisation."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Toujours autoriser <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> à accéder à la position de l\'appareil ?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"L\'application a toujours accès à la position de l\'appareil, même lorsqu\'elle n\'est pas en cours d\'utilisation."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Agenda"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"accéder à votre agenda"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Permettre à <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> d\'accéder à votre agenda ?"</string>
@@ -293,7 +296,7 @@
<string name="permgrouprequest_camera" msgid="1299833592069671756">"Permettre à <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> de prendre des photos et de filmer des vidéos ?"</string>
<string name="permgrouplab_calllog" msgid="8798646184930388160">"Journaux d\'appels"</string>
<string name="permgroupdesc_calllog" msgid="3006237336748283775">"Lire et écrire les journaux d\'appels du téléphone"</string>
- <string name="permgrouprequest_calllog" msgid="8487355309583773267">"Autoriser <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> à accéder aux journaux d\'appels de votre téléphone ?"</string>
+ <string name="permgrouprequest_calllog" msgid="8487355309583773267">"Permettre à <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> d\'accéder aux journaux d\'appels de votre téléphone ?"</string>
<string name="permgrouplab_phone" msgid="5229115638567440675">"Téléphone"</string>
<string name="permgroupdesc_phone" msgid="6234224354060641055">"effectuer et gérer des appels téléphoniques"</string>
<string name="permgrouprequest_phone" msgid="9166979577750581037">"Permettre à <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> de passer et gérer des appels téléphoniques ?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Cette application peut ajouter, supprimer ou modifier les événements d\'agenda enregistrés sur votre téléphone. Elle peut en outre envoyer des messages qui semblent provenir du propriétaire de l\'agenda, ou modifier des événements sans en informer leur propriétaire."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"Accès aux commandes de fournisseur de position géographique supplémentaires"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Permet à l\'application d\'accéder à des commandes de localisation supplémentaires offertes par le fournisseur. Elle est ainsi susceptible d\'interférer avec le bon fonctionnement du GPS ou de toute autre source de localisation."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"accéder à la position exacte au premier plan uniquement"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Cette application peut obtenir votre position exacte uniquement lorsqu\'elle s\'exécute au premier plan. Ces services de localisation doivent être activés et disponibles sur votre téléphone pour que l\'application puisse les utiliser. Ceci peut réduire l\'autonomie de la batterie."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"accéder à votre position approximative (selon le réseau)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Cette application peut obtenir votre position via des sources de réseau telles que les antennes-relais et les réseaux Wi-Fi. Ces services de localisation doivent être activés et disponibles sur votre tablette pour que l\'application puisse les utiliser."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Icône d\'empreinte digitale"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"gérer le matériel d\'authentification faciale"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Autorise l\'appli à invoquer des méthodes pour ajouter et supprimer des modèles de visages."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"utiliser le matériel d\'authentification faciale"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Autorise l\'appli à utiliser le matériel d\'authentification faciale pour l\'authentification"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Impossible reconnaître visage. Veuillez réessayer."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Visage trop éclairé. Veuillez réduire la lumière."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Visage trop sombre. Veuillez accroître la lumière."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Veuillez éloigner le capteur de votre visage."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Veuillez rapprocher le capteur de votre visage."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Veuillez déplacer le capteur vers le haut."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Veuillez déplacer le capteur vers le bas."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Veuillez déplacer le capteur vers la droite."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Veuillez déplacer le capteur vers la gauche."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Veuillez regarder le capteur."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Aucun visage détecté."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Maintenez votre visage stable devant l\'appareil."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Matériel de reconnaissance faciale indisponible."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Délai de détection du visage expiré. Réessayez."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Impossible de stocker les informations du visage."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Opération de reconnaissance faciale annulée."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Trop de tentatives. Réessayez plus tard."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Trop d\'essais. Authentification faciale désactivée."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Réessayez."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Aucun visage enregistré."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Aucun capteur d\'authentification faciale sur cet appareil"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Visage <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Icône visage"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"lire les paramètres de synchronisation"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Permet à l\'application d\'accéder aux paramètres de synchronisation d\'un compte. Par exemple, cette autorisation peut permettre de déterminer si l\'application Contacts est synchronisée avec un compte ou non."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"activer/désactiver la synchronisation"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Impossible de se connecter à Internet via le réseau Wi-Fi"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Appuyez ici pour afficher des options."</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Modifications apportées à vos paramètres de point d\'accès"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Votre bande de point d\'accès a été modifiée."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Cet appareil n\'est pas compatible avec votre préférence d\'utilisation de la bande 5 GHz uniquement. Il utilisera la bande 5 GHz lorsqu\'elle sera disponible."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Nouveau réseau : <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"L\'appareil utilise <xliff:g id="NEW_NETWORK">%1$s</xliff:g> lorsque <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> n\'a pas de connexion Internet. Des frais peuvent s\'appliquer."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Ancien réseau : <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>. Nouveau réseau : <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index c59d928..6424135 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Localización"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"acceder á localización deste dispositivo"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Queres permitir que a aplicación <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> acceda á localización deste dispositivo?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"A aplicación só terá acceso á localización mentres a esteas utilizando."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Queres permitir que <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> acceda á localización?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"A aplicación sempre terá acceso á localización, aínda que non a esteas utilizando."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Calendario"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"acceder ao teu calendario"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Queres permitir que a aplicación <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> acceda ao teu calendario?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Esta aplicación pode engadir, quitar ou cambiar eventos do calendario almacenados no teu teléfono. Tamén pode enviar mensaxes que parezan dos propietarios do calendario e cambiar eventos sen comunicárllelo aos propietarios."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"acceder a comandos adicionais do provedor de localización"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Permite á aplicación acceder a comandos adicionais de fornecedor de localizacións. É posible que isto provoque que a aplicación interfira co funcionamento do GPS ou doutras fontes da localización."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"acceder á localización exacta só en primeiro plano"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Esta aplicación pode obter a túa localización exacta só cando se atope en primeiro plano. É necesario activar estes servizos de localización e deben estar dispoñibles no teléfono para que a aplicación poida utilizalos. Ademais, poden supoñer un aumento do consumo de batería."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"acceder á localización aproximada (baseada na rede)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Esta aplicación pode obter a túa localización a partir de fontes de rede como torres de telecomunicacións e redes wifi. Para que a aplicación poida utilizar os servizos de localización, deben estar activados e dispoñibles na túa tableta."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Icona de impresión dixital"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"xestionar hardware de autenticación facial"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Permite que a aplicación invoque métodos para engadir e eliminar modelos faciais de uso."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"usar hardware de autenticación facial"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Permite que a aplicación utilice hardware facial para a autenticación"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Non se puido procesar a cara. Téntao de novo."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"A cara brilla moito. Proba con menos luz."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"A cara está moi escura. Proba con máis luz."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Afasta o sensor da cara."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Achega o sensor á cara."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Sube máis o sensor."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Baixa o sensor."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Move o sensor cara á dereita."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Move o sensor cara á esquerda."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Mira ao sensor."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Non se detectou ningunha cara."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Mantén a cara fixa diante do dispositivo."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"O hardware facial non está dispoñible."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Esgotouse o tempo de espera. Téntao de novo."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Non se puido almacenar a cara."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Cancelouse a operación relacionada coa cara"</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Demasiados intentos. Téntao de novo máis tarde."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Demasiados intentos. Autenticación desactivada."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Téntao de novo."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Non se rexistrou ningunha cara."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Este dispositivo non ten un sensor de autenticación facial"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Cara <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Icona cara"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"ler a configuración de sincronización"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Permite á aplicación ler a configuración de sincronización dunha conta. Por exemplo, esta acción pode determinar se a aplicación Contactos se sincroniza cunha conta."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"activar e desactivar a sincronización"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"A wifi non ten acceso a Internet"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toca para ver opcións."</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Cambios na configuración da zona wifi"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Modificouse a banda da zona wifi."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Este dispositivo non admite a opción de conectarse só a bandas de 5 GHz, pero usaraas se están dispoñibles."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Cambiouse a: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"O dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> non ten acceso a Internet. Pódense aplicar cargos."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Cambiouse de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 6599fd3..a473243 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"સ્થાન"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"આ ઉપકરણના સ્થાનને ઍક્સેસ કરવાની"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ને આ ઉપકરણના સ્થાનને ઍક્સેસ કરવાની મંજૂરી આપીએ?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"માત્ર જ્યારે તમે ઍપનો ઉપયોગ કરી રહ્યાં હોય ત્યારે જ ઍપ સ્થાનને ઍક્સેસ કરી શકશે."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ને હંમેશાં આ ઉપકરણના સ્થાનને ઍક્સેસ કરવાની મંજૂરી આપીએ?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"તમે ઍપનો ઉપયોગ કરી રહ્યાં ન હોય, તો પણ ઍપ હંમેશાં સ્થાનને ઍક્સેસ કરી શકશે."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"કૅલેન્ડર"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"તમારા કેલેન્ડરને ઍક્સેસ કરવાની"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ને તમારા કૅલેન્ડરને ઍક્સેસ કરવાની મંજૂરી આપીએ?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"આ ઍપ્લિકેશન, તમારા ફોન પર કૅલેન્ડર ઇવેન્ટ્સ ઉમેરી, દૂર કરી અથવા બદલી શકે છે. આ ઍપ્લિકેશન, કૅલેન્ડર માલિકો તરફથી આવતાં હોય તેવા લાગતાં સંદેશા મોકલી શકે છે અથવા તેમના માલિકોને સૂચિત કર્યા વિના ઇવેન્ટ્સ બદલી શકે છે."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"વધારાના સ્થાન પ્રદાતા આદેશોને ઍક્સેસ કરો"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"એપ્લિકેશનને વધારાના સ્થાન પ્રદાતા આદેશોને ઍક્સેસ કરવાની મંજૂરી આપે છે. આ એપ્લિકેશનને GPS અથવા અન્ય સ્થાન સ્રોતોના ઓપરેશનમાં દખલ કરવાની મંજૂરી આપી શકે છે."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"ફૉરગ્રાઉન્ડમાં ફક્ત ચોક્કસ સ્થાન ઍક્સેસ કરો"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"આ ઍપ ફક્ત બૅકગ્રાઉન્ડમાં હોય ત્યારે જ તમારું ચોક્કસ સ્થાન મેળવી શકે છે. ઍપ આ સ્થાન સેવાઓનો ઉપયોગ કરી શકે તે માટે તમારા ફોન પર આ સેવાઓ ઉપલબ્ધ અને ચાલુ હોવી આવશ્યક છે. આ બૅટરી વપરાશ વધારી શકે છે."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"અંદાજિત સ્થાન ઍક્સેસ કરો (નેટવર્ક-આધારિત)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"આ ઍપ્લિકેશન, સેલ ટાવર્સ અને વાઇ-ફાઇ નેટવર્ક્સ જેવા નેટવર્ક સ્રોતોના આધારે તમારું સ્થાન મેળવી શકે છે. ઍપ્લિકેશન દ્વારા આ સ્થાન સેવાઓનો ઉપયોગ કરવામાં સમર્થ થવા માટે તમારા ટેબ્લેટ પર આ ઉપલબ્ધ અને ચાલુ હોવી આવશ્યક છે."</string>
@@ -518,6 +520,64 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"ફિંગરપ્રિન્ટ આયકન"</string>
+ <!-- no translation found for permlab_manageFace (2137540986007309781) -->
+ <skip />
+ <!-- no translation found for permdesc_manageFace (8919637120670185330) -->
+ <skip />
+ <!-- no translation found for permlab_useFaceAuthentication (8996134460546804535) -->
+ <skip />
+ <!-- no translation found for permdesc_useFaceAuthentication (5011118722951833089) -->
+ <skip />
+ <!-- no translation found for face_acquired_insufficient (5901287247766106330) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_bright (610606792381297174) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_dark (7229162716976778371) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_close (1980310037427755293) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_far (4494571381828850007) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_high (228411096134808372) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_low (4539774649296349109) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_right (1650292067226118760) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_left (2712489669456176505) -->
+ <skip />
+ <!-- no translation found for face_acquired_poor_gaze (8344973502980415859) -->
+ <skip />
+ <!-- no translation found for face_acquired_not_detected (5707782294589511391) -->
+ <skip />
+ <!-- no translation found for face_acquired_not_steady (3722829465011040042) -->
+ <skip />
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <!-- no translation found for face_error_hw_not_available (6255891785768984615) -->
+ <skip />
+ <!-- no translation found for face_error_timeout (4014326147867150054) -->
+ <skip />
+ <!-- no translation found for face_error_no_space (8224993703466381314) -->
+ <skip />
+ <!-- no translation found for face_error_canceled (283945501061931023) -->
+ <skip />
+ <!-- no translation found for face_error_lockout (3407426963155388504) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_permanent (8198354656746088890) -->
+ <skip />
+ <!-- no translation found for face_error_unable_to_process (238761109287767270) -->
+ <skip />
+ <!-- no translation found for face_error_not_enrolled (9166792142679691323) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (4737289254517095671) -->
+ <skip />
+ <!-- no translation found for face_name_template (7004562145809595384) -->
+ <skip />
+ <string-array name="face_error_vendor">
+ </string-array>
+ <!-- no translation found for face_icon_content_description (4024817159806482191) -->
+ <skip />
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"સમન્વયન સેટિંગ્સ વાંચો"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"ઍપ્લિકેશનને એકાઉન્ટ માટે સમન્વયન સેટિંગ્સને વાંચવાની મંજૂરી આપે છે. ઉદાહરણ તરીકે, આ એકાઉન્ટ સાથે લોકો ઍપ્લિકેશન સમન્વયિત થઈ છે કે કેમ તે નિર્ધારિત કરી શકે છે."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"સમન્વયન ચાલુ અને બંધ ટોગલ કરો"</string>
@@ -1178,6 +1238,12 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"વાઇ-ફાઇને કોઈ ઇન્ટરનેટ ઍક્સેસ નથી"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"વિકલ્પો માટે ટૅપ કરો"</string>
+ <!-- no translation found for wifi_softap_config_change (8475911871165857607) -->
+ <skip />
+ <!-- no translation found for wifi_softap_config_change_summary (7601233252456548891) -->
+ <skip />
+ <!-- no translation found for wifi_softap_config_change_detailed (8022936822860678033) -->
+ <skip />
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> પર સ્વિચ કર્યું"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"જ્યારે <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> પાસે કોઈ ઇન્ટરનેટ ઍક્સેસ ન હોય ત્યારે ઉપકરણ <xliff:g id="NEW_NETWORK">%1$s</xliff:g>નો ઉપયોગ કરે છે. શુલ્ક લાગુ થઈ શકે છે."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> પરથી <xliff:g id="NEW_NETWORK">%2$s</xliff:g> પર સ્વિચ કર્યું"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index d6924ee..e00ade1 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -275,7 +275,10 @@
<string name="permgrouprequest_contacts" msgid="6032805601881764300">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> को अपने संपर्क देखने की अनुमति देना चाहते हैं?"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"जगह"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"इस डिवाइस की जगह तक पहुंचने दें"</string>
- <string name="permgrouprequest_location" msgid="3788275734953323491">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> को इस डिवाइस की जगह की जानकारी देखने की अनुमति देना चाहते हैं?"</string>
+ <string name="permgrouprequest_location" msgid="3788275734953323491">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> को इस डिवाइस की \'जगह की जानकारी\' ऐक्सेस करने की अनुमति देना चाहते हैं?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"ऐप्लिकेशन, डिवाइस की \'जगह की जानकारी\' सिर्फ़ तभी देख पाएगा जब आप इसका इस्तेमाल कर रहे हों."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> को हमेशा डिवाइस की \'जगह की जानकारी\' एक्सेस करने दें?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"ऐप्लिकेशन के पास हमेशा डिवाइस की \'जगह की जानकारी\' देखने की मंज़ूरी होगी, तब भी जब आप इसका इस्तेमाल न कर रहे हों."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"कैलेंडर"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"अपने कैलेंडर को ऐक्सेस करने"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> को अपना कैलेंडर देखने की अनुमति देना चाहते हैं?"</string>
@@ -402,18 +405,14 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"यह ऐप्लिकेशन आपके फ़ोन पर मौजूद कैलेंडर इवेंट जोड़, निकाल या बदल सकता है. यह ऐप्लिकेशन ऐसे संदेश भेज सकता है जो कैलेंडर स्वामियों से आए हुए लग सकते हैं या यह स्वामियों को सूचित किए बिना इवेंट में बदलाव कर सकता है."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"कुछ और जगह बताने वाले आदेशों तक पहुंच"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"ऐप को कुछ और जगह की जानकारी देने वाले आदेशों की पहुंच पाने देता है. इससे ऐप जीपीएस या जगह की जानकारी देने वाले दूसरे स्रोतों के काम में रोक-टोक कर सकता है."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
- <!-- no translation found for permdesc_accessFineLocation (3520508381065331098) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"ऐप्लिकेशन \'जगह की सटीक जानकारी\' सिर्फ़ सामने खुली होने पर एक्सेस करे"</string>
+ <string name="permdesc_accessFineLocation" msgid="3520508381065331098">"यह ऐप्लिकेशन सिर्फ़ तब आपकी \'जगह की सटीक जानकारी\' का इस्तेमाल कर सकता है जब यह स्क्रीन पर दिखाई दे रहा हो. यह ज़रूरी है कि \'जगह की जानकारी\' वाली ये सेवाएं आपके फ़ोन में मौजूद हों और चालू की गई हों ताकि ऐप्लिकेशन उनका इस्तेमाल कर पाए. ऐसा करने से ज़्यादा बैटरी खर्च हो सकती है."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"अनुमानित जगह की पहुंच दें (नेटवर्क-आधारित)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"यह ऐप सेल टावर और वाई-फ़ाई नेटवर्क जैसे नेटवर्क के स्रोतों के आधार पर आपकी जगह का पता कर सकता है. ये जगह की जानकारी आपके टैबलेट पर चालू और मौजूद होनी चाहिए ताकि ऐप उनका इस्तेमाल कर सके."</string>
<string name="permdesc_accessCoarseLocation" product="tv" msgid="1884022719818788511">"यह ऐप सेल टावर और वाई-फ़ाई नेटवर्क जैसे नेटवर्क के स्रोतों के आधार पर आपकी जगह का पता कर सकता है. ये जगह की जानकारी आपके टीवी पर चालू और मौजूद होनी चाहिए ताकि ऐप उनका इस्तेमाल कर सके."</string>
<string name="permdesc_accessCoarseLocation" product="default" msgid="7788009094906196995">"यह ऐप सेल टावर और वाई-फ़ाई नेटवर्क जैसे नेटवर्क के स्रोतों के आधार पर आपकी जगह का पता कर सकता है. ये जगह की जानकारी आपके फ़ोन पर चालू और मौजूद होनी चाहिए ताकि ऐप उनका इस्तेमाल कर सके."</string>
- <!-- no translation found for permlab_accessBackgroundLocation (5742466381902568536) -->
- <skip />
- <!-- no translation found for permdesc_accessBackgroundLocation (6371533283380774135) -->
- <skip />
+ <string name="permlab_accessBackgroundLocation" msgid="5742466381902568536">"बैकग्राउंड में होने पर \'जगह की सटीक जानकारी\' एक्सेस करें"</string>
+ <string name="permdesc_accessBackgroundLocation" msgid="6371533283380774135">"यह ऐप्लिकेशन बैकग्राउंड में चलते हुए, किसी भी समय आपकी \'जगह की सटीक जानकारी\' का इस्तेमाल कर सकता है. यह ज़रूरी है कि \'जगह की जानकारी\' वाली ये सेवाएं आपके फ़ोन में मौजूद हों और चालू की गई हों ताकि ऐप्लिकेशन उनका इस्तेमाल कर पाए. ऐसा करने से ज़्यादा बैटरी खर्च हो सकती है."</string>
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"अपनी ऑडियो सेटिंग बदलें"</string>
<string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"ऐप्स को वैश्विक ऑडियो सेटिंग, जैसे वॉल्यूम और कौन-सा स्पीकर आउटपुट के लिए उपयोग किया गया, संशोधित करने देता है."</string>
<string name="permlab_recordAudio" msgid="3876049771427466323">"ऑडियो रिकॉर्ड करने"</string>
@@ -521,6 +520,64 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"फ़िंगरप्रिंट आइकॉन"</string>
+ <!-- no translation found for permlab_manageFace (2137540986007309781) -->
+ <skip />
+ <!-- no translation found for permdesc_manageFace (8919637120670185330) -->
+ <skip />
+ <!-- no translation found for permlab_useFaceAuthentication (8996134460546804535) -->
+ <skip />
+ <!-- no translation found for permdesc_useFaceAuthentication (5011118722951833089) -->
+ <skip />
+ <!-- no translation found for face_acquired_insufficient (5901287247766106330) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_bright (610606792381297174) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_dark (7229162716976778371) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_close (1980310037427755293) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_far (4494571381828850007) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_high (228411096134808372) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_low (4539774649296349109) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_right (1650292067226118760) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_left (2712489669456176505) -->
+ <skip />
+ <!-- no translation found for face_acquired_poor_gaze (8344973502980415859) -->
+ <skip />
+ <!-- no translation found for face_acquired_not_detected (5707782294589511391) -->
+ <skip />
+ <!-- no translation found for face_acquired_not_steady (3722829465011040042) -->
+ <skip />
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <!-- no translation found for face_error_hw_not_available (6255891785768984615) -->
+ <skip />
+ <!-- no translation found for face_error_timeout (4014326147867150054) -->
+ <skip />
+ <!-- no translation found for face_error_no_space (8224993703466381314) -->
+ <skip />
+ <!-- no translation found for face_error_canceled (283945501061931023) -->
+ <skip />
+ <!-- no translation found for face_error_lockout (3407426963155388504) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_permanent (8198354656746088890) -->
+ <skip />
+ <!-- no translation found for face_error_unable_to_process (238761109287767270) -->
+ <skip />
+ <!-- no translation found for face_error_not_enrolled (9166792142679691323) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (4737289254517095671) -->
+ <skip />
+ <!-- no translation found for face_name_template (7004562145809595384) -->
+ <skip />
+ <string-array name="face_error_vendor">
+ </string-array>
+ <!-- no translation found for face_icon_content_description (4024817159806482191) -->
+ <skip />
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"समन्वयन सेटिंग पढ़ें"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"ऐप्स को किसी खाते की समन्वयन सेटिंग पढ़ने देता है. उदाहरण के लिए, इससे यह निर्धारित किया जा सकता है कि लोग ऐप्स किसी खाते के साथ समन्वयित है या नहीं."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"समन्वयन बंद या चालू टॉगल करें"</string>
@@ -1181,6 +1238,12 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"वाई-फ़ाई के लिए इंटरनेट नहीं मिल रहा है"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"विकल्पों के लिए टैप करें"</string>
+ <!-- no translation found for wifi_softap_config_change (8475911871165857607) -->
+ <skip />
+ <!-- no translation found for wifi_softap_config_change_summary (7601233252456548891) -->
+ <skip />
+ <!-- no translation found for wifi_softap_config_change_detailed (8022936822860678033) -->
+ <skip />
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> पर ले जाया गया"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> में इंटरनेट की सुविधा नहीं होने पर डिवाइस <xliff:g id="NEW_NETWORK">%1$s</xliff:g> का इस्तेमाल करता है. इसके लिए शुल्क लिया जा सकता है."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> से <xliff:g id="NEW_NETWORK">%2$s</xliff:g> पर ले जाया गया"</string>
@@ -1679,7 +1742,7 @@
<item quantity="other"><xliff:g id="COUNT">%d</xliff:g> सेकंड में पुन: प्रयास करें</item>
</plurals>
<string name="restr_pin_try_later" msgid="973144472490532377">"बाद में फिर से प्रयास करें"</string>
- <string name="immersive_cling_title" msgid="8394201622932303336">"पूरे स्क्रीन पर देखें"</string>
+ <string name="immersive_cling_title" msgid="8394201622932303336">"आप पूरे स्क्रीन पर देख रहे हैं"</string>
<string name="immersive_cling_description" msgid="3482371193207536040">"बाहर निकलने के लिए, ऊपर से नीचे स्वाइप करें."</string>
<string name="immersive_cling_positive" msgid="5016839404568297683">"ठीक है"</string>
<string name="done_label" msgid="2093726099505892398">"हो गया"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 13dc029..2b742ae 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -279,6 +279,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Lokacija"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"pristupiti lokaciji ovog uređaja"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Želite li dopustiti aplikaciji <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> da pristupa lokaciji ovog uređaja?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Aplikacija će imati pristup lokaciji samo dok upotrebljavate aplikaciju."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Želite li dopustiti aplikaciji <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> da pristupa lokaciji ovog uređaja?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Aplikacija će uvijek imati pristup lokaciji, čak i dok ne upotrebljavate aplikaciju."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalendar"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"pristupati kalendaru"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Želite li dopustiti aplikaciji <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> da pristupa vašem kalendaru?"</string>
@@ -405,8 +408,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Aplikacija može dodavati, uklanjati ili mijenjati kalendarske događaje na telefonu. Može slati poruke koje izgledaju kao da ih je poslao vlasnik kalendara ili mijenjati događaje bez znanja vlasnika."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"pristup dodatnim naredbama davatelja lokacije"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Omogućuje aplikaciji pristup dodatnim naredbama davatelja usluga lokacije. To može omogućiti aplikaciji ometanje rada GPS-a ili drugih izvora lokacije."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"pristupiti preciznoj lokaciji samo u prednjem planu"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Aplikacija može dobiti vašu točnu lokaciju samo kada je u prednjem planu. Te usluge lokacije moraju biti uključene i dostupne na telefonu da bi ih aplikacija mogla upotrebljavati. To može pojačati potrošnju baterije."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"pristupati približnoj lokaciji (na temelju mreža)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Aplikacija može dohvatiti vašu lokaciju putem mrežnih izvora poput baznih stanica i Wi-Fi mreža. Te usluge lokacije moraju biti uključene i dostupne na tabletu da bi ih aplikacija mogla upotrebljavati."</string>
@@ -521,6 +523,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Ikona otiska prsta"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"upravljati hardverom za autentifikaciju lica"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Aplikaciji omogućuje pozivanje načina za dodavanje i brisanje predložaka lica za upotrebu."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"upotrebljavati hardver za autentifikaciju lica"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Aplikaciji omogućuje upotrebu hardvera za autentifikaciju lica radi autentifikacije"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Obrada lica nije uspjela. Pokušajte ponovo."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Lice je presvijetlo. Smanjite osvjetljenje."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Lice je pretamno. Otkrijte izvor svjetlosti."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Odmaknite senzor od lica."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Približite senzor licu."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Podignite senzor."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Spustite senzor."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Pomaknite senzor udesno."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Pomaknite senzor ulijevo."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Gledajte senzor."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Lice nije otkriveno."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Držite lice mirno ispred uređaja."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Hardver za lice nije dostupan."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Isteklo je vrijeme čekanja za lice. Pokušajte opet"</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Nije moguće pohraniti lice."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Otkazana je radnja s licem."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Previše pokušaja. Pokušajte ponovo kasnije."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Previše pokušaja. Autentifikacija lica onemogućena"</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Pokušajte ponovo."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Nije registrirano nijedno lice."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Ovaj uređaj nema senzor za autentifikaciju lica"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Lice <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Ikona lica"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"čitanje postavki sinkronizacije"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Aplikaciji omogućuje čitanje postavki sinkronizacije za račun. Time se, primjerice, može utvrditi je li aplikacija Osobe sinkronizirana s računom."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"uključivanje/isključivanje sinkronizacije"</string>
@@ -1200,6 +1233,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi nema pristup internetu"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Dodirnite za opcije"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Promjene postavki vaše žarišne točke"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Promijenila se frekvencija vaše žarišne točke."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Ovaj uređaj ne podržava vašu postavku za upotrebu samo 5 GHz. Upotrebljavat će frekvenciju od 5 GHz kada je dostupna."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Prelazak na drugu mrežu: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Kada <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu, na uređaju se upotrebljava <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Moguća je naplata naknade."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Mreža je promijenjena: <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> > <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 443663a..7fb0cbb 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Helyadatok"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"hozzáférés az eszköz földrajzi helyéhez"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Engedélyezi a(z) <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> számára, hogy hozzáférjen az eszköz helyadataihoz?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Az alkalmazás csak akkor férhet hozzá a helyadatokhoz, amikor használja az alkalmazást."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Engedélyezi, hogy a(z) <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> hozzáférjen a helyadatokhoz?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Az alkalmazás bármikor hozzáférhet majd a helyadatokhoz, akkor is, amikor nem használja az alkalmazást."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Naptár"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"hozzáférés a naptárhoz"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Engedélyezi a(z) <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> számára, hogy hozzáférjen a naptárhoz?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Az alkalmazás hozzáadhatja, eltávolíthatja vagy módosíthatja a telefonon található naptáreseményeket. Az alkalmazás olyan üzeneteket küldhet, amelyekről úgy tűnhet, hogy a naptár tulajdonosaitól származnak, illetve a tulajdonosok értesítése nélkül módosíthat eseményeket."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"további helyszolgáltatói parancsok elérése"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Lehetővé teszi az alkalmazás számára további helyszolgáltatói parancsok elérését. Ezáltal az alkalmazás beavatkozhat a GPS vagy más helyforrások működésébe."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"pontos helyadatokhoz való hozzáférés csak előtérben"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Ez az alkalmazás csak akkor férhet hozzá az eszköz pontos helyadataihoz, amikor az előtérben fut. A helyszolgáltatásoknak bekapcsolt és hozzáférhető állapotban kell lenniük a telefonon ahhoz, hogy az alkalmazás használhassa őket. Ez növelheti az akkumulátorhasználatot."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"hozzáférés a hozzávetőleges (hálózatalapú) helyadatokhoz"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Az alkalmazás hozzáférhet hálózati forrásokon (például az adótornyokon és a Wi-Fi-hálózatokon) alapuló helyadataihoz. A helyszolgáltatásoknak bekapcsolt és elérhető állapotban kell lenniük a táblagépen ahhoz, hogy az alkalmazás használhassa őket."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Ujjlenyomat ikon"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"arcfelismerő hardver kezelése"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Engedélyezi, hogy az alkalmazás arcsablon-hozzáadási és -törlési metódusokat hívjon."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"arcfelismerő hardver használata"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Engedélyezi, hogy az alkalmazás hitelesítésre használja az arcfelismerő hardvert"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Nem sikerült feldolgozni az arcot. Próbálja újra."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Az arc túl világos. Kevesebb fény szükséges."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Az arc túl sötét. Több fény szükséges."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Tartsa az érzékelőt távolabb az arctól."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Tartsa az érzékelőt közelebb az archoz."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Emelje magasabbra az érzékelőt."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Engedje lejjebb az érzékelőt."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Mozdítsa el jobbra az érzékelőt."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Mozdítsa el balra az érzékelőt."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Nézzen az érzékelőbe."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Nem észlelhető arc."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Tartsa az eszközt egyenesen az arc előtt."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Az arcfelismerő hardver nem áll rendelkezésre."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Időtúllépés az arcbeolvasásnál. Próbálja újra."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Az arc nem tárolható."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Az arccal kapcsolatos művelet törölve."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Túl sok próbálkozás. Próbálja újra később."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Túl sok próbálkozás. Arcfelismerés letiltva."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Próbálkozzon újra."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Nincs regisztrált arc."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Ez az eszköz nem rendelkezik arcfelismerő érzékelővel"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"<xliff:g id="FACEID">%d</xliff:g> arc"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Arcikon"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"szinkronizálási beállítások olvasása"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Lehetővé teszi az alkalmazás számára egy fiók szinkronizálási beállításainak beolvasását. Például ellenőrizheti, hogy a Személyek alkalmazás szinkronizálva van-e egy fiókkal."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"szinkronizálás be-és kikapcsolása"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"A Wi-Fi-hálózaton nincs internetkapcsolat"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Koppintson a beállítások megjelenítéséhez"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"A hotspot beállításainak módosítása"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"A hotspot sávja megváltozott."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Ez az eszköz nem támogatja a csak 5 GHz-es sávra vonatkozó beállítást. Az eszköz akkor használ 5 GHz-es sávot, ha a sáv rendelkezésre áll."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Átváltva erre: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> használata, ha nincs internet-hozzáférés <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>-kapcsolaton keresztül. A szolgáltató díjat számíthat fel."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Átváltva <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>-hálózatról erre: <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index ba4b73e..56e00c7 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -219,11 +219,11 @@
<string name="global_action_emergency" msgid="7112311161137421166">"Շտապ կանչ"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Վրիպակի զեկույց"</string>
<string name="global_action_logout" msgid="935179188218826050">"Ավարտել աշխատաշրջանը"</string>
- <string name="global_action_screenshot" msgid="8329831278085426283">"Էկրանի պատկեր"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Սքրինշոթ"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Հաղորդել սխալի մասին"</string>
<string name="bugreport_message" msgid="398447048750350456">"Սա տեղեկություններ կհավաքագրի ձեր սարքի առկա կարգավիճակի մասին և կուղարկի այն էլեկտրոնային նամակով: Որոշակի ժամանակ կպահանջվի վրիպակի մասին զեկուցելու պահից սկսած մինչ ուղարկելը: Խնդրում ենք փոքր-ինչ համբերատար լինել:"</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Ինտերակտիվ զեկույց"</string>
- <string name="bugreport_option_interactive_summary" msgid="229299488536107968">"Հիմնականում օգտագործեք այս տարբերակը: Այն ձեզ թույլ է տալիս հետևել զեկույցի ստեղծման գործընթացին, խնդրի մասին լրացուցիչ տեղեկություններ մուտքագրել և էկրանի պատկերներ կորզել: Կարող է բաց թողնել քիչ օգտագործվող որոշ բաժինները, որոնց ստեղծումը երկար է տևում:"</string>
+ <string name="bugreport_option_interactive_summary" msgid="229299488536107968">"Հիմնականում օգտագործեք այս տարբերակը: Այն ձեզ թույլ է տալիս հետևել զեկույցի ստեղծման գործընթացին, խնդրի մասին լրացուցիչ տեղեկություններ մուտքագրել և սքրինշոթներ ստեղծել: Կարող է բաց թողնել քիչ օգտագործվող որոշ բաժիններ, որոնց ստեղծումը երկար է տևում:"</string>
<string name="bugreport_option_full_title" msgid="6354382025840076439">"Ամբողջական զեկույց"</string>
<string name="bugreport_option_full_summary" msgid="7210859858969115745">"Օգտագործեք այս տարբերակը համակարգի միջամտությունը նվազեցնելու համար՝ երբ սարքը չի արձագանքում կամ շատ դանդաղ է աշխատում, կամ երբ ձեզ հարկավոր են զեկույցի բոլոր բաժինները: Թույլ չի տալիս լրացուցիչ տվյալներ մուտքագրել կամ էկրանի լրացուցիչ պատկերներ ստանալ:"</string>
<plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Տեղորոշում"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"տեղորոշել այս սարքը"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Թույլ տա՞լ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> հավելվածին օգտագործել այս սարքի տեղադրության տվյալները:"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Տեղադրության տվյալները հավելվածին հասանելի կլինեն միայն, երբ այն օգտագործելիս լինեք:"</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Միշտ թույլ տա՞լ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b>-ին օգտագործել սարքի տեղադրությունը:"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Տեղադրության տվյալները հավելվածին միշտ հասանելի կլինեն, նույնիսկ եթե այն չեք օգտագործում:"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Օրացույց"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"օգտագործել օրացույցը"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Թույլ տա՞լ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> հավելվածին օգտագործել ձեր օրացույցը:"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Այս հավելվածը կարող է ավելացնել, հեռացնել կամ փոխել օրացույցի միջոցառումները ձեր հեռախոսում: Այս հավելվածը կարող է ուղարկել հաղորդագրություններ օրացույցի սեփականատերերի անունից կամ փոխել միջոցառումները առանց դրանց սեփականատերերին ծանուցելու:"</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"օգտագործել տեղադրություն տրամադրող հավելվյալ հրամաններ"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Ծրագրին թույլ է տալիս օգտագործել տեղադրության մասին տվյալների աղբյուրների կառավարման լրացուցիչ հրահանգներ: Սա կարող է ծրագրին թույլ տալ միջամտել GPS-ի կամ տեղադրության մասին տվյալների այլ աղբյուրների գործառույթներին:"</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"Տեղադրության ճշգրիտ տվյալների հասանելիություն միայն ֆոնային ռեժիմում"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Հավելվածը կարող է ստանալ ձեր տեղադրության տվյալները ֆոնային ռեժիմում։ Այս տեղորոշման ծառայությունները պետք է միացված և հասանելի լինեն ձեր հեռախոսում, որպեսզի հավելվածը կարողանա օգտագործել դրանք: Սա կարող է արագացնել մարտկոցի լիցքի սպառումը:"</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"օգտագործել մոտավոր տեղադրությունը (ցանցային)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Այս հավելվածը կարող է ստանալ ձեր տեղադրության տվյալները ցանցային տարբեր աղբյուրներից, օրինակ՝ բջջային աշտարակներից և Wi-Fi ցանցերից: Այս տեղորոշման ծառայությունները պետք է միացված և հասանելի լինեն ձեր պլանշետում, որպեսզի հավելվածը կարողանա օգտագործել դրանք:"</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Մատնահետքի պատկերակ"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"կառավարել դեմքի ճանաչման սարքը"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Հավելվածին թույլ է տալիս ավելացնել և հեռացնել դեմքի նմուշներ:"</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"օգտագործել դեմքի ճանաչման սարքը"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Հավելվածին թույլ է տալիս օգտագործել նույնականացման համար նախատեսված սարքը"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Չհաջողվեց ճանաչել ձեր դեմքը: Նորից փորձեք:"</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Դեմքը չափազանց վառ է երևում։ Թուլացրեք լույսը։"</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Դեմքը չափազանց մուգ է երևում։ Ուժեղացրեք լույսը։"</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Սարքը մի փոքր հեռացրեք դեմքից։"</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Սարքը մի փոքր մոտեցրեք դեմքին։"</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Սարքը մի փոքր վերև պահեք։"</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Սարքը մի փոքր ներքև պահեք։"</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Սարքը մի փոքր ձախ պահեք։"</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Սարքը մի փոքր ձախ պահեք։"</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Նայեք սարքի տեսախցիկին։"</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Դեմք չի հայտնաբերվել։"</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Պահեք սարքը դեմքի դիմաց։"</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Դեմքի ճանաչման սարքն անհասանելի է։"</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Ժամանակը սպառվել է: Նորից փորձեք:"</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Դեմքը հնարավոր չէ պահել։"</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Դեմքի ճանաչումը չեղարկվել է։"</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Չափից շատ փորձեր եք կատարել: Փորձեք ավելի ուշ:"</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Չափից շատ փորձեր եք կատարել: Դեմքի ճանաչման գործառույթն անջատվել է։"</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Նորից փորձեք:"</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Գրանցված դեմք չկա։"</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Սարքը չունի դեմքի ճանաչման սկաներ"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Դեմք <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Դեմքի պատկերակ"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"կարդալ համաժամեցման կարգավորումները"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Թույլ է տալիս հավելվածին կարդալ համաժամեցման կարգավորումները հաշվի համար: Օրինակ` այն կարող է որոշել, արդյոք Մարդիկ հավելվածը համաժամեցված է հաշվի հետ:"</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"համաժամեցումը փոխարկել միացվածի և անջատվածի"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi ցանցում ինտերնետ կապ չկա"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Հպեք՝ ընտրանքները տեսնելու համար"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Փոփոխություններ թեժ կետի կարգավորումներում"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Ձեր թեժ կետի հաճախականությունը փոխվել է։"</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Սարքը չի կարող աշխատել միայն 5 ԳՀց հաճախականությամբ։ Այդ հաճախականությունը կօգտագործվի հնարավորության դեպքում։"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Անցել է <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ցանցի"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Երբ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ցանցում ինտերնետ կապ չի լինում, սարքն անցնում է <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ցանցի: Նման դեպքում կարող են վճարներ գանձվել:"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ցանցից անցել է <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ցանցի"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 0f3165e..376b651 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Lokasi"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"mengakses lokasi perangkat ini"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Izinkan <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> mengakses lokasi perangkat ini?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Aplikasi ini hanya akan memiliki akses ke lokasi saat Anda sedang menggunakan aplikasi."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Selalu izinkan <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> mengakses lokasi perangkat ini?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Aplikasi ini akan selalu memiliki akses ke lokasi, bahkan saat Anda sedang tidak menggunakan aplikasi."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalender"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"mengakses kalender"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Izinkan <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> mengakses kalender?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Aplikasi ini dapat menambahkan, menghapus, atau mengubah acara kalender di ponsel. Aplikasi ini dapat mengirim pesan yang kelihatannya berasal dari pemilik kalender, atau mengubah acara tanpa memberi tahu pemilik."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"akses perintah penyedia lokasi ekstra"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Memungkinkan aplikasi mengakses perintah penyedia lokasi ekstra. Tindakan ini memungkinkan aplikasi mengganggu pengoperasian GPS atau sumber lokasi lain."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"akses lokasi pasti hanya saat di latar depan"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Aplikasi ini bisa mendapatkan lokasi pasti Anda ketika aplikasi berada di latar depan. Fitur layanan lokasi ini harus diaktifkan dan tersedia di ponsel agar dapat digunakan oleh aplikasi. Fitur ini dapat meningkatkan konsumsi baterai."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"akses perkiraan lokasi (berbasis jaringan)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Aplikasi ini dapat memperoleh lokasi Anda berdasarkan sumber jaringan seperti menara seluler dan jaringan Wi-Fi. Layanan lokasi ini harus diaktifkan dan tersedia di tablet agar aplikasi dapat menggunakannya."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Ikon sidik jari"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"kelola hardware autentikasi wajah"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Mengizinkan apl meminta metode untuk menambah & menghapus template wajah untuk digunakan."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"gunakan hardware autentikasi wajah"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Mengizinkan aplikasi untuk menggunakan hardware autentikasi wajah untuk autentikasi"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Tidak dapat memproses wajah. Harap coba lagi."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Wajah terlalu cerah. Coba dengan cahaya lebih redup."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Wajah terlalu gelap. Singkap sumber cahaya."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Jauhkan sensor dari wajah."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Dekatkan sensor ke wajah."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Naikkan sensor."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Turunkan sensor."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Gerakkan sensor ke kanan."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Gerakkan sensor ke kiri."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Lihat sensor."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Tidak ada wajah yang terdeteksi"</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Pastikan wajah tetap diam di depan perangkat."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Hardware wajah tidak tersedia."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Waktu tunggu wajah habis. Harap coba lagi."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Wajah tidak dapat disimpan."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Pengoperasian wajah dibatalkan."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Terlalu banyak percobaan. Coba lagi nanti."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Terlalu sering dicoba. Autentikasi wajah dinonaktifkan."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Coba lagi."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Tidak ada wajah yang didaftarkan."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Perangkat ini tidak memiliki sensor autentikasi wajah"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"<xliff:g id="FACEID">%d</xliff:g> wajah"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Ikon wajah"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"baca setelan sinkron"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Memungkinkan aplikasi membaca setelan sinkronisasi untuk sebuah akun. Misalnya, izin ini dapat menentukan apakah aplikasi Orang disinkronkan dengan sebuah akun."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"nyalakan dan matikan sinkronisasi"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi tidak memiliki akses internet"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tap untuk melihat opsi"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Perubahan pada setelan hotspot Anda"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Pita hotspot Anda telah berubah."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Perangkat ini tidak mendukung preferensi Anda, yaitu hanya 5GHz. Sebagai gantinya, perangkat ini akan menggunakan pita 5GHz jika tersedia."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Dialihkan ke <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Perangkat menggunakan <xliff:g id="NEW_NETWORK">%1$s</xliff:g> jika <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tidak memiliki akses internet. Tarif mungkin berlaku."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Dialihkan dari <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ke <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index a47d5b6..5f9d508 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Staðsetning"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"fá aðgang að staðsetningu þessa tækis"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Viltu veita <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> aðgang að staðsetningu þessa tækis?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Forritið hefur aðeins aðgang að staðsetningunni á meðan þú notar forritið."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Viltu alltaf veita <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> aðgang að staðsetningu þessa tækis?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Forritið hefur alltaf aðgang að staðsetningunni, jafnvel þegar þú ert ekki að nota forritið."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Dagatal"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"fá aðgang að dagatalinu þínu"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Viltu veita <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> aðgang að dagatalinu þínu?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Þetta forrit getur bætt við, fjarlægt eða breytt dagatalsviðburðum í símanum. Þetta forrit getur sent skilaboð sem geta virst koma ffrá eigendum dagatala eða breytt viðburðum án þess að láta eigendurna vita."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"aðgangur að viðbótarskipunum staðsetningarveitu"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Leyfir forriti að fá aðgang að fleiri skipunum staðsetningarveitu. Þetta getur gert forritinu kleift að hafa áhrif á virkni GPS og annars staðsetningarbúnaðar."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"aðgangur að nákvæmri staðsetningu aðeins í forgrunni"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Þetta forrit getur aðeins séð staðsetningu þína þegar það er í forgrunni. Það verður að vera kveikt á þessari staðsetningarþjónustu og hún þarf að vera aðgengileg í símanum til að forritið geti notað hana. Þetta getur aukið rafhlöðunotkun."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"fá aðgang að áætlaðri staðsetningu (frá símkerfi)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Þetta forrit getur séð staðsetningu þína út frá netkerfum á borð við farsímasenda og Wi-Fi net. Það verður að vera kveikt á slíkri staðsetningarþjónustu og hún þarf að vera aðgengileg spjaldtölvunni til að forritið geti notað hana."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Fingrafaratákn"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"stjórna vélbúnaði andlitsgreiningar"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Leyfir forritinu að beita aðferðum til að bæta við og eyða andlitssniðmátum til notkunar."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"nota vélbúnað andlitsgreiningar"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Leyfir forritinu að nota andlitsgreiningarvélbúnað til auðkenningar"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Ekki tókst að vinna úr andlitinu. Reyndu aftur."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Andlitið er of bjart. Prófaðu í minni birtu."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Andlitið er of dökkt. Finndu betri lýsingu."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Færðu skynjarann lengra frá andlitinu."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Færðu skynjarann nær andlitinu."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Færðu skynjarann ofar."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Færðu skynjarann neðar."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Færðu skynjarann til hægri."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Færðu skynjarann til vinstri."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Horfðu á skynjarann."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Ekkert andlit fannst."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Haltu andlitinu kyrru fyrir framan tækið."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Andlitsvélbúnaður ekki til staðar."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Tímamörk runnu út fyrir andlit. Reyndu aftur."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Ekki tókst að geyma andlit."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Hætt við andlitsgreiningu."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Of margar tilraunir. Reyndu aftur síðar."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Of margar tilraunir. Slökkt á andlitsgreiningu."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Reyndu aftur."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Ekkert andlit skráð."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Þetta tæki er ekki með auðkenningarskynjara fyrir andlit"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Andlit <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Andlitstákn"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"lesa samstillingar"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Leyfir forriti að lesa kosti samstillingar fyrir reikning. Þetta er til dæmis hægt að nota til að komast að því hvort forritið Fólk er samstillt við reikning."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"kveikja og slökkva á samstillingu"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi er ekki með tengingu við internetið"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Ýttu til að sjá valkosti"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Breytingar á stillingum heits reits"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Tíðnisvið heita reitsins hefur breyst."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Þetta tæki styður ekki val þitt fyrir aðeins 5 GHz. Í staðinn mun þetta tæki nota 5 GHz tíðnisvið þegar það er í boði."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Skipt yfir á <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Tækið notar <xliff:g id="NEW_NETWORK">%1$s</xliff:g> þegar <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> er ekki með internetaðgang. Gjöld kunna að eiga við."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Skipt úr <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> yfir í <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index f7cc8b6..13e8fad 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Geolocalizzazione"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"accedere alla posizione di questo dispositivo"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Consentire all\'app <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> di accedere alla posizione di questo dispositivo?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"L\'app avrà accesso alla posizione soltanto quando la usi."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Vuoi consentire sempre a <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> di accedere alla posizione di questo dispositivo?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"L\'app avrà sempre accesso alla posizione, anche quando non la usi."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Calendario"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"accedere al calendario"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Consentire all\'app <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> di accedere al tuo calendario?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Questa app può aggiungere, rimuovere o modificare eventi di calendario sul telefono. Può inviare messaggi che possono sembrare inviati dai proprietari del calendario o modificare eventi senza notificare i proprietari."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"accesso a comandi aggiuntivi provider di geolocalizz."</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Consente all\'app di accedere a ulteriori comandi del fornitore di posizione. Ciò potrebbe consentire all\'app di interferire con il funzionamento del GPS o di altre fonti di geolocalizzazione."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"Accesso alla posizione esatta solo in primo piano"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Questa app può recuperare la tua posizione esatta solo quando è in primo piano. Questi servizi di geolocalizzazione devono essere attivi e disponibili sul telefono affinché l\'app possa usarli. Potrebbe aumentare il consumo della batteria."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"accesso alla posizione approssimativa (basata sulla rete)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Questa app può accedere alla tua posizione tramite fonti di rete come antenne di telefonia mobile e reti Wi-Fi. Tali servizi di geolocalizzazione devono essere attivati e disponibili sul tablet per consentire all\'app di utilizzarli."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Icona dell\'impronta digitale"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"gestisci l\'hardware per l\'autenticazione dei volti"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Consente all\'app di richiamare i metodi per aggiungere e rimuovere i modelli di volti."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"utilizza l\'hardware per l\'autenticazione dei volti"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Consente all\'app di utilizzare hardware per l\'autenticazione dei volti"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Impossibile elaborare il volto. Riprova."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Volto troppo luminoso. Prova dove c\'è meno luce."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Volto troppo scuro. Non coprire la fonte di luce."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Allontana i sensori dal volto."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Avvicina i sensori al volto."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Sposta i sensori verso l\'alto."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Sposta i sensori verso il basso."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Sposta i sensori verso destra."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Sposta i sensori verso sinistra."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Guarda i sensori."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Nessun volto rilevato."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Tieni il volto fermo davanti al dispositivo."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Hardware per il volto non disponibile."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Timeout operazione associata al volto. Riprova."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Il volto non può essere memorizzato."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Operazione associata al volto annullata."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Troppi tentativi. Riprova più tardi."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Troppi tentativi. Autenticazione disattivata."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Riprova."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Nessun volto registrato."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Nessun sensore di autenticazione del volto sul dispositivo."</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Volto <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Icona volto"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"lettura impostazioni di sincronizz."</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Consente all\'applicazione di leggere le impostazioni di sincronizzazione per un account. Ad esempio, questa autorizzazione può determinare se l\'applicazione Persone è sincronizzata con un account."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"attivazione e disattivazione della sincronizzazione"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"La rete Wi-Fi non ha accesso a Internet"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tocca per le opzioni"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Modifiche alle tue impostazioni dell\'hotspot"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"La tua banda di hotspot è cambiata."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Questo dispositivo non supporta la tua preferenza esclusiva per 5 GHz. Utilizzerà invece la banda a 5 GHz solo quando è disponibile."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Passato a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Il dispositivo utilizza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> non ha accesso a Internet. Potrebbero essere applicati costi."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Passato da <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index a8e231a..097d791 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -282,6 +282,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"מיקום"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"גישה אל מיקום המכשיר הזה"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"לתת לאפליקציה <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> הרשאת גישה למיקום המכשיר?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"לאפליקציה תהיה גישה אל נתוני המיקום רק במהלך השימוש באפליקציה."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"תמיד לתת לאפליקציה <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> הרשאת גישה למיקום המכשיר?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"לאפליקציה תמיד תהיה גישה לנתוני המיקום, גם כשהאפליקציה אינה בשימוש."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"יומן"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"גישה אל היומן"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"לתת לאפליקציה <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> הרשאת גישה ליומן?"</string>
@@ -408,8 +411,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"אפליקציה זו יכולה להוסיף, להסיר ולשנות אירועי יומן בטלפון. האפליקציה יכולה לשנות אירועים בלי להודיע לבעליהם ולשלוח הודעות שעשויות להיראות כאילו נשלחו מבעלי יומנים."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"גישה לפקודות ספק מיקום נוספות"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"מאפשרת לאפליקציה לגשת לפקודות נוספות של ספק המיקום. הרשאה זו עשויה לאפשר לאפליקציה לשבש את פעולת ה-GPS או מקורות מיקום אחרים."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"קבלת גישה למיקום מדויק בחזית בלבד"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"אפליקציה זו יכולה לזהות את המיקום המדויק שלך רק כאשר היא פועלת בחזית. כדי שהאפליקציה תוכל להשתמש בשירותי המיקום, עליהם להיות מופעלים וזמינים בטלפון. ייתכן שפעולה זו תגביר את צריכת הסוללה."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"גישה אל מיקום משוער (מבוסס רשת)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"אפליקציה זו יכולה לזהות את המיקום שלך על סמך מקורות מיקום ברשת, כגון אנטנות סלולריות ורשתות Wi-Fi. שירותי מיקום אלה חייבים להיות מופעלים וזמינים בטאבלט שלך כדי שהאפליקציה תוכל להשתמש בהם."</string>
@@ -524,6 +526,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"סמל טביעת אצבע"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"ניהול של חומרה של זיהוי פנים לצורך אימות"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"מאפשרת לאפליקציה להפעיל שיטות להוספה ומחיקה של תבניות פנים שבהן ייעשה שימוש."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"שימוש בחומרה של זיהוי פנים לצורך אימות"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"מאפשרת לאפליקציה להשתמש בחומרה של זיהוי פנים לצורך אימות"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"לא ניתן היה לעבד את הפנים. יש לנסות שוב."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"הפנים בהירים מדי. יש לנסות באור עמום יותר."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"הפנים כהים מדי. יש להוסיף מקור אור."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"יש להרחיק את החיישן מהפנים."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"יש לקרב את החיישן לפנים."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"יש להזיז את החיישן גבוה יותר."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"יש להזיז את החיישן נמוך יותר."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"יש להזיז את החיישן ימינה."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"יש להזיז את החיישן שמאלה."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"יש להסתכל על החיישן."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"לא זוהו פנים."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"יש להחזיק את הפנים באופן יציב מול המכשיר."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"החומרה לזיהוי הפנים לא זמינה."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"חלף הזמן הקצוב לזיהוי הפנים. יש לנסות שוב."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"לא ניתן לשמור את הפנים."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"פעולת הפנים בוטלה."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"יותר מדי ניסיונות. יש לנסות שוב מאוחר יותר."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"יותר מדי ניסיונות. אימות הפנים הושבת."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"יש לנסות שוב."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"לא נרשמו פנים."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"במכשיר זה אין חיישן לאימות פנים"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"פנים <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"סמל הפנים"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"קרא את הגדרות הסינכרון"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"מאפשר לאפליקציה לקרוא את הגדרות הסנכרון של חשבון. לדוגמה, ניתן לגלות כך האם האפליקציה \'אנשים\' מסונכרן עם חשבון כלשהו."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"הפעלת וכיבוי סנכרון"</string>
@@ -1222,6 +1255,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"לרשת ה-Wi-Fi אין גישה לאינטרנט"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"הקש לקבלת אפשרויות"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"שינויים להגדרות של הנקודה לשיתוף אינטרנט"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"התדר של הנקודה לשיתוף אינטרנט השתנה."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"מכשיר זה לא תומך בהעדפות שלך ל-5GHz בלבד. במקום זאת, מכשיר זה ישתמש בתדר 5GHz כשיהיה זמין."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"מעבר אל <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"המכשיר משתמש ברשת <xliff:g id="NEW_NETWORK">%1$s</xliff:g> כשלרשת <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> אין גישה לאינטרנט. עשויים לחול חיובים."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"עבר מרשת <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> לרשת <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 9f8fd74..1c63913 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"位置情報"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"この端末の位置情報へのアクセス"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"この端末の位置情報へのアクセスを <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> に許可しますか?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"このアプリは、使用時のみ、位置情報にアクセスできるようになります。"</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"この端末の位置情報へのアクセスを <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> に常に許可しますか?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"このアプリは、未使用時も含め、常に位置情報にアクセスできるようになります。"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"カレンダー"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"カレンダーへのアクセス"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"カレンダーへのアクセスを <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> に許可しますか?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"このアプリは、お使いのスマートフォンでカレンダーの予定を追加、削除、変更できます。また、カレンダーの所有者から発信されたかのように表示されるメッセージを送信したり、所有者に通知することなく予定を変更したりできます。"</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"位置情報提供者の追加コマンドアクセス"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"位置情報提供元の追加のコマンドにアクセスすることをアプリに許可します。許可すると、アプリがGPSなどの位置情報源の動作を妨害する恐れがあります。"</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"フォアグラウンドでのみ正確な位置情報にアクセス"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"このアプリは、フォアグラウンド状態でのみユーザーの正確な位置情報を取得できます。この位置情報サービスは ON の状態にして、スマートフォンでアプリがサービスを利用できるようにする必要があります。これにより、電池の消費量が増える可能性があります。"</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"おおよその位置情報(ネットワーク基地局)へのアクセス"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"このアプリは、ネットワーク位置情報源(携帯基地局や Wi-Fi ネットワークなど)に基づいて、ユーザーの位置情報を取得します。これらの位置情報サービスは ON の状態にして、タブレットでアプリがサービスを利用できるようにする必要があります。"</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"指紋アイコン"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"顔認証ハードウェアの管理"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"使用する顔テンプレートの追加や削除を行うメソッドの呼び出しをアプリに許可します。"</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"顔認証ハードウェアの使用"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"顔認証ハードウェアを認証に使用することをアプリに許可します"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"顔を認識できませんでした。もう一度お試しください。"</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"顔が明るすぎます。照明を暗くしてみてください。"</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"顔が暗すぎます。光源のカバーを外してください。"</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"センサーを顔から遠ざけてください。"</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"センサーを顔に近づけてください。"</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"センサーを上に動かしてください。"</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"センサーを下に動かしてください。"</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"センサーを右に動かしてください。"</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"センサーを左に動かしてください。"</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"センサーを見てください。"</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"顔を検出できません。"</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"端末の前で顔を静止してください。"</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"顔認証ハードウェアが使用できません。"</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"読み取りのタイムアウトです。もう一度お試しください。"</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"顔の情報を保存できません。"</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"顔の操作をキャンセルしました。"</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"試行回数の上限です。後でもう一度お試しください。"</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"試行回数の上限です。顔認証は無効になりました。"</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"もう一度お試しください。"</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"顔の情報が登録されていません。"</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"この端末には顔認証センサーがありません"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"顔 <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"顔アイコン"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"同期設定の読み取り"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"アカウントの同期設定の読み取りをアプリに許可します。たとえば、連絡帳アプリがアカウントと同期しているかどうかをアプリから特定できるようになります。"</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"同期のON/OFFの切り替え"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi‑Fi はインターネットに接続していません"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"タップしてその他のオプションを表示"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"アクセス ポイントの設定の変更"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"アクセス ポイントの帯域幅が変更されました。"</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"この端末は 5 GHz のみという設定に対応していません。ただし、5 GHz 周波数帯が利用できるときには利用します。"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"「<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>」に切り替えました"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"端末で「<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>」によるインターネット接続ができない場合に「<xliff:g id="NEW_NETWORK">%1$s</xliff:g>」を使用します。通信料が発生することがあります。"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"「<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>」から「<xliff:g id="NEW_NETWORK">%2$s</xliff:g>」に切り替えました"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index deab577..c5a9ab2 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"მდებარეობა"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"მოწყობილობის მდებარეობაზე წვდომა"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"გსურთ, მიანიჭოთ <b><xliff:g id="APP_NAME">%1$s</xliff:g>-ს</b> ამ მოწყობილობის მდებარეობაზე წვდომის ნებართვა?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"ამ აპს მდებარეობაზე წვდომა მხოლოდ მაშინ ექნება, როცა თქვენ მას გამოიყენებთ."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"გსურთ, მიანიჭოთ <b><xliff:g id="APP_NAME">%1$s</xliff:g>-ს</b> ამ მოწყობილობის მდებარეობაზე წვდომის ნებართვა?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"ამ აპს ყოველთვის ექნება მდებარეობაზე წვდომა, მაშინაც კი, როცა თქვენ მას არ იყენებთ."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"კალენდარი"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"თქვენს კალენდარზე წვდომა"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"გსურთ, მიანიჭოთ <b><xliff:g id="APP_NAME">%1$s</xliff:g>-ს</b> თქვენს კალენდარზე წვდომის ნებართვა?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"ამ აპს შეუძლია თქვენს ტელეფონში კალენდრის მოვლენების დამატება, ამოშლა ან შეცვლა. ამ აპს შეუძლია კალენდრების მფლობელების სახელით შეტყობინებების გაგზავნა ან მოვლენების მათი მფლობელების შეტყობინების გარეშე შეცვლა."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"მდებარეობის პროვაიდერის დამატებით ბრძანებებზე წვდომა"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"აპს შეეძლება წვდომა ჰქონდეს მდებარეობის სერვისის დამატებით ბრძანებებზე. შესაძლოა აპმა ეს გამოიყენოს GPS-ისა და მდებარეობის სხვა წყაროების მუშაობის პროცესში ჩარევისთვის."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"ზუსტ მდებარეობაზე წვდომა მხოლოდ წინა პლანზე"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"ამ აპს შეუძლია თქვენი ზუსტი მდებარეობის შესახებ ინფორმაციის მიღება მხოლოდ მაშინ, როცა გაშვებულია წინა პლანზე. თქვენს ტელეფონზე ჩართული და ხელმისაწვდომი უნდა იყოს მდებარეობის სერვისები, აპმა მათი გამოყენება რომ შეძლოს. ამან შეიძლება გაზარდოს ბატარეის მოხმარება."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"მიახლოებით მდებარეობაზე წვდომა (ქსელის მეშვეობით)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"ამ აპს თქვენი მდებარეობის შესახებ ინფორმაციის მიღება ისეთი წყაროების მეშვეობით შეუძლია, როგორიცაა მობილური კავშირგაბმულობის ანძები და Wi-Fi ქსელები. მდებარეობის აღნიშნული სერვისები თქვენს ტაბლეტზე ჩართული და ხელმისაწვდომი უნდა იყოს, რათა აპმა მათი გამოყენება შეძლოს."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"თითის ანაბეჭდის ხატულა"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"სახის ამოცნობის აპარატურის მართვა"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"საშუალებას აძლევს აპს, დაამატოს და წაშალოს სახეების შაბლონები."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"სახის ამოცნობის აპარატურის გამოყენება"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"საშუალებას აძლევს აპს, ავტორიზაციისთვის გამოიყენოს სახის ამოცნობის აპარატურა"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"სახე ვერ მუშავდება. გთხოვთ, ცადოთ ხელახლა."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"სახე გადანათებულია. დაუკელით განათებას."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"სახე ჩაბნელებულია. მოუმატეთ განათებას."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"დააშორეთ მოწყობილობის სენსორი სახეს."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"მიუახლოვეთ მოწყობილობის სენსორი სახეს."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"ასწიეთ მოწყობილობის სენსორი ოდნავ ზემოთ."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"ჩასწიეთ მოწყობილობის სენსორი ოდნავ ქვემოთ."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"გასწიეთ მოწყობილობის სენსორი ოდნავ მარჯვნივ."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"გასწიეთ მოწყობილობის სენსორი ოდნავ მარცხნივ."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"შეხედეთ სენსორს."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"სახის ამოცნობა ვერ მოხერხდა."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"მოათავსეთ სახე მოწყობილობის წინ უმოძრაოდ."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"სახის ამოცნობის აპარატურა მიუწვდომელია."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"სახის ამოცნობის დრო ამოიწურა. ცადეთ ხელახლა."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"სახის შენახვა ვერ მოხერხდა."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"სახის ამოცნობა გაუქმდა."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"დაფიქსირდა ბევრი მცდელობა. ცადეთ მოგვიანებით."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"დაფიქსირდა ბევრი მცდელობა. სახის ამოცნობა გაითიშა."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"ცადეთ ხელახლა."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"სახე რეგისტრირებული არ არის."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"ამ მოწყობილობას არ აქვს სახის ამოცნობის სენსორი"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"სახე <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"სახის ხატულა"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"სინქრონიზაციის პარამეტრების წაკითხვა"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"აპს შეეძლება, წაიკითხოს ანგარიშის სინქრონიზაციის პარამეტრები. მაგალითად, მას შეეძლება განსაზღვროს, არის თუ არა People აპი სინქრონიზებული ანგარიშთან."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"სინქრონიზაციის ჩართვა და გამორთვა"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi‑Fi ქსელს ინტერნეტზე წვდომა არ აქვს"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"შეეხეთ ვარიანტების სანახავად"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"თქვენი უსადენო ქსელის პარამეტრების ცვლილება"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"თქვენი უსადენო ქსელის დიაპაზონი შეიცვალა."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"ამ მოწყობილობას არ შეუძლია მხოლოდ 5 გჰც სიხშირეზე მუშაობა. აღნიშნული სიხშირის გამოყენება მოხდება მაშინ, როცა ეს შესაძლებელია."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"ახლა გამოიყენება <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"თუ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ინტერნეტთან კავშირს დაკარგავს, მოწყობილობის მიერ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> იქნება გამოყენებული, რამაც შეიძლება დამატებითი ხარჯები გამოიწვიოს."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"ახლა გამოიყენება <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> (გამოიყენებოდა <xliff:g id="NEW_NETWORK">%2$s</xliff:g>)"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 38f12c4..0c02202 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Орналасу"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"бұл құрылғының орналасқан жерін көру"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> қолданбасына құрылғының орналасқан жері туралы мәліметтерді пайдалануға рұқсат берілсін бе?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Қолданбаны пайдалану кезінде ғана оған геодеректеріңізді көруге рұқсат етіледі."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"\"<xliff:g id="APP_NAME">%1$s</xliff:g>\" кез келген уақытта құрылғы геодеректерін пайдалансын ба?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Қолданба пайдаланылмаса да, оған геодеректеріңізді көруге рұқсат етіледі."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Күнтізбе"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"күнтізбеге кіру"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> қолданбасына күнтізбеге кіруге рұқсат берілсін бе?"</string>
@@ -402,15 +405,14 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Бұл қолданба телефондағы күнтізбе оқиғаларын енгізе, өшіре не өзгерте алады. Ол күнтізбе иелерінен келгендей болып көрінетін хабарларды жіберуі немесе иелеріне хабарламай, оқиғаларды өзгертуі мүмкін."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"қосымша аймақ жабдықтаушы пәрмендеріне қол жетімділік"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Қолданбаға орын жеткізушісінің қосымша пәрмендеріне қатынасуға рұқсат береді. Бұл қолданбаға GPS немесе басқа орын көздерінің жұмысына кедергі келтіруге рұқсат беруі мүмкін."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
- <string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Бұл қолданба тек фондық режимде нақты орналасқан жеріңіз туралы ақпаратты анықтай алады. Қолданба бұл орынды анықтау қызметтерін пайдалана алуы үшін олар қосулы әрі телефонда қолжетімді болуы керек. Батарея көбірек тұтынылуы мүмкін."</string>
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"нақты орналасқан жер туралы ақпаратқа тек ашық экранда кіру"</string>
+ <string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Бұл қолданба нақты орналасқан жеріңіз туралы ақпаратты экранда ашық тұрғанда ғана анықтай алады. Қолданба бұл орынды анықтау қызметтерін пайдалана алуы үшін, олар қосулы әрі телефонда қолжетімді болуы керек. Батарея көбірек тұтынылуы мүмкін."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"шамамен алған орынға қатынасу (желі негізінде)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Бұл қолданба орналасқан жеріңізді ұялы байланыс мұнаралары мен Wi-Fi желілері сияқты желі көздерінің негізінде анықтайды. Қолданба бұл орынды анықтау қызметтерін пайдалана алуы үшін олар қосулы әрі планшетте қолжетімді болуы керек."</string>
<string name="permdesc_accessCoarseLocation" product="tv" msgid="1884022719818788511">"Бұл қолданба орналасқан жеріңізді ұялы байланыс мұнаралары мен Wi-Fi желілері сияқты желі көздерінің негізінде анықтайды. Қолданба бұл орынды анықтау қызметтерін пайдалана алуы үшін олар қосулы әрі теледидарда қолжетімді болуы керек."</string>
<string name="permdesc_accessCoarseLocation" product="default" msgid="7788009094906196995">"Бұл қолданба орналасқан жеріңізді ұялы байланыс мұнаралары мен Wi-Fi желілері сияқты желі көздерінің негізінде анықтайды. Қолданба бұл орынды анықтау қызметтерін пайдалана алуы үшін олар қосулы әрі телефонда қолжетімді болуы керек."</string>
<string name="permlab_accessBackgroundLocation" msgid="5742466381902568536">"геодеректерге фондық режимде кіру"</string>
- <string name="permdesc_accessBackgroundLocation" msgid="6371533283380774135">"Бұл қолданба кез келген уақытта фондық режимде нақты орналасқан жеріңіз туралы ақпаратты анықтай алады. Қолданба бұл орынды анықтау қызметтерін пайдалана алуы үшін олар қосулы әрі телефонда қолжетімді болуы керек. Батарея көбірек тұтынылуы мүмкін."</string>
+ <string name="permdesc_accessBackgroundLocation" msgid="6371533283380774135">"Бұл қолданба нақты орналасқан жеріңіз туралы ақпаратты фондық режимде де анықтай алады. Қолданба бұл орынды анықтау қызметтерін пайдалана алуы үшін, олар қосулы әрі телефонда қолжетімді болуы керек. Батарея көбірек тұтынылуы мүмкін."</string>
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"аудио параметрлерін өзгерту"</string>
<string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Қолданбаға дыбыс қаттылығы және аудио шығыс үндеткішін таңдау сияқты жаһандық аудио параметрлерін өзгерту мүмкіндігін береді."</string>
<string name="permlab_recordAudio" msgid="3876049771427466323">"аудио жазу"</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Саусақ ізі белгішесі"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"бетті аутентификациялау жабдығын басқару"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Қолданбаға пайдаланатын бет үлгілерін енгізу және жою әдістерін шақыруға мүмкіндік береді."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"бетті аутентификациялау жабдығын пайдалану"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Қолданбаға бетті аутентификациялау жабдығын қолдануға рұқсат етеді"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Бет өңделмеді. Әрекетті қайталаңыз."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Бет тым ашық түсті болып шықты. Жарықты азайтыңыз."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Бет тым күңгірт түсті. Жарық көзін бөгемеңіз."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Датчикті беттен алшақ қойыңыз."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Датчикті бетке жақындатыңыз."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Датчикті жоғары көтеріңіз."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Датчикті төмен қарай жылжытыңыз."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Датчикті оңға қарай жылжытыңыз."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Датчикті солға қарай жылжытыңыз."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Датчикке қараңыз."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Бет анықталмады."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Құрылғыға бетіңізді қозғалтпай қарап тұрыңыз."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Бетті тану жабдығы қолжетімді емес."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Күту уақыты бітті. Әрекетті қайталаңыз."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Бетті сақтау мүмкін емес."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Бетті танудан бас тартылды."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Тым көп әрекет жасалды. Кейінірек қайталаңыз."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Тым көп әрекет жасалды. Бетті аутентификациялау функциясы өшірілді."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Қайталап көріңіз."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Ешқандай бет тіркелмеген."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Бұл құрылғыда бетті аутентификациялау датчигі жоқ"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Бет: <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Бет белгішесі"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"синх параметрлерін оқу"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Қолданбаға есептік жазба синхрондау параметрлерін оқу мүмкіндігін береді. Мысалы, бұл арқылы People қолданбасының есептік жазбамен сихрондалғаны анықталуы мүмкін."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"синх қосу және өшіру арасында ауысу"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi желісінде интернет байланысы жоқ"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Опциялар үшін түртіңіз"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Хотспот параметрлеріне өзгерістер енгізілді"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Хотспот жолағы өзгертілді."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Бұл құрылғы тек 5 ГГц жиілікте жұмыс істей алмайды. Бұл жиілік мүмкін болған жағдайда ғана қолданылады."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> желісіне ауысты"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Құрылғы <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> желісінде интернетпен байланыс жоғалған жағдайда <xliff:g id="NEW_NETWORK">%1$s</xliff:g> желісін пайдаланады. Деректер ақысы алынуы мүмкін."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> желісінен <xliff:g id="NEW_NETWORK">%2$s</xliff:g> желісіне ауысты"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 90142dc..50344e9 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"ទីតាំង"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"ចូលដំណើរការទីតាំងរបស់ឧបករណ៍នេះ"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"អនុញ្ញាតឱ្យ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ចូលប្រើទីតាំងរបស់ឧបករណ៍នេះ?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"កម្មវិធីនេះនឹងមានសិទ្ធិចូលប្រើទីតាំង នៅពេលអ្នកប្រើកម្មវិធីនេះតែប៉ុណ្ណោះ។"</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"អនុញ្ញាតឱ្យ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ចូលប្រើទីតាំងរបស់ឧបករណ៍នេះជានិច្ចមែនទេ?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"កម្មវិធីនេះនឹងមានសិទ្ធិចូលប្រើទីតាំងជានិច្ច ទោះបីជានៅពេលអ្នកមិនប្រើកម្មវិធីនេះក៏ដោយ។"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"ប្រតិទិន"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"ចូលប្រើប្រិតិទិនរបស់អ្នក"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"អនុញ្ញាតឱ្យ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ចូលប្រើប្រតិទិនរបស់អ្នក?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"កម្មវិធីនេះអាចបញ្ចូល លុប ឬប្តូរព្រឹត្តិការណ៍ប្រតិទិននៅលើទូរសព្ទរបស់អ្នក។ កម្មវិធីនេះអាចផ្ញើសារ ដែលអាចបង្ហាញថាសារនោះចេញមកពីម្ចាស់ប្រតិទិន ឬផ្លាស់ប្តូរព្រឹត្តិការណ៍ដោយគ្មានការជូនដំណឹងដល់ម្ចាស់របស់ពួកវាទេ។"</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"ចូលដំណើរការពាក្យបញ្ជាក្រុមហ៊ុនផ្ដល់ទីតាំង"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"ឲ្យកម្មវិធីចូលដំណើរការពាក្យបញ្ជាកម្មវិធីផ្ដល់ទីតាំងបន្ថែម។ វាអាចអនុញ្ញាតឲ្យកម្មវិធីទាក់ទងជាមួយប្រតិបត្តិការជីភីអេស ឬប្រភពទីតាំងផ្សេង។"</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"ចូលប្រើទីតាំងជាក់លាក់តែនៅផ្ទៃខាងមុខប៉ុណ្ណោះ"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"កម្មវិធីនេះអាចទទួលបានទីតាំងពិតប្រាកដរបស់អ្នកតែនៅពេលវាស្ថិតនៅផ្ទៃខាងមុខប៉ុណ្ណោះ។ សេវាកម្មទីតាំងទាំងនេះត្រូវតែបើក និងមាននៅលើទូរសព្ទរបស់អ្នក ដើម្បីឱ្យកម្មវិធីនេះអាចប្រើពួកវាបាន។ វាអាចប្រើថាមពលច្រើនជាងមុន។"</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"ចូលដំណើរការទីតាំងប្រហាក់ប្រហែល (ផ្អែកលើបណ្តាញ)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"កម្មវិធីនេះអាចទទួលបានទីតាំងរបស់អ្នក ដោយផ្អែកលើប្រភពបណ្តាញ ដូចជា៖ អង់តែន និងបណ្តាញ Wi-Fi ។ សេវាកម្មទីតាំងទាំងនេះត្រូវតែបើក និងត្រូវតែមាននៅលើថេប្លេតរបស់អ្នក ដើម្បីឲ្យកម្មវិធីនេះអាចប្រើវាបាន។"</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"រូបតំណាងស្នាមម្រាមដៃ"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"គ្រប់គ្រងផ្នែករឹងផ្ទៀងផ្ទាត់ផ្ទៃមុខ"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"អនុញ្ញាតឱ្យកម្មវិធីប្រើវិធីសាស្ត្រដើម្បីបញ្ចូល និងលុបទម្រង់គំរូផ្ទៃមុខសម្រាប់ប្រើប្រាស់។"</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"ប្រើផ្នែករឹងផ្ទៀងផ្ទាត់ផ្ទៃមុខ"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"អនុញ្ញាតឱ្យកម្មវិធីប្រើផ្នែករឹងផ្ទៀងផ្ទាត់ផ្ទៃមុខសម្រាប់ការផ្ទៀងផ្ទាត់"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"មិនអាចដំណើរការផ្ទៃមុខបានទេ។ សូមព្យាយាមម្តងទៀត។"</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"ផ្ទៃមុខចាំងពេក។ សូមសាកល្បងនៅកន្លែងដែលមានពន្លឺទាបជាងនេះ។"</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"ផ្ទៃមុខងងឹតពេក។ សូមរកកន្លែងដែលមានប្រភពពន្លឺ។"</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"សូមផ្លាស់ទីឧបករណ៍ចាប់សញ្ញាឱ្យឆ្ងាយពីផ្ទៃមុខរបស់អ្នកជាងនេះ។"</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"សូមដាក់ឧបករណ៍ចាប់សញ្ញាឱ្យនៅជិតផ្ទៃមុខជាងនេះ។"</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"សូមផ្លាស់ទីឧបករណ៍ចាប់សញ្ញាឱ្យខ្ពស់ជាងនេះ។"</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"សូមផ្លាស់ទីឧបករណ៍ចាប់សញ្ញាឱ្យទាបជាងនេះ។"</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"សូមផ្លាស់ទីឧបករណ៍ចាប់សញ្ញាទៅស្ដាំ។"</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"សូមផ្លាស់ទីឧបករណ៍ចាប់សញ្ញាទៅឆ្វេង។"</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"សូមមើលទៅឧបករណ៍ចាប់សញ្ញា។"</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"រកមិនឃើញផ្ទៃមុខទេ។"</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"រក្សាផ្ទៃមុខរបស់អ្នកឱ្យនឹងនៅមុខឧបករណ៍។"</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"មិនអាចប្រើផ្នែករឹងផ្ទៃមុខបានទេ។"</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"ការសម្គាល់ផ្ទៃមុខបានអស់ម៉ោង។ សូមព្យាយាមម្ដងទៀត។"</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"មិនអាចរក្សាទុកផ្ទៃមុខបានទេ។"</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"បានបោះបង់ប្រតិបត្តិការផ្ទៃមុខ។"</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"ព្យាយាមចូលច្រើនពេកហើយ។ សូមព្យាយាមម្តងទៀតពេលក្រោយ។"</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"ព្យាយាមចូលច្រើនពេកហើយ។ បានបិទការផ្ទៀងផ្ទាត់ផ្ទៃមុខ។"</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"សូមព្យាយាមម្ដងទៀត។"</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"មិនអាចចុះឈ្មោះផ្ទៃមុខបានទេ។"</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"ឧបករណ៍នេះមិនមានឧបករណ៍ផ្ទៀងផ្ទាត់ផ្ទៃមុខនោះទេ"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"ផ្ទៃមុខទី <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"រូបផ្ទៃមុខ"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"អានការកំណត់ធ្វើសមកាលកម្ម"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"ឲ្យកម្មវិធីអានការកំណត់ធ្វើសមកាលកម្មសម្រាប់គណនី។ ឧទាហរណ៍ វាអាចកំណត់ថាតើកម្មវិធីត្រូវបានបើកជាមួយគណនីដែរឬទេ។"</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"បិទ/បើកការធ្វើសមកាលកម្ម"</string>
@@ -1180,6 +1213,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi មិនមានការតភ្ជាប់អ៊ីនធឺណិតទេ"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ប៉ះសម្រាប់ជម្រើស"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"ប្ដូរទៅការកំណត់ហតស្ប៉តរបស់អ្នក"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"រលកសញ្ញាហតស្ប៉តរបស់អ្នកបានផ្លាស់ប្ដូរ។"</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"ឧបករណ៍នេះមិនអាចប្រើចំណូលចិត្តរបស់អ្នកសម្រាប់តែ 5GHz ទេ។ ផ្ទុយមកវិញ ឧបករណ៍នេះនឹងប្រើរលកសញ្ញា 5GHz នៅពេលដែលអាចប្រើបាន។"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"បានប្តូរទៅ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"ឧបករណ៍ប្រើ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> នៅពេលដែល <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> មិនមានការតភ្ជាប់អ៊ីនធឺណិត។ អាចគិតថ្លៃលើការប្រើប្រាស់ទិន្នន័យ។"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"បានប្តូរពី <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ទៅ <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index efc650c..59055bb 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"ಸ್ಥಳ"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"ಈ ಸಾಧನದ ಸ್ಥಳವನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"ಈ ಸಾಧನದ ಸ್ಥಳವನ್ನು ಪ್ರವೇಶಿಸಲು <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"ನೀವು ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಬಳಸುವಾಗ ಈ ಅಪ್ಲಿಕೇಶನ್ ಸ್ಥಳಕ್ಕೆ ಮಾತ್ರ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿರುತ್ತದೆ."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"ಈ ಸಾಧನದ ಸ್ಥಳವನ್ನು ಪ್ರವೇಶಿಸಲು ಯಾವಾಗಲೂ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"ನೀವು ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಬಳಸದಿರುವಾಗಲೂ ಅಪ್ಲಿಕೇಶನ್ ಯಾವಾಗಲೂ ಸ್ಥಳಕ್ಕೆ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿರುತ್ತದೆ."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"ಕ್ಯಾಲೆಂಡರ್"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"ನಿಮ್ಮ ಕ್ಯಾಲೆಂಡರ್ ಪ್ರವೇಶಿಸಲು"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"ನಿಮ್ಮ ಕ್ಯಾಲೆಂಡರ್ ಪ್ರವೇಶಿಸಲು <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"ಈ ಅಪ್ಲಿಕೇಶನ್ ನಿಮ್ಮ ಫೋನ್ನಲ್ಲಿ ಕ್ಯಾಲೆಂಡರ್ ಈವೆಂಟ್ಗಳನ್ನು ಸೇರಿಸಬಹುದು, ತೆಗೆದುಹಾಕಬಹುದು ಅಥವಾ ಬದಲಾಯಿಸಬಹುದು. ಈ ಅಪ್ಲಿಕೇಶನ್ ಕ್ಯಾಲೆಂಡರ್ನ ಮಾಲೀಕರಿಂದ ಬಂದಿರಬಹುದಾದ ಕಾಣಿಸಿಕೊಳ್ಳುವ ಸಂದೇಶಗಳನ್ನು ಕಳುಹಿಸಬಹುದು ಅಥವಾ ಅವರ ಮಾಲೀಕರಿಗೆ ತಿಳಿಸದಂತೆ ಘಟನೆಗಳು ಬದಲಾಯಿಸುವುದು."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"ಹೆಚ್ಚುವರಿ ಸ್ಥಳ ಪೂರೈಕೆದಾರರ ಆದೇಶಗಳನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"ಹೆಚ್ಚಿನ ಸ್ಥಳ ಪೂರೈಕೆದಾರ ಆದೇಶಗಳನ್ನು ಪ್ರವೇಶಿಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅವಕಾಶ ನೀಡುತ್ತದೆ. ಇದು GPS ಅಥವಾ ಇತರ ಸ್ಥಳ ಮೂಲಗಳ ಕಾರ್ಯಾಚರಣೆಯಲ್ಲಿ ಮಧ್ಯ ಪ್ರವೇಶಿಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸಬಹುದು."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"ಮುನ್ನೆಲೆಯಲ್ಲಿ ಮಾತ್ರ ನಿಖರವಾದ ಸ್ಥಳವನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"ಈ ಅಪ್ಲಿಕೇಶನ್ ಮುಂಭಾಗದಲ್ಲಿರುವಾಗ ಮಾತ್ರ ನಿಮ್ಮ ನಿಖರ ಸ್ಥಳವನ್ನು ಪಡೆಯಬಹುದು. ಈ ಸ್ಥಳ ಸೇವೆಗಳನ್ನು ಆನ್ ಮಾಡಿರಬೇಕು ಮತ್ತು ಅವುಗಳನ್ನು ಬಳಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಸಾಧ್ಯವಾಗುವಂತೆ ನಿಮ್ಮ ಫೋನ್ನಲ್ಲಿ ಅವುಗಳು ಲಭ್ಯವಿರಬೇಕು."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"ಅಂದಾಜು ಸ್ಥಳವನ್ನು ಪ್ರವೇಶಿಸಿ (ನೆಟ್ವರ್ಕ್-ಆಧಾರಿತ)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"ಈ ಅಪ್ಲಿಕೇಶನ್ ನಿಮ್ಮ ಸ್ಥಳವನ್ನು ಸೆಲ್ ಟವರ್ಗಳು ಮತ್ತು ವೈ-ಫೈ ನೆಟ್ವರ್ಕ್ನಂತಹ ನೆಟ್ವರ್ಕ್ ಮೂಲಗಳ ಆಧಾರದ ಮೇಲೆ ಪಡೆಯಬಹುದು. ಈ ಸ್ಥಳ ಸೇವೆಗಳನ್ನು ಆನ್ ಮಾಡಿರಬೇಕು ಮತ್ತು ಅವುಗಳನ್ನು ಬಳಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಸಾಧ್ಯವಾಗುವಂತೆ ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ನಲ್ಲಿ ಅವುಗಳು ಲಭ್ಯವಿರಬೇಕು."</string>
@@ -518,6 +520,64 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"ಬೆರಳಚ್ಚು ಐಕಾನ್"</string>
+ <!-- no translation found for permlab_manageFace (2137540986007309781) -->
+ <skip />
+ <!-- no translation found for permdesc_manageFace (8919637120670185330) -->
+ <skip />
+ <!-- no translation found for permlab_useFaceAuthentication (8996134460546804535) -->
+ <skip />
+ <!-- no translation found for permdesc_useFaceAuthentication (5011118722951833089) -->
+ <skip />
+ <!-- no translation found for face_acquired_insufficient (5901287247766106330) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_bright (610606792381297174) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_dark (7229162716976778371) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_close (1980310037427755293) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_far (4494571381828850007) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_high (228411096134808372) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_low (4539774649296349109) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_right (1650292067226118760) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_left (2712489669456176505) -->
+ <skip />
+ <!-- no translation found for face_acquired_poor_gaze (8344973502980415859) -->
+ <skip />
+ <!-- no translation found for face_acquired_not_detected (5707782294589511391) -->
+ <skip />
+ <!-- no translation found for face_acquired_not_steady (3722829465011040042) -->
+ <skip />
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <!-- no translation found for face_error_hw_not_available (6255891785768984615) -->
+ <skip />
+ <!-- no translation found for face_error_timeout (4014326147867150054) -->
+ <skip />
+ <!-- no translation found for face_error_no_space (8224993703466381314) -->
+ <skip />
+ <!-- no translation found for face_error_canceled (283945501061931023) -->
+ <skip />
+ <!-- no translation found for face_error_lockout (3407426963155388504) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_permanent (8198354656746088890) -->
+ <skip />
+ <!-- no translation found for face_error_unable_to_process (238761109287767270) -->
+ <skip />
+ <!-- no translation found for face_error_not_enrolled (9166792142679691323) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (4737289254517095671) -->
+ <skip />
+ <!-- no translation found for face_name_template (7004562145809595384) -->
+ <skip />
+ <string-array name="face_error_vendor">
+ </string-array>
+ <!-- no translation found for face_icon_content_description (4024817159806482191) -->
+ <skip />
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"ಸಿಂಕ್ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ರೀಡ್ ಮಾಡು"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"ಒಂದು ಖಾತೆಯ ಸಿಂಕ್ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಓದಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅವಕಾಶ ನೀಡುತ್ತದೆ. ಉದಾಹರಣೆಗೆ, ಖಾತೆಯೊಂದಿಗೆ ಜನರ ಅಪ್ಲಿಕೇಶನ್ ಸಿಂಕ್ ಮಾಡಲಾಗಿದೆಯೇ ಎಂಬುದನ್ನು ಇದು ನಿರ್ಧರಿಸಬಹುದು."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ಸಿಂಕ್ ಆನ್ ಮತ್ತು ಸಿಂಕ್ ಆಫ್ ಟಾಗಲ್ ಮಾಡಿ"</string>
@@ -1178,6 +1238,12 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"ವೈ ಫೈ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿಲ್ಲ"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ಆಯ್ಕೆಗಳಿಗೆ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+ <!-- no translation found for wifi_softap_config_change (8475911871165857607) -->
+ <skip />
+ <!-- no translation found for wifi_softap_config_change_summary (7601233252456548891) -->
+ <skip />
+ <!-- no translation found for wifi_softap_config_change_detailed (8022936822860678033) -->
+ <skip />
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶ ಹೊಂದಿಲ್ಲದಿರುವಾಗ, ಸಾಧನವು <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ಬಳಸುತ್ತದೆ. ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ರಿಂದ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 881eee20..8d28671 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"위치"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"이 기기의 위치정보에 액세스"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>에서 내 기기 위치에 액세스하도록 허용하시겠습니까?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"앱을 사용할 때만 앱에서 위치에 액세스합니다."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>에서 내 기기 위치에 액세스하도록 허용하시겠습니까?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"앱을 사용하지 않을 때에도 앱에서 항상 위치에 액세스합니다."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"캘린더"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"캘린더에 액세스"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>에서 내 캘린더에 액세스하도록 허용하시겠습니까?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"앱이 일정을 추가, 삭제, 변경할 수 있도록 허용합니다. 앱이 메시지를 전송하거나 사용자에게 별도 표시 없이 일정을 수정할 수도 있습니다."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"추가 위치 제공업체 명령에 접근"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"앱이 추가 위치 정보 제공 기능의 명령에 접근하도록 허용합니다. 이 경우 앱이 GPS 또는 기타 위치 소스의 작동을 방해할 수 있습니다."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"포그라운드에서만 정확한 위치에 액세스"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"이 앱은 포그라운드에 있을 때만 나의 정확한 위치를 알 수 있습니다. 앱에서 위치 서비스를 사용하려면 휴대전화에서 위치 서비스가 사용 설정되어 있으며 사용할 수 있어야 합니다. 배터리 사용량이 늘어날 수 있습니다."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"대략적인 위치(네트워크 기반)에 액세스"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"이 앱은 기지국 및 Wi-Fi 네트워크와 같은 네트워크 소스를 통해 내 위치를 알 수 있습니다. 앱에서 위치 서비스를 사용하려면 태블릿에서 위치 서비스가 사용 설정되어 있으며 사용 가능해야 합니다."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"지문 아이콘"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"얼굴 인증 하드웨어 관리"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"사용할 얼굴 템플릿의 추가 및 삭제 메서드를 앱에서 호출하도록 허용합니다."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"얼굴 인증 하드웨어 사용"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"앱에서 얼굴 인증 하드웨어를 인증에 사용하도록 허용합니다."</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"얼굴을 인식할 수 없습니다. 다시 시도해 주세요."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"얼굴이 너무 밝습니다. 조명을 더 어둡게 해 보세요."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"얼굴이 너무 어둡습니다. 조명을 더 밝게 해 보세요."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"센서를 얼굴에서 더 멀리 떨어뜨려 주세요."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"센서를 얼굴에 더 가까이 대 주세요."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"센서를 위쪽으로 옮겨 주세요."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"센서를 아래쪽으로 옮겨 주세요."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"센서를 오른쪽으로 옮겨 주세요."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"센서를 왼쪽으로 옮겨 주세요."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"센서를 바라보세요."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"얼굴을 감지할 수 없습니다."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"얼굴을 움직이지 말고 기기를 마주 보세요."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"얼굴 인식 하드웨어를 사용할 수 없습니다."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"얼굴 인식 시간이 초과되었습니다. 다시 시도하세요."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"얼굴을 저장할 수 없습니다."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"얼굴 인식 작업이 취소되었습니다."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"시도 횟수가 너무 많습니다. 나중에 다시 시도하세요."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"시도 횟수가 너무 많아 얼굴 인증이 사용 중지되었습니다."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"다시 시도해 보세요."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"등록된 얼굴이 없습니다."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"이 기기에는 얼굴 인증 센서가 없습니다."</string>
+ <string name="face_name_template" msgid="7004562145809595384">"얼굴 <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"얼굴 아이콘"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"동기화 설정 읽기"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"앱이 계정의 동기화 설정을 읽을 수 있도록 허용합니다. 예를 들어, 계정에서 주소록 앱을 동기화할지 여부를 확인할 수 있습니다."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"동기화 사용 및 사용 중지 전환"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi가 인터넷에 연결되어 있지 않습니다"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"탭하여 옵션 보기"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"핫스팟 설정 변경"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"핫스팟 대역이 변경되었습니다."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"이 기기에서는 5GHz 전용 환경설정이 지원되지 않습니다. 대신 가능할 때만 기기에서 5GHz 대역이 사용됩니다."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>(으)로 전환"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>(으)로 인터넷에 연결할 수 없는 경우 기기에서 <xliff:g id="NEW_NETWORK">%1$s</xliff:g>이(가) 사용됩니다. 요금이 부과될 수 있습니다."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>에서 <xliff:g id="NEW_NETWORK">%2$s</xliff:g>(으)로 전환"</string>
@@ -1676,7 +1712,7 @@
<item quantity="one">1초 후에 다시 시도하세요.</item>
</plurals>
<string name="restr_pin_try_later" msgid="973144472490532377">"나중에 다시 시도"</string>
- <string name="immersive_cling_title" msgid="8394201622932303336">"전체 화면 보기 중"</string>
+ <string name="immersive_cling_title" msgid="8394201622932303336">"전체 화면 모드"</string>
<string name="immersive_cling_description" msgid="3482371193207536040">"종료하려면 위에서 아래로 스와이프합니다."</string>
<string name="immersive_cling_positive" msgid="5016839404568297683">"확인"</string>
<string name="done_label" msgid="2093726099505892398">"완료"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 7d046c6..a56fb67 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Жайгашкан жер"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"түзмөктүн жайгашкан жерин аныктоого"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> колдонмосу бул түзмөктүн кайда жүргөнүн көрүп турганга уруксат бересизби?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Сиз бул колдонмону пайдаланып жатканда гана ал жайгашкан жериңизди көрө алат."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> колдонмосуна бул түзмөктүн жайгашкан жерин пайдаланууга дайыма уруксат берилсинби?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Сиз бул колдонмону пайдаланбай турганда да ал жайгашкан жериңизди көрүп турат."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Жылнаама"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"жылнаамаңызды пайдалануу"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> колдонмосуна жылнаамаңызды пайдаланууга уруксат берилсинби?"</string>
@@ -402,15 +405,14 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Бул колдонмо телефонуңузга жылнаама иш-чараларын кошуп, алып салып же өзгөртүшү мүмкүн. Бул колдонмо жылнаама ээсинин атынан билдирүүлөрдү жөнөтүп же ээсине эскертпестен иш-чараларды өзгөртүшү мүмкүн."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"жайгашкан жерди аныктагычтын кошумча буйруктарын пайдалануу"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Колдонмого жайгашкан жерди табуучу кошумча жабдуучулардын буйруктарын колдонуу мүмкүнчүлүгүн берет. Ушуну менен колдонмо GPS\'тин ишине жана башка жайгашкан жерлерди аныктоо кызматтарына кийлигише алат."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"так аныкталган жайгашкан жерге активдүү режимде гана кирүүгө уруксат берүү"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Бул колдонмонун активдүү режимде гана жайгашкан жериңиздин дайындарын алууга мүмкүнчүлүгү бар. Колдонмо бул кызматтарды пайдаланышы үчүн аларды күйгүзүп, телефонуңузга туташтырып коюшуңуз керек. Ушуну менен батареянын кубаты көбүрөөк сарпталышы мүмкүн."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"болжолдуу жайгашкан жерге (тармактын негизинде) уруксат"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Бул колдонмо байланыш мунаралары жана Wi-Fi сыяктуу тармактык булактар аркылуу жайгашкан жериңизди аныктай алат. Колдонмо бул кызматтарды пайдаланышы үчүн, аларды күйгүзүп, планшетиңизге туташтырып коюшуңуз керек."</string>
<string name="permdesc_accessCoarseLocation" product="tv" msgid="1884022719818788511">"Бул колдонмо байланыш мунаралары жана Wi-Fi сыяктуу тармактык булактар аркылуу жайгашкан жериңизди аныктай алат. Колдонмо бул кызматтарды пайдаланышы үчүн, аларды күйгүзүп, сыналгыңызга туташтырып коюшуңуз керек."</string>
<string name="permdesc_accessCoarseLocation" product="default" msgid="7788009094906196995">"Бул колдонмо байланыш мунаралары жана Wi-Fi сыяктуу тармактык булактар аркылуу жайгашкан жериңизди аныктай алат. Колдонмо бул кызматтарды пайдаланышы үчүн, аларды күйгүзүп, телефонуңузга туташтырып коюшуңуз керек."</string>
<string name="permlab_accessBackgroundLocation" msgid="5742466381902568536">"так аныкталган жайгашкан жерге фондук режимде кирүүгө уруксат берүү"</string>
- <string name="permdesc_accessBackgroundLocation" msgid="6371533283380774135">"Бул колдонмонун фондук режимде жайгашкан жериңиздин дайындарын каалаган убакта алууга мүмкүнчүлүгү бар. Колдонмо бул кызматтарды пайдаланышы үчүн аларды күйгүзүп, телефонуңузга туташтырып коюшуңуз керек. Ушуну менен батареянын кубаты көбүрөөк сарпталышы мүмкүн."</string>
+ <string name="permdesc_accessBackgroundLocation" msgid="6371533283380774135">"Бул колдонмо фондук режимде сиздин кайда жүргөнүңүздү көрүп турат. Ал үчүн жайгашкан жерди аныктоо функциясын иштетишиңиз керек. Эскерте кетүүчү нерсе, батареяңыз тез отуруп калышы мүмкүн."</string>
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"аудио жөндөөлөрүңүздү өзгөртүңүз"</string>
<string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Колдонмого үн деңгээли жана кайсы динамик аркылуу үн чыгарылышы керек сыяктуу түзмөктүн аудио тууралоолорун өзгөртүүгө уруксат берет."</string>
<string name="permlab_recordAudio" msgid="3876049771427466323">"аудио жаздыруу"</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Манжа изинин сөлөкөтү"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"жүздүн аныктыгын текшерүүчү аппараттык камсыздоону башкаруу"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Колдонмого пайдалануу үчүн жүздүн үлгүлөрүн кошуу жана жок кылуу мүмкүндүгүн берет."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"жүздүн аныктыгын текшерүүчү аппараттык камсыздоону колдонуу"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Колдонмого аныктыгын текшерүү үчүн жүздүн аныктыгын текшерүүчү аппараттык камсыздоону пайдалануу мүмкүндүгүн берет"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Жүзүңүз таанылбай койду. Кайра аракет кылыңыз."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Өтө жарык болуп жатат. Жаракты азайтып көрүңүз."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Өтө караңгы болуп жатат. Жарыкты ачып коюңуз."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Сенсорду бетиңизден алысыраак жылдырыңыз."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Сенсорду бетиңизге жакыныраак жылдырыңыз."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Сенсорду жогору жакка жылдырыңыз."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Сенсорду төмөн жакка жылдырыңыз."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Сенсорду оң жакка жылдырыңыз."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Сенсорду сол жакка жылдырыңыз."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Сенсорду караңыз."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Жүзүңүз табылган жок."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Түзмөктүн алдында жүзүңүздү бир калыпта кармаңыз."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Жүздү аныктоочу аппараттык камсыздоо жеткиликсиз."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Жүздүн аныктыгын текшерүүнү күтүү мөөнөтү бүттү. Кайра аракет кылыңыз."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Жүздү сактоо мүмкүн эмес."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Жүздүн аныктыгын текшерүү жокко чыгарылды."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Өтө көп жолу аракет жасадыңыз. Кийинчерээк кайра аракет кылыңыз."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Өтө көп жолу аракет жасадыңыз. Жүздүн аныктыгын текшерүү сенсору өчүрүлдү."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Кайра аракет кылыңыз."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Бир да жүз катталган жок."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Бул түзмөктө жүздүн аныктыгын текшерүү сенсору жок"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Жүз <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Жүздүн сүрөтчөсү"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"шайкештирүү жөндөөлөрүн окуу"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Колдонмого эсеп менен синхрондошуу тууралоолорун окуганга уруксат берет. Мисалы, Кишилер колдонмосу эсеп менен синхрондошкондугун аныктай алат."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"синхрондоштурууну өчүрүү/жандыруу"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi тармагы Интернетке туташпай турат"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Параметрлерди ачуу үчүн таптап коюңуз"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Туташуу түйүнүңүздүн жөндөөлөрүнө өзгөртүүлөр киргизилди"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Туташуу түйүнүңүздүн жыштыгы өзгөрдү."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Бул түзмөк 5ГГцти гана колдонуу жөндөөсүн колдоого албайт. Анын ордуна, бул түзмөк 5ГГц жыштыгын ал жеткиликтүү болгондо колдонот."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> тармагына которуштурулду"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> тармагы Интернетке туташпай турганда, түзмөгүңүз <xliff:g id="NEW_NETWORK">%1$s</xliff:g> тармагын колдонот. Акы алынышы мүмкүн."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> дегенден <xliff:g id="NEW_NETWORK">%2$s</xliff:g> тармагына которуштурулду"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 50499b0..64df34d 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"ສະຖານທີ່"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"ເຂົ້າເຖິງຂໍ້ມູນສະຖານທີ່ຂອງອຸປະກອນນີ້"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"ອະນຸຍາດ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ໃຫ້ເຂົ້າເຖິງສະຖານທີ່ຂອງອຸປະກອນບໍ?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"ແອັບຈະມີສິດເຂົ້າເຖິງສະຖານທີ່ໃນເວລາທີ່ທ່ານກຳລັງໃຊ້ແອັບຢູ່ເທົ່ານັ້ນ."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"ອະນຸຍາດໃຫ້ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ເຂົ້າເຖິງສະຖານທີ່ຂອງອຸປະກອນນີ້ບໍ?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"ແອັບຈະມີສິດເຂົ້າເຖິງສະຖານທີ່ທຸກເທື່ອ ເຖິງແມ່ນໃນເວລາທ່ານບໍ່ໃຊ້ແອັບຢູ່ກໍຕາມ."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"ປະຕິທິນ"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"ເຂົ້າຫາປະຕິທິນຂອງທ່ານ"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"ອະນຸຍາດ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ໃຫ້ເຂົ້າເຖິງປະຕິທິນຂອງທ່ານບໍ?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"This app can add, remove, or change calendar events on your phone. This app can send messages that may appear to come from calendar owners, or change events without notifying their owners."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"ເຂົ້າເຖິງຄຳສັ່ງຜູ່ໃຫ້ບໍລິການພິກັດສະຖານທີ່"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"ອະນຸຍາດໃຫ້ແອັບຯເຂົ້າເຖິງຄຳສັ່ງເພີ່ມເຕີມຂອງຜູ່ໃຫ້ບໍລິການສະຖານທີ່. ນີ້ອາດຈະເປັນການເຮັດໃຫ້ແອັບຯ ລົບກວນການເຮັດວຽກຂອງ GPS ຫຼືແຫລ່ງຂໍ້ມູນສະຖານທີ່ອື່ນໆໄດ້."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"ເຂົ້າເຖິງສະຖານທີ່ແນ່ນອນໃນພື້ນໜ້າເທົ່ານັ້ນ"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"ແອັບນີ້ສາມາດຮັບເອົາສະຖານທີ່ແນ່ນອນຂອງທ່ານໄດ້ທຸກເວລາທີ່ມັນຢູ່ໃນພື້ນໜ້າ. ການບໍລິການສະຖານທີ່ເຫຼົ່ານີ້ຕ້ອງເປີດຢູ່ ແລະ ສາມາດໃຊ້ໄດ້ໃນໂທລະສັບຂອງທ່ານເພື່ອໃຫ້ແອັບສາມາດໃຊ້ພວກມັນໄດ້. ນີ້ອາດຈະເຮັດໃຫ້ການໃຊ້ແບັດເຕີຣີເພີ່ມຂຶ້ນ."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"ເຂົ້າຫາທີ່ຕັ້ງໂດຍປະມານ (ອີງໃສ່ເຄືອຂ່າຍ)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"This app can get your location based on network sources such as cell towers and Wi-Fi networks. These location services must be turned on and available on your tablet for the app to be able to use them."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"ໄອຄອນລາຍນິ້ວມື"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"ຈັດການຮາດແວການກວດສອບຄວາມຖືກຕ້ອງດ້ວຍໃບໜ້າ"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"ອະນຸຍາດໃຫ້ແອັບເປີດວິທີການຕ່າງໆເພື່ອເພີ່ມ ແລະ ລຶບແມ່ແບບໃບໜ້າສຳລັບການນຳໃຊ້."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"ໃຊ້ຮາດແວການກວດສອບຄວາມຖືກຕ້ອງດ້ວຍໃບໜ້າ"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"ອະນຸຍາດໃຫ້ແອັບໃຊ້ຮາດແວການກວດສອບຄວາມຖືກຕ້ອງດ້ວຍໃບໜ້າສຳລັບການກວດສອບຄວາມຖືກຕ້ອງ"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"ບໍ່ສາມາດປະມວນຜົນຂໍ້ມູນໃບໜ້າໄດ້. ກະລຸນາລອງອີກຄັ້ງ."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"ໃບໜ້າສະຫວ່າງເກີນໄປ. ກະລຸນາລອງໃນບ່ອນທີ່ແສງໜ້ອຍກວ່າ."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"ໃບໜ້າມືດເກີນໄປ. ກະລຸນາເປີດແຫຼ່ງກຳເນີດແສງ."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"ກະລຸນາຍ້າຍເຊັນເຊີອອກຫ່າງຈາກໃບໜ້າຕື່ມອີກ."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"ກະລຸນາຍ້າຍເຊັນເຊີເຂົ້າໃກ້ໃບໜ້າຕື່ມອີກ."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"ກະລຸນາຍ້າຍເຊັນເຊີໃຫ້ສູງຂຶ້ນອີກ."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"ກະລຸນາຍ້າຍເຊັນເຊີໃຫ້ຕໍ່າລົງອີກ."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"ກະລຸນາຍ້າຍເຊັນເຊີໄປເບື້ອງຂວາ."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"ກະລຸນາຍ້າຍເຊັນເຊີໄປເບື້ອງຊ້າຍ."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"ກະລຸນາແນມເບິ່ງເຊັນເຊີ."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"ກວດບໍ່ພົບໃບໜ້າ."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"ຮັກສາໃບໜ້າໃຫ້ຢູ່ນິ້ງຕໍ່ໜ້າອຸປະກອນ"</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"ຮາດແວກວດໃບໜ້າບໍ່ສາມາດໃຊ້ໄດ້."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"ໝົດເວລາກວດໃບໜ້າແລ້ວ. ກະລຸນາລອງອີກຄັ້ງ."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"ບໍ່ສາມາດເກັບຮັກສາໃບໜ້າໄວ້ໄດ້."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"ຍົກເລີກການດຳເນີນການກັບໃບໜ້າແລ້ວ."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"ມີຄວາມພະຍາຍາມຫຼາຍຄັ້ງເກີນໄປ. ກະລຸນາລອງໃໝ່ໃນພາຍຫຼັງ."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"ມີຄວາມພະຍາຍາມຫຼາຍຄັ້ງເກີນໄປ. ປິດນຳໃຊ້ການກວດສອບຄວາມຖືກຕ້ອງດ້ວຍໃບໜ້າແລ້ວ."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"ລອງອີກຄັ້ງ."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"ບໍ່ໄດ້ລົງທະບຽນໃບໜ້າໃດ."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"ອຸປະກອນນີ້ບໍ່ມີເຊັນເຊີກວດສອບຄວາມຖືກຕ້ອງດ້ວຍໃບໜ້າ"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"ໃບໜ້າ <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"ໄອຄອນໃບໜ້າ"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"ອ່ານການຕັ້ງຄ່າຊິ້ງຂໍ້ມູນ"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"ອະນຸຍາດໃຫ້ແອັບຯ ອ່ານການຕັ້ງຄ່າການຊິ້ງຂໍ້ມູນຂອງບັນຊີໄດ້. ຕົວຢ່າງເຊັ່ນ: ມັນຈະສາມາດກວດສອບໄດ້ແອັບຯ People ຖືກຊິ້ງຂໍ້ມູນກັບບັນຊີໃດນຶ່ງແລ້ວຫຼືຍັງ."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ສະລັບການເປີດ ແລະປິດການຊິ້ງຂໍ້ມູນ"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi ບໍ່ມີສັນຍານອິນເຕີເນັດ"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ແຕະເພື່ອເບິ່ງຕົວເລືອກ"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"ການປ່ຽນແປງການຕັ້ງຄ່າຮັອດສະປອດຂອງທ່ານ"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"ຄື້ນຄວາມຖີ່ຮັອດສະປອດຂອງທ່ານປ່ຽນແປງແລ້ວ."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"ອຸປະກອນນີ້ບໍ່ຮອງຮັບການຕັ້ງຄ່າຂອງທ່ານສຳລັບ 5GHz ເທົ່ານັ້ນ. ແຕ່ວ່າອຸປະກອນນີ້ຈະໃຊ້ຄື້ນຄວາມຖີ່ 5GHz ເມື່ອສາມາດໃຊ້ໄດ້."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"ສະຫຼັບໄປໃຊ້ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ແລ້ວ"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"ອຸປະກອນຈະໃຊ້ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ເມື່ອ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ. ອາດມີການຮຽກເກັບຄ່າບໍລິການ."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"ສະຫຼັບຈາກ <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ໄປໃຊ້ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ແລ້ວ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index bd7a1f0..f396cca 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -282,6 +282,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Vietovė"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"pasiekti įrenginio vietovės informaciją"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Suteikti <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> galimybę pasiekti įrenginio vietovę?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Programa galės pasiekti vietovę, tik kai ją naudosite."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Visada leisti programai <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> pasiekti šio įrenginio vietovę?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Programa visada galės pasiekti vietovę, net kai jos nenaudosite."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalendorius"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"pasiekti kalendorių"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Suteikti <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> galimybę pasiekti kalendorių?"</string>
@@ -408,8 +411,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Ši programa gali pridėti, pašalinti arba pakeisti telefone esančius kalendoriaus įvykius. Ši programa gali siųsti pranešimus, kurie atrodys atsiųsti kalendoriaus savininkų, arba pakeisti įvykius nepranešusi jų savininkams."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"pasiekti papildomas vietos teikimo įrankio komandas"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Programai leidžiama pasiekti papildomas vietovės nustatymo paslaugų teikėjų komandas. Dėl to programa gali trukdyti veikti GPS ar kitiems vietovės nustatymo šaltiniams."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"pasiekti tikslią vietovę, tik kai programa veikia priekiniame plane"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Ši programa gali gauti tikslius jūsų vietovės duomenis bet kuriuo metu, kai veikia priekiniame plane. Šios vietovės paslaugos turi būti įjungtos ir pasiekiamos telefone, kad programa galėtų jas naudoti. Tai gali padidinti akumuliatoriaus energijos suvartojimą."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"pasiekti apytikslę vietą (nustatytą atsižvelgiant į tinklą)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Ši programa gali gauti jūsų vietos informaciją naudodamasi tinklo šaltinių, pvz., mobiliojo ryšio bokštų ir „Wi-Fi“ tinklų, duomenimis. Šios vietovės paslaugos turi būti įjungtos ir pasiekiamos planšetiniame kompiuteryje, kad programa galėtų jas naudoti."</string>
@@ -524,6 +526,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Kontrolinio kodo piktograma"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"tvarkyti veido autentifikavimo aparatinę įrangą"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Programai leidžiama aktyv. metodus, norint pridėti ir ištrinti naudojamus veidų šablonus."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"naudoti veido autentifikavimo aparatinę įrangą"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Programai leidžiama naudoti veido autentifikavimo aparatinę įrangą tapatybei nustatyti"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Nepavyko apdoroti veido. Bandykite dar kartą."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Veidas per šviesus. Band. sumažinti apšvietimą."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Veidas per tamsus. Atidenkite apšvietimo šaltinį."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Patraukite jutiklį toliau nuo veido."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Laikykite jutiklį arčiau veido."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Pakelkite jutiklį aukščiau."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Nuleiskite jutiklį žemiau."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Patraukite jutiklį dešinėn."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Patraukite jutiklį kairėn."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Žiūrėkite į jutiklį."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Neaptikta jokių veidų."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Stabiliai laikykite veidą prieš įrenginį."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Veido atpažinimo aparatinė įranga nepasiekiama."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Baigėsi veido atpaž. skirt. laik. Band. dar kartą."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Nepavyko išsaugoti veido duomenų."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Veido atpažinimo operacija atšaukta."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Per daug bandymų. Vėliau bandykite dar kartą."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Per daug bandymų. Veido autentifik. išjungtas."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Bandykite dar kartą."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Neužregistruota jokių veidų."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Šiame įrenginyje nėra veido autentifikavimo jutiklio"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"<xliff:g id="FACEID">%d</xliff:g> veidas"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Veido pkt."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"skaityti sinchronizavimo nustatymus"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Leidžiama programai skaityti ir sinchronizuoti paskyros nustatymus. Pvz., taip gali būti nustatoma, ar su paskyra sinchronizuota Žmonių programa."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"įjungti arba išjungti sinchronizavimą"</string>
@@ -1222,6 +1255,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"„Wi‑Fi“ tinkle nėra interneto ryšio"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Palieskite, kad būtų rodomos parinktys."</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Viešosios interneto prieigos taško nustatymų pakeitimai"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Viešosios prieigos taško dažnio juosta pasikeitė."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Šiame įrenginyje nepalaikoma tik 5 GHz nuostata. Vietoj to šiame įrenginyje bus naudojama 5 GHz dažnio juosta, kai bus pasiekiama."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Perjungta į tinklą <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Įrenginyje naudojamas kitas tinklas (<xliff:g id="NEW_NETWORK">%1$s</xliff:g>), kai dabartiniame tinkle (<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>) nėra interneto ryšio. Gali būti taikomi mokesčiai."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Perjungta iš tinklo <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> į tinklą <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 5f25162..da8644d 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -279,6 +279,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Atrašanās vieta"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"piekļūt ierīces atrašanās vietas informācijai"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Vai atļaut lietotnei <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> piekļūt šīs ierīces atrašanās vietai?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Lietotne varēs piekļūt atrašanās vietai tikai tad, kad izmantosiet šo lietotni."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Vienmēr atļaut <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> piekļūt atrašanās vietai?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Lietotne vienmēr varēs piekļūt atrašanās vietai, pat ja neizmantosiet šo lietotni."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalendārs"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"piekļūt jūsu kalendāram"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Vai atļaut lietotnei <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> piekļūt jūsu kalendāram?"</string>
@@ -405,8 +408,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Šī lietotne var pievienot, noņemt vai mainīt kalendāra pasākumus jūsu tālrunī. Šī lietotne var sūtīt ziņojumus, ko šķietami sūtījuši kalendāru īpašnieki, vai mainīt pasākumus, neinformējot to īpašniekus."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"piekļūt atrašanās vietas nodrošinātāja papildu komandām"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Ļauj lietotnei piekļūt papildu atrašanās vietas noteikšanas nodrošinātāju komandām. Tas var ļaut lietotnei traucēt GPS vai citu atrašanās vietas noteikšanas avotu darbību."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"piekļuve precīzai atrašanās vietai, tikai darbojoties priekšplānā"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Šī lietotne var iegūt precīzu jūsu atrašanās vietu, tikai darbojoties priekšplānā. Šiem atrašanās vietu pakalpojumiem ir jābūt ieslēgtiem un pieejamiem jūsu tālrunī, lai lietotne varētu tos izmantot. Tādējādi var palielināties akumulatora jaudas patēriņš."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"Piekļūt aptuvenai atrašanās vietai (izmantojot tīklu)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Šī lietotne var iegūt jūsu atrašanās vietu, pamatojoties uz tīkla avotiem, piemēram, mobilo sakaru torņiem un Wi-Fi tīkliem. Šiem atrašanās vietu pakalpojumiem ir jābūt ieslēgtiem un pieejamiem jūsu planšetdatorā, lai lietotne tos varētu izmantot."</string>
@@ -521,6 +523,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Pirksta nospieduma ikona"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"pārvaldīt sejas autentifikācijas aparatūru"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Atļauj lietotnei izsaukt metodes izmantojamo sejas veidņu pievienošanai un dzēšanai."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"izmantot sejas autentifikācijas aparatūru"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Atļauj lietotnei izmantot sejas autentifikācijas aparatūru autentificēšanai"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Nevarēja apstrādāt sejas datus. Mēģiniet vēlreiz."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Seja ir pārāk izgaismota. Mēģiniet tumšākā vidē."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Pārāk tumšs sejas attēls. Mēģiniet gaišākā vidē."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Pavirziet sensoru tālāk no sejas."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Pavirziet sensoru tuvāk sejai."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Pavirziet sensoru augstāk."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Pavirziet sensoru zemāk."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Pavirziet sensoru pa labi."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Pavirziet sensoru pa kreisi."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Lūdzu, paskatieties uz sensoru."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Nav atrasta neviena seja."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Turiet ierīci vērstu pret nekustīgu seju."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Sejas autentifikācijas aparatūra nav pieejama."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Sejas datu nolasīšanas noildze. Mēģiniet vēlreiz."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Sejas datus nevar saglabāt."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Darbība ar sejas datiem atcelta."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Pārāk daudz mēģinājumu. Vēlāk mēģiniet vēlreiz."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Par daudz mēģinājumu. Sejas atpazīšana atspējota."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Mēģiniet vēlreiz."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Nav reģistrēti sejas dati."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Šai ierīcei nav sejas autentifikācijas sensora."</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Seja <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Sejas ikona"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"lasīt sinhronizācijas iestatījumus"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Ļauj lietotnei lasīt konta sinhronizācijas iestatījumus. Piemēram, šādi var noteikt, vai lietotne Personas ir sinhronizēta ar kontu."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ieslēgt un izslēgt sinhronizāciju"</string>
@@ -1200,6 +1233,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi tīklā nav piekļuves internetam."</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Pieskarieties, lai skatītu iespējas."</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Izmaiņas tīklāja iestatījumos"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Ir mainīts tīklāja joslas platums."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Šajā ierīcē netiek atbalstīta jūsu preference par tikai 5 GHz joslu. 5 GHz josla ierīcē tiks izmantota, kad tā būs pieejama."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Pārslēdzās uz tīklu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Kad vienā tīklā (<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>) nav piekļuves internetam, ierīcē tiek izmantots cits tīkls (<xliff:g id="NEW_NETWORK">%1$s</xliff:g>). Var tikt piemērota maksa."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Pārslēdzās no tīkla <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> uz tīklu <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 07571efd..bc8cb07 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Локација"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"пристапува до локацијата на овој уред"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Дали да се дозволи <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> да пристапува до локацијата на уредот?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Апликацијата ќе има пристап до локацијата само додека ја користите."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Дозволете <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> секогаш да пристапува до локацијата?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Апликацијата секогаш ќе има пристап до локацијата, дури и кога не ја користите."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Календар"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"пристапува до календарот"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Дали да се дозволи <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> да пристапува до календарот?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Апликацијава може да додава, отстранува или менува настани во календарот на телефонот. Таа може да испраќа пораки што ќе изгледаат како да се испратени од сопствениците на календарот или да менува настани без да ги извести нивните сопственици."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"пристапи кон наредби на давателот на дополнителна локација"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Овозможува апликацијата да пристапи кон дополнителни наредби на давател на локација. Ова може да овозможи апликацијата да го попечи функционирањето на GPS или други извори на локација."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"пристап до прецизната локација само во преден план"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Апликацијава може да ја добие вашата точна локација само кога е во преден план. Услугиве според локација мора да се вклучени и достапни на телефонот за да може да ги користи апликацијата. Ова може да го зголеми трошењето на батеријата."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"пристап до приближната локација (врз база на мрежа)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Апликацијава може да ја добие вашата локација од мрежните извори како што се репетиторите за мобилни мрежи и Wi-Fi мрежите. Овие услуги за локација мора да се вклучени и достапни на таблетот за да може да ги користи апликацијата."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Икона за отпечатоци"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"управува со хардвер за проверка на лице"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Дозволува апликац. да повика начини за додавање и бришење шаблони на лице за користење."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"користи хардвер за проверка на лице"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Дозволува апликацијата да користи хардвер за лице за проверка"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Лицето не можеше да се обработи. Обидете се пак."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Лицето е пресветло. Пробајте на послаба светлина."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Лицето е претемно. Пробајте со поголема светлина."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Оддалечете го сензорот од лицето."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Доближете го сензорот до лицето."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Подигнете го сензорот."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Спуштете го сензорот."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Поместете го сензорот надесно."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Поместете го сензорот налево."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Погледнете во сензорот."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Не е откриено лице."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Држете го лицето стабилно пред уредот."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Хардверот за лице не е достапен."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Истече времето за проверка на лице. Повторен обид."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Лицето не може да се чува."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Операцијата со лице се откажа."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Премногу обиди. Обидете се повторно подоцна."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Премногу обиди. Проверката на лице е оневозможена."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Обидете се повторно."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Нема регистрирано лице."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Уредов нема сензор за проверка на лице"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Лице <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Икона за лице"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"чита поставки за синхронизација"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Овозможува апликацијата да ги чита поставките за синхронизирање на сметка. На пример, така може да се утврди дали апликацијата „Луѓе“ е синхронизирана со сметка."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"вклучи и исклучи синхронизација"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi нема пристап до интернет"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Допрете за опции"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Промени на поставките за точка на пристап"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Појасот за точка на пристап е променет."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Уредов не ги поддржува вашите поставки за само 5 GHz. Наместо тоа, ќе го користи појасот од 5 GHz кога е достапен."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Префрлено на <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Уредот користи <xliff:g id="NEW_NETWORK">%1$s</xliff:g> кога <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> нема пристап до интернет. Може да се наплатат трошоци."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Префрлено од <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 5bbddf9..3c89c2c 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"ലൊക്കേഷൻ"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"ഈ ഉപകരണത്തിന്റെ ലൊക്കേഷൻ ആക്സസ് ചെയ്യാൻ"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"ഈ ഉപകരണത്തിന്റെ ലൊക്കേഷൻ ആക്സസ് ചെയ്യാൻ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ആപ്പിനെ അനുവദിക്കണോ?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"നിങ്ങൾ ഉപയോഗിക്കുമ്പോൾ മാത്രം ആപ്പ് ലൊക്കേഷൻ ആക്സസ് ചെയ്യും."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"ഈ ഉപകരണത്തിന്റെ ലൊക്കേഷൻ ആക്സസ് ചെയ്യാൻ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> എപ്പോഴും ആപ്പിനെ അനുവദിക്കണോ?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"നിങ്ങൾ ആപ്പ് ഉപയോഗിക്കാത്തപ്പോൾ പോലും, ഏതുസമയത്തും ആപ്പ് ലൊക്കേഷൻ ആക്സസ് ചെയ്യും."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"കലണ്ടർ"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"നിങ്ങളുടെ കലണ്ടർ ആക്സസ്സ് ചെയ്യുക"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"നിങ്ങളുടെ കലണ്ടർ ആക്സസ് ചെയ്യാൻ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ആപ്പിനെ അനുവദിക്കണോ?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"ഈ ആപ്പിന്, നിങ്ങളുടെ ഫോണിൽ കലണ്ടർ ഇവന്റുകൾ ചേർക്കാനോ നീക്കംചെയ്യാനോ മാറ്റാനോ കഴിയും. കലണ്ടർ ഉടമകളിൽ നിന്നാണ് വരുന്നതെന്ന് തോന്നിപ്പിക്കാവുന്ന സന്ദേശങ്ങൾ അയയ്ക്കാനോ ഉടമകളെ അറിയിക്കാതെ അവരുടെ ഇവന്റുകളെ മാറ്റാനോ ഈ ആപ്പിന് കഴിയും."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"ലൊക്കേഷൻ ദാതാവിന്റെ അധിക കമാൻഡുകൾ ആക്സസ്സുചെയ്യുക"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"ലൊക്കേഷൻ ദാതാവിന്റെ അധിക കമാൻഡുകൾ ആക്സസ്സുചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഇത് GPS-ന്റെയോ മറ്റ് ലൊക്കേഷൻ ഉറവിടങ്ങളുടെയോ പ്രവർത്തനത്തിൽ ഇടപെടാൻ അപ്ലിക്കേഷനെ അനുവദിക്കാനിടയുണ്ട്."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"ഫോർഗ്രൗണ്ടിൽ മാത്രം കൃത്യമായ ലൊക്കേഷൻ ആക്സസ് ചെയ്യുക"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"ഫോർഗ്രൗണ്ടിൽ ഉള്ളപ്പോൾ മാത്രമേ ഈ ആപ്പിന് നിങ്ങളുടെ കൃത്യമായ ലൊക്കേഷൻ നേടാനാവൂ. ആപ്പിന് ഉപയോഗിക്കാനായി, ഈ ലൊക്കേഷൻ സേവനങ്ങൾ ഓണായിരിക്കുകയും നിങ്ങളുടെ ഫോണിൽ ലഭ്യമാവുകയും വേണം. ഇതിലൂടെ ബാറ്ററി ഉപഭോഗം വർദ്ധിച്ചേക്കാം."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"ഏകദേശ ലൊക്കേഷൻ (നെറ്റ്വർക്ക് അധിഷ്ഠിതം) ആക്സസ് ചെയ്യുക"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"സെൽ ടവറുകളും വൈഫൈ നെറ്റ്വർക്കുകളും പോലുള്ള നെറ്റ്വർക്ക് ഉറവിടങ്ങളെ അടിസ്ഥാനമാക്കിക്കൊണ്ട് ഈ ആപ്പിന് നിങ്ങളുടെ ലൊക്കേഷൻ അനുമാനിക്കാൻ കഴിയും. നിങ്ങളുടെ ടാബ്ലെറ്റിൽ ഈ ലൊക്കേഷൻ സേവനങ്ങൾ ഓൺ ചെയ്തിട്ടുണ്ടെങ്കിൽ മാത്രമാണ് ആപ്പിന് അവ ഉപയോഗിക്കാൻ കഴിയുക."</string>
@@ -518,6 +520,64 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"വിരലടയാള ഐക്കൺ"</string>
+ <!-- no translation found for permlab_manageFace (2137540986007309781) -->
+ <skip />
+ <!-- no translation found for permdesc_manageFace (8919637120670185330) -->
+ <skip />
+ <!-- no translation found for permlab_useFaceAuthentication (8996134460546804535) -->
+ <skip />
+ <!-- no translation found for permdesc_useFaceAuthentication (5011118722951833089) -->
+ <skip />
+ <!-- no translation found for face_acquired_insufficient (5901287247766106330) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_bright (610606792381297174) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_dark (7229162716976778371) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_close (1980310037427755293) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_far (4494571381828850007) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_high (228411096134808372) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_low (4539774649296349109) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_right (1650292067226118760) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_left (2712489669456176505) -->
+ <skip />
+ <!-- no translation found for face_acquired_poor_gaze (8344973502980415859) -->
+ <skip />
+ <!-- no translation found for face_acquired_not_detected (5707782294589511391) -->
+ <skip />
+ <!-- no translation found for face_acquired_not_steady (3722829465011040042) -->
+ <skip />
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <!-- no translation found for face_error_hw_not_available (6255891785768984615) -->
+ <skip />
+ <!-- no translation found for face_error_timeout (4014326147867150054) -->
+ <skip />
+ <!-- no translation found for face_error_no_space (8224993703466381314) -->
+ <skip />
+ <!-- no translation found for face_error_canceled (283945501061931023) -->
+ <skip />
+ <!-- no translation found for face_error_lockout (3407426963155388504) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_permanent (8198354656746088890) -->
+ <skip />
+ <!-- no translation found for face_error_unable_to_process (238761109287767270) -->
+ <skip />
+ <!-- no translation found for face_error_not_enrolled (9166792142679691323) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (4737289254517095671) -->
+ <skip />
+ <!-- no translation found for face_name_template (7004562145809595384) -->
+ <skip />
+ <string-array name="face_error_vendor">
+ </string-array>
+ <!-- no translation found for face_icon_content_description (4024817159806482191) -->
+ <skip />
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"സമന്വയ ക്രമീകരണങ്ങൾ റീഡുചെയ്യുക"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"ഒരു അക്കൗണ്ടിനായി സമന്വയ ക്രമീകരണങ്ങൾ റീഡുചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഉദാഹരണത്തിന്, ആളുകൾ അപ്ലിക്കേഷൻ ഒരു അക്കൗണ്ടിൽ സമന്വയിപ്പിച്ചിട്ടുണ്ടോയെന്നത് നിർണ്ണയിക്കാൻ ഇതിനാകും."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"സമന്വയം ഓണാക്കുക, ഓഫാക്കുക ടോഗിൾചെയ്യുക"</string>
@@ -1178,6 +1238,12 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"വൈഫൈയ്ക്ക് ഇന്റർനെറ്റ് ആക്സസ് ഇല്ല"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ഓപ്ഷനുകൾക്ക് ടാപ്പുചെയ്യുക"</string>
+ <!-- no translation found for wifi_softap_config_change (8475911871165857607) -->
+ <skip />
+ <!-- no translation found for wifi_softap_config_change_summary (7601233252456548891) -->
+ <skip />
+ <!-- no translation found for wifi_softap_config_change_detailed (8022936822860678033) -->
+ <skip />
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> എന്നതിലേക്ക് മാറി"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>-ന് ഇന്റർനെറ്റ് ആക്സസ് ഇല്ലാത്തപ്പോൾ ഉപകരണം <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ഉപയോഗിക്കുന്നു. നിരക്കുകൾ ബാധകമായേക്കാം."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> നെറ്റ്വർക്കിൽ നിന്ന് <xliff:g id="NEW_NETWORK">%2$s</xliff:g> നെറ്റ്വർക്കിലേക്ക് മാറി"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 96975ca..5caebe1 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Байршил"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"энэ төхөөрөмжийн байршилд хандалт хийх"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>-д энэ төхөөрөмжийн байршилд хандахыг зөвшөөрөх үү?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Та аппыг зөвхөн хэрэглэж байгаа үед апп нь байршилд хандах болно."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>-д энэ төхөөрөмжийн байршилд хандахыг байнга зөвшөөрөх үү?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Та энэ аппыг хэрэглээгүй байсан ч апп нь байршилд үргэлж хандах болно."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Хуанли"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"Хуанли руу хандах"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>-д таны календарьт хандахыг зөвшөөрөх үү?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Энэ апп таны утсанд хуанлийн арга хэмжээг нэмэх, устгах, эсвэл өөрчлөх боломжтой. Энэ апп нь хуанли эзэмшигчээс зурвас илгээсэн мэт харагдах, эсвэл эзэмшигчид мэдэгдэлгүйгээр арга хэмжээг өөрчлөх боломжтой."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"байршил нийлүүлэгчийн нэмэлт тушаалд хандах"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Апп нь байршил нийлүүлэгчийн нэмэлт тушаалд хандах боломжтой. Энэ нь апп-д GPS эсвэл бусад байршлын үйлчилгээний ажиллагаанд нөлөөлөх боломжийг олгоно."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"нарийвчилсан байршилд зөвхөн нүүр хэсэгт хандах"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Энэ апп нь зөвхөн нүүр хэсэгт байх үедээ л таны байршлыг нарийн тогтоох боломжтой. Апп эдгээр байршлын үйлчилгээг ашиглахын тулд эдгээрийг таны утсан дээр асааж идэвхтэй байлгах шаардлагатай. Энэ нь батарейны хэрэглээг ихэсгэж болзошгүй."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"ойролцоох байршилд хандах (сүлжээнд суурилсан)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Энэ апп үүрэн цамхаг, Wi-Fi сүлжээ зэрэг сүлжээний байршлын эх сурвалжийг ашиглан таны байршлыг мэдэх боломжтой. Эдгээр байршлын үйлчилгээ нь таны таблетад асаалттай байх ёстой ба апп ашиглах боломжтой байх ёстой."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Хурууны хээний дүрс"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"царай танилтын техник хангамжийг удирдах"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Аппад царайны загварыг ашиглахын тулд нэмэх эсвэл устгах аргыг идэвхжүүлэхийг зөвшөөрдөг."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"царай танилтын техник хангамжийг ашиглах"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Аппад царай танилтын техник хангамжийг баталгаажуулалтад ашиглахыг зөвшөөрдөг"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Царайг таньж чадсангүй. Дахин оролдоно уу."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Царай хэт цайвар байна. Гэрэл багатай газар оролдож үзнэ үү."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Царай хэт бараан байна. Гэрэлтэй газар туршиж үзнэ үү."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Мэдрэгчийг царайнаас холдуулна уу."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Mэдрэгчийг царайтай ойртуулна уу."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Мэдрэгчийг дээшлүүлнэ үү."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Mэдрэгчийг доошлуулна уу."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Мэдрэгчийг баруун тийш болгоно уу."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Мэдрэгчийг зүүн тийш болгоно уу."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Мэдрэгч рүү харна уу."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Царай олдсонгүй."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Царайг төхөөрөмжийн урд талд хөдөлгөөнгүй байлгана уу."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Царайны техник хангамж боломжгүй байна."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Царай таниулах хугацаа дууслаа. Дахин оролдоно уу."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Царайг хадгалах боломжгүй байна."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Царайны үйл ажиллагааг цуцаллаа."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Хэт олон удаа оролдлоо. Дараа дахин оролдоно уу."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Хэт олон удаа оролдлоо. Царай танилтыг идэвхгүй болголоо."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Дахин оролдоно уу."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Бүртгүүлсэн царай алга."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Энэ төхөөрөмжид царай таних мэдрэгч алга"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Царай <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Царайны дүрс тэмдэг"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"синк тохиргоог унших"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Апп нь бүртгэлийн синк тохиргоог унших боломжтой. Жишээ нь энэ нь Хүмүүс апп бүртгэлтэй синк хийгдсэн эсэхийг тодорхойлох боломжтой."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"синкийг унтрааж асаах тохиргоо"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi-д интернет хандалт алга"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Сонголт хийхийн тулд товшино уу"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Таны сүлжээний цэгийн тохиргооны өөрчлөлт"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Таны сүлжээний цэгийн зурвасыг өөрчилсөн."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Энэ төхөөрөмж таны \"зөвхөн 5Гц\" гэсэн давуу сонголтыг дэмждэггүй. Үүний оронд энэ төхөөрөмж 5Гц зурвасыг боломжтой үед нь ашиглах болно."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> руу шилжүүлсэн"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> интернет холболтгүй үед төхөөрөмж <xliff:g id="NEW_NETWORK">%1$s</xliff:g>-г ашигладаг. Төлбөр гарч болзошгүй."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>-с <xliff:g id="NEW_NETWORK">%2$s</xliff:g> руу шилжүүлсэн"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index fd7a67cc..206e0de 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"स्थान"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"या डिव्हाइसच्या स्थानावर प्रवेश"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ला या डिव्हाइसचे स्थान अॅक्सेस करू द्यायचे?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"तुम्ही अॅप वापरत असताना, अॅपला फक्त स्थानाचा अॅक्सेस असेल."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"या डिव्हाइसचे स्थान अॅक्सेस करण्याची <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ला नेहेमी अनुमती द्यायची का?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"तुम्ही अॅप वापरत नसलात तरीही, अॅपला स्थानाचा नेहेमी अॅक्सेस असेल."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"कॅलेंडर"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"आपल्या कॅलेंडरवर प्रवेश"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ला तुमचे कॅलेंडर अॅक्सेस करू द्यायचे?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"हा अॅप आपल्या फोनवर कॅलेंडर इव्हेंट जोडू, काढू किंवा बदलू शकतो. हा अॅप कॅलेंडर मालकांकडून येत आहेत असे वाटणारे मेसेज पाठवू किंवा त्यांच्या मालकांना सूचित केल्याशिवाय इव्हेंट बदलू शकतो."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"अतिरिक्त स्थान प्रदाता आदेश अॅक्सेस करा"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"अॅपला अतिरिक्त स्थान प्रदाता आदेशावर प्रवेश करण्याची अनुमती देते. हे कदाचित अॅपला GPS किंवा इतर स्थान स्त्रोत च्या ऑपरेशनमध्ये हस्तक्षेप करण्याची अनुमती देऊ शकते."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"फक्त फोरग्राउंडमध्ये अचूकपणे अॅक्सेस करा"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"हे अॅप फक्त फोरग्राउंडमध्ये असतानाच तुमचे अचूक स्थान मिळवू शकते. या स्थान सेवा सुरू करणे आणि त्या वापरण्यासाठी अॅपसाठी तुमच्या फोनवर उपलब्ध करणे आवश्यक आहे, यामुळे बॅटरी वापर वाढू शकतो."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"अंदाजे स्थानामध्ये (नेटवर्क-आधारित) अॅक्सेस करा"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"हा अॅप सेल टॉवर आणि वाय-फाय नेटवर्क सारख्या नेटवर्क स्रोतांच्या आधारावर तुमचे स्थान मिळवू शकतो. अॅपला या स्थान सेवा वापरण्यास सक्षम असण्यासाठी तुमच्या टॅब्लेटवर त्या चालू केलेल्या आणि उपलब्ध असणे आवश्यक आहे."</string>
@@ -518,6 +520,64 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"फिंगरप्रिंट आयकन"</string>
+ <!-- no translation found for permlab_manageFace (2137540986007309781) -->
+ <skip />
+ <!-- no translation found for permdesc_manageFace (8919637120670185330) -->
+ <skip />
+ <!-- no translation found for permlab_useFaceAuthentication (8996134460546804535) -->
+ <skip />
+ <!-- no translation found for permdesc_useFaceAuthentication (5011118722951833089) -->
+ <skip />
+ <!-- no translation found for face_acquired_insufficient (5901287247766106330) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_bright (610606792381297174) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_dark (7229162716976778371) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_close (1980310037427755293) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_far (4494571381828850007) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_high (228411096134808372) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_low (4539774649296349109) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_right (1650292067226118760) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_left (2712489669456176505) -->
+ <skip />
+ <!-- no translation found for face_acquired_poor_gaze (8344973502980415859) -->
+ <skip />
+ <!-- no translation found for face_acquired_not_detected (5707782294589511391) -->
+ <skip />
+ <!-- no translation found for face_acquired_not_steady (3722829465011040042) -->
+ <skip />
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <!-- no translation found for face_error_hw_not_available (6255891785768984615) -->
+ <skip />
+ <!-- no translation found for face_error_timeout (4014326147867150054) -->
+ <skip />
+ <!-- no translation found for face_error_no_space (8224993703466381314) -->
+ <skip />
+ <!-- no translation found for face_error_canceled (283945501061931023) -->
+ <skip />
+ <!-- no translation found for face_error_lockout (3407426963155388504) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_permanent (8198354656746088890) -->
+ <skip />
+ <!-- no translation found for face_error_unable_to_process (238761109287767270) -->
+ <skip />
+ <!-- no translation found for face_error_not_enrolled (9166792142679691323) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (4737289254517095671) -->
+ <skip />
+ <!-- no translation found for face_name_template (7004562145809595384) -->
+ <skip />
+ <string-array name="face_error_vendor">
+ </string-array>
+ <!-- no translation found for face_icon_content_description (4024817159806482191) -->
+ <skip />
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"सिंक सेटिंग्ज वाचा"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"खात्याच्या सिंक सेटिंग्ज वाचण्यासाठी अॅप ला अनुमती देते. उदाहरणार्थ, हे खात्यासह लोकांचा अॅप संकालित केला आहे किंवा नाही हे निर्धारित करू शकते."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"सिंक चालू आणि बंद करा टॉगल करा"</string>
@@ -1178,6 +1238,12 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"वाय-फाय ला इंटरनेटचा अॅक्सेस नाही"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"पर्यायांसाठी टॅप करा"</string>
+ <!-- no translation found for wifi_softap_config_change (8475911871165857607) -->
+ <skip />
+ <!-- no translation found for wifi_softap_config_change_summary (7601233252456548891) -->
+ <skip />
+ <!-- no translation found for wifi_softap_config_change_detailed (8022936822860678033) -->
+ <skip />
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> वर स्विच केले"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> कडे इंटरनेटचा अॅक्सेस नसताना डिव्हाइस <xliff:g id="NEW_NETWORK">%1$s</xliff:g> वापरते. शुल्क लागू शकते."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> वरून <xliff:g id="NEW_NETWORK">%2$s</xliff:g> वर स्विच केले"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index eba3d296..074d27b 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Lokasi"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"mengakses lokasi peranti ini"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Benarkan <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> mengakses lokasi peranti ini?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Apl ini hanya dapat mengakses lokasi semasa anda menggunakan apl tersebut."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Sentiasa benarkan <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> mengakses lokasi peranti ini?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Apl ini akan dapat mengakses lokasi pada sepanjang masa, meskipun apabila anda tidak menggunakan apl tersebut."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalendar"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"mengakses kalendar"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Benarkan <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> mengakses kalendar anda?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Apl ini boleh menambah, mengalih keluar atau mengubah acara kalendar pada telefon anda. Apl ini boleh menghantar mesej yang mungkin kelihatan seperti dihantar oleh pemilik kalendar atau mengubah acara tanpa memaklumi pemilik acara itu."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"akses perintah tambahan pembekal lokasi"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Membenarkan apl mengakses arahan pembekal lokasi tambahan. Ini boleh membenarkan apl untuk campur tangan dengan operasi GPS atau sumber lokasi lain."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"akses lokasi tepat hanya di latar depan"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Apl ini boleh mendapatkan lokasi tepat anda hanya apabila apl tersebut berada di latar depan. Perkhidmatan lokasi ini mesti dihidupkan dan tersedia pada telefon anda untuk membolehkan apl menggunakan perkhidmatan tersebut. Tindakan ini mungkin meningkatkan penggunaan bateri."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"akses lokasi anggaran (berasaskan rangkaian)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Apl ini boleh mendapatkan lokasi anda berdasarkan sumber rangkaian seperti menara selular dan rangkaian Wi-Fi. Perkhidmatan lokasi ini mesti dihidupkan dan tersedia pada tablet anda untuk membolehkan apl menggunakan perkhidmatan tersebut."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Ikon cap jari"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"urus perkakasan pengesahan wajah"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Membenarkan apl menggunakan kaedah untuk menambahkan dan memadamkan templat wajah untuk digunakan."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"gunakan perkakasan pengesahan wajah"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Membenarkan apl menggunakan perkakasan pengesahan wajah untuk pengesahan"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Tidak dapat memproses wajah. Sila cuba lagi."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Wajah terlalu cerah. Cuba dlm cahaya lebih rendah."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Wajah terlalu gelap. Sila buka sumber cahaya."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Sila alihkan penderia lebih jauh dari wajah."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Sila dekatkan penderia ke wajah."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Sila alihkan penderia ke kedudukan lebih tinggi."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Sila alihkan penderia ke kedudukan lebih rendah."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Sila alihkan penderia ke kanan."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Sila alihkan penderia ke kiri."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Sila lihat penderia."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Tiada wajah dikesan."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Pastikan wajah tidak bergerak di hadapan peranti."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Perkakasan wajah tidak tersedia."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Tamat masa wajah dicapai. Cuba lagi."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Wajah tidak dapat disimpan."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Pengendalian wajah dibatalkan."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Terlalu banyak percubaan. Cuba sebentar lagi."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Terlalu banyak percubaan. Pengesahan wajah dilumpuhkan."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Cuba lagi."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Tiada wajah didaftarkan."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Peranti ini tiada penderia pengesahan wajah"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Wajah <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Ikon wajah"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"membaca tetapan penyegerakan"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Membenarkan apl membaca tetapan segerak untuk akaun. Sebagai contoh, ini boleh menentukan sama ada apl Orang disegerakkan dengan akaun."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"togol segerak hidup dan mati"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi tiada akses Internet"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Ketik untuk mendapatkan pilihan"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Perubahan kepada tetapan tempat liputan anda"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Jalur tempat liputan anda telah berubah."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Peranti ini tidak menyokong pilihan anda untuk 5GHz sahaja. Sebaliknya, peranti ini akan menggunakan jalur 5GHz apabila tersedia."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Beralih kepada <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Peranti menggunakan <xliff:g id="NEW_NETWORK">%1$s</xliff:g> apabila <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tiada akses Internet. Bayaran mungkin dikenakan."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Beralih daripada <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> kepada <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 87ef1e5a..19bf212 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"တည်နေရာ"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"ဤစက်ပစ္စည်း၏ တည်နေရာကို ရယူရန်"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> အား ဤစက်ပစ္စည်း၏တည်နေရာကို သုံးခွင့်ပေးလိုပါသလား။"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"အက်ပ်ကိုအသုံးပြုသည့် အချိန်တွင်သာ ၎င်းကတည်နေရာကို အသုံးပြုခွင့်ရပါမည်။"</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> အား ဤစက်ပစ္စည်း၏တည်နေရာကို အမြဲ အသုံးပြုခွင့်ပေးလိုပါသလား။"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"သင် အက်ပ်ကိုအသုံးပြုမနေသော်လည်း ၎င်းကတည်နေရာကို အမြဲ အသုံးပြုခွင့်ရနေပါမည်။"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"ပြက္ခဒိန်"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"သင့်ပြက္ခဒိန်အား ဝင်ရောက်သုံးရန်"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> အား သင်၏ပြက္ခဒိန်ကို သုံးခွင့်ပေးလိုပါသလား။"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"ဤအက်ပ်သည် သင့်ဖုန်းပေါ်ရှိ ပြက္ခဒိန်ဖြစ်ရပ်များကို ထည့်ခြင်း၊ ဖယ်ရှားခြင်း သို့မဟုတ် ပြောင်းလဲခြင်းတို့ ပြုလုပ်နိုင်ပါသည်။ ဤအက်ပ်သည် ပြက္ခဒိန်ပိုင်ရှင်များမှ လာခြင်းဖြစ်နိုင်သည့် မက်ဆေ့ဂျ်များကို ပို့နိုင်ပြီး ပိုင်ရှင်များကို အသိမပေးဘဲ ဖြစ်ရပ်များကို ပြောင်းလဲနိုင်ပါသည်။"</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"တည်နေရာပံ့ပိုးမှုညွှန်ကြားချက်အပိုအား ဝင်ရောက်ကြည့်ခြင်း"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"အက်ပ်အား တည်နေရာ စီမံပေးရေး ညွှန်ကြားချက် အပိုများကို ရယူခွင့်ပြုသည်။ သို့ဖြစ်၍ အက်ပ်သည် GPS သို့မဟုတ် အခြား တည်နေရာ ရင်းမြစ်ကို သုံးကြသူတို့၏ လုပ်ငန်းများကို ဝင်စွက်ခွင့် ပြုနိုင်သည်။"</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"မျက်နှာစာတွင်သာ တည်နေရာအတိအကျ အသုံးပြုခြင်း"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"မျက်နှာစာတွင် ဖွင့်ထားမှသာ ဤအက်ပ်က သင်၏တည်နေရာအတိအကျကို ရယူနိုင်ပါသည်။ သင်၏ဖုန်းတွင် အက်ပ်ကအသုံးပြုရန်အတွက် ဤတည်နေရာဝန်ဆောင်မှုများကို ဖွင့်ထားပြီး အသုံးပြု၍ ရပါမည်။ ၎င်းက ဘက်ထရီ ပိုကုန်နိုင်ပါသည်။"</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"အနီးစပ်ဆုံး တည်နေရာ (ကွန်ရက် အခြေခံ)ကို ရယူသုံးရန်"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"ဤအက်ပ်သည် ဆဲလ်တာဝါများနှင့် Wi-Fi ကွန်ရက်များကဲ့သို့ ကွန်ရက်အရင်းအမြစ်ပေါ် အခြေခံပြီး သင့်တည်နေရာအချက်အလက်ကို ရယူနိုင်ပါသည်။ အက်ပ်က အသုံးပြုနိုင်ရန်အတွက် ဤတည်နေရာ ဝန်ဆောင်မှုများကို ဖွင့်ထားရမည် ဖြစ်ပြီး သင့်တက်ဘလက်ပေါ်တွင် ရရှိနိုင်ရပါမည်။"</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"လက်ဗွေ အိုင်ကွန်"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"မျက်နှာအထောက်အထားစိစစ်ခြင်း စက်ပစ္စည်းကို စီမံပါ"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"အသုံးပြုရန်အတွက် မျက်နှာပုံစံထည့်ရန် (သို့) ဖျက်ရန်နည်းလမ်းကို အက်ပ်အားသုံးခွင့်ပြုသည်။"</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"မျက်နှာအထောက်အထားစိစစ်ခြင်း စက်ပစ္စည်းကို သုံးပါ"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"အထောက်အထားစိစစ်ရန်အတွက် ဤအက်ပ်အား မျက်နှာအထောက်အထားစိစစ်ခြင်း စက်ပစ္စည်းကိုသုံးခွင့်ပြုသည်"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"မျက်နှာကို မဆောင်ရွက်နိုင်ပါ။ ထပ်လုပ်ကြည့်ပါ။"</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"မျက်နှာအလွန်လင်းနေသည်။ အလင်းနည်းနည်းတွင်ထပ်စမ်းပါ။"</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"မျက်နှာအလွန်မှောင်နေသည်။ ပြတင်းပေါက်ဖွင့်လိုက်ပါ။"</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"အာရုံခံကိရိယာကို မျက်နှာနှင့် ခွာလိုက်ပါ။"</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"အာရုံခံကိရိယာကို မျက်နှာနှင့် ကပ်လိုက်ပါ။"</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"အာရုံခံကိရိယာကို ပိုမြင့်အောင်ထားပါ။"</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"အာရုံခံကိရိယာကို ပိုနိမ့်အောင်ထားပါ။"</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"အာရုံခံကိရိယာကို ညာဘက်သို့ ရွှေ့ပါ။"</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"အာရုံခံကိရိယာကို ဘယ်ဘက်သို့ ရွှေ့ပါ။"</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"အာရုံခံကိရိယာကို ကြည့်ပါ။"</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"မျက်နှာတစ်ခုမျှ မတွေ့ပါ။"</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"မျက်နှာကို စက်ပစ္စည်း၏ အရှေ့တွင် အဆင်သင့်ထားပါ။"</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"မျက်နှာ စက်ပစ္စည်း မရနိုင်ပါ။"</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"မျက်နှာ သက်တမ်းကုန်သွားပါပြီ။ ထပ်စမ်းကြည့်ပါ။"</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"မျက်နှာကို သိုလှောင်၍မရပါ။"</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"မျက်နှာ ဆောင်ရွက်ခြင်းကို ပယ်ဖျက်လိုက်ပါပြီ။"</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"အကြိမ်များစွာ စမ်းပြီးပါပြီ။ နောက်မှထပ်စမ်းပါ။"</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"အကြိမ်များစွာ စမ်းပြီးပါပြီ။ ပိတ်လိုက်ပါပြီ။"</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"ထပ်စမ်းကြည့်ပါ။"</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"စာရင်းသွင်းထားသည့် မျက်နှာတစ်ခုမျှ မရှိပါ။"</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"ဤစက်တွင် မျက်နှာအထောက်အထားစိစစ်ခြင်း အာရုံခံကိရိယာမရှိပါ"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"မျက်နှာ <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"မျက်နှာသင်္ကေတ"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"ထပ်တူပြုအဆင်အပြင်အားဖတ်ခြင်း"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"အပလီကေးရှင်းအား အကောင့်တစ်ခုအတွက် ထပ်တူညီအောင် လုပ်ဆောင်မှု ဆက်တင်အား ကြည့်ခွင့် ပြုပါ။ ဥပမာ People အက်ပ်က အကောင့်တစ်ခုနဲ့ ထပ်တူညီအောင် လုပ်ရန် ဆက်သွယ်ထားမှု ရှိမရှိ သိရှိနိုင်ခြင်း"</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ထပ်တူညီအောင် လုပ်ခြင်းအား ပြုနိုင်၊ မပြုနိုင် အပြောင်းအလဲလုပ်ခြင်း"</string>
@@ -569,7 +602,7 @@
<string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"DRM လက်မှတ်များကို ရယူသုံးခြင်း"</string>
<string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"အပလီကေးရှင်းတစ်ခုအား စီမံလုပ်ကိုင်ခွင့် DRM လက်မှတ်များ သုံးခွင့် ပြုသည်။ သာမန် အက်ပ်များ အတွက် ဘယ်တော့မှ မလိုအပ်နိုင်ပါ။"</string>
<string name="permlab_handoverStatus" msgid="7820353257219300883">"Android ရဲ့ အလင်းတန်းထိုး လွှဲပြောင်းမှု အခြေအနေကို ရယူရန်"</string>
- <string name="permdesc_handoverStatus" msgid="4788144087245714948">"ဒီအပလီကေးရှင်းအား အန်ဒရွိုက်၏ လက်ရှိ အလင်းတန်းထိုး လွှဲပြောင်းမှု အကြောင်း အချက်အလက်ကို ရယူခွင့် ပြုသည်"</string>
+ <string name="permdesc_handoverStatus" msgid="4788144087245714948">"ဒီအပလီကေးရှင်းအား Android၏ လက်ရှိ အလင်းတန်းထိုး လွှဲပြောင်းမှု အကြောင်း အချက်အလက်ကို ရယူခွင့် ပြုသည်"</string>
<string name="permlab_removeDrmCertificates" msgid="7044888287209892751">"DRM လက်မှတ်များ ဖယ်ရှားရန်"</string>
<string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"အပလီကေးရှင်းအား DRM လက်မှတ်များကို ဖယ်ရှားခွင့် ပြုသည်။ သာမန် အက်ပ်များ အတွက် ဘယ်တော့မှ မလိုအပ်နိုင်ပါ။"</string>
<string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"စာပို့စာယူ ဆက်သွယ်ရေးဝန်ဆောင်မှုတစ်ခုအား ပူးပေါင်းခွင့်ပြုရန်"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi တွင် အင်တာနက်ချိတ်ဆက်မှု မရှိပါ"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"အခြားရွေးချယ်စရာများကိုကြည့်ရန် တို့ပါ"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"သင်၏ဟော့စပေါ့ ဆက်တင်များ ပြောင်းလဲမှု"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"သင်၏ ဟော့စပေါ့လိုင်း ပြောင်းသွားပါပြီ။"</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"ဤစက်ပစ္စည်းသည် သင်၏ 5GHz သီးသန့်ရွေးချယ်မှုအတွက် ပံ့ပိုးမထားပါ။ ၎င်းအစား ဤစက်ပစ္စည်းသည် ရနိုင်သည့်အခါ 5GHz လိုင်းကို သုံးသွားပါမည်။"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> သို့ ပြောင်းလိုက်ပြီ"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ဖြင့် အင်တာနက် အသုံးမပြုနိုင်သည့်အချိန်တွင် စက်ပစ္စည်းသည် <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ကို သုံးပါသည်။ ဒေတာသုံးစွဲခ ကျသင့်နိုင်ပါသည်။"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> မှ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> သို့ ပြောင်းလိုက်ပြီ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 759cbaa..4f643fc 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Posisjon"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"få tilgang til enhetens plassering"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Vil du gi <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> tilgang til denne enhetens posisjon?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Appen får bare tilgang til posisjonen når du bruker appen."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Vil du alltid gi <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> tilgang til denne enhetens posisjon?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Appen får alltid tilgang til posisjonen, selv når du ikke bruker appen."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalender"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"åpne kalenderen din"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Vil du gi <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> tilgang til kalenderen din?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Denne appen kan legge til, fjerne eller endre kalenderaktiviteter på telefonen din. Denne appen kan sende meldinger som kan virke som om kommer fra kalendereiere, eller endre aktiviteter uten at eierne blir varslet."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"bruke ekstra posisjonskommandoer"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Appen gis tillatelse til å bruke ekstra kommandoer fra posisjonsleverandører. Dette kan gi appen tillatelse til å påvirke bruken av GPS eller andre posisjonskilder."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"bare tilgang til nøyaktig posisjon i forgrunnen"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Denne appen kan bare få den nøyaktige posisjonen din når den er på i forgrunnen. Disse posisjonstjenestene må være slått på og tilgjengelige på telefonen din for at appen skal kunne bruke dem. Dette kan øke batteriforbruket."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"få tilgang til omtrentlig posisjon (nettverksbasert)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Denne appen kan få posisjonen din fra nettverkskilder som mobilmaster og Wi-Fi-nettverk. Disse posisjonstjenestene må være slått på og tilgjengelige på nettbrettet ditt for at appen skal kunne bruke dem."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Ikon for fingeravtrykk"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"administrere maskinvare for ansiktsautentisering"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Lar appen bruke metoder for å legge til og slette ansiktmaler for bruk."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"bruke maskinvare for ansiktsautentisering"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Lar appen bruke maskinvare for ansiktsautentisering til autentisering"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Kunne ikke behandle ansiktet. Prøv igjen."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Ansiktet er for lyst. Prøv med svakere lys."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Ansiktet er for mørkt. Bruk en lyskilde."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Flytt sensoren lengre vekk fra ansiktet."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Hold sensoren nærmere ansiktet."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Flytt sensoren opp."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Flytt sensoren ned."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Flytt sensoren til høyre."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Flytt sensoren til venstre."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Se på sensoren."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Ingen ansikter er oppdaget."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Hold ansiktet stødig foran enheten."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Maskinvare for ansikt er ikke tilgjengelig."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Tidsavbrudd for ansikt er nådd. Prøv igjen."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Ansiktet kan ikke lagres."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Ansikt-operasjonen ble avbrutt."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"For mange forsøk. Prøv igjen senere."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"For mange forsøk. Ansiktsautentisering er slått av."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Prøv igjen."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Ingen ansikt er registrert."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Denne enheten har ikke sensor for ansiktsautentisering"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Ansikt <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Ansiktikon"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"lese synkroniseringsinnstillinger"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Lar appen lese synkroniseringsinnstillingene for en konto. For eksempel kan den finne ut om Personer-appen er synkronisert med en konto."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"slå synkronisering av og på"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi har ikke Internett-tilgang"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Trykk for å få alternativer"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Endres til innstillingene dine for Wi-Fi-soner"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Båndet ditt for Wi-Fi-sone er endret."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Denne enheten støtter ikke innstillingen din for bare 5 GHz. I stedet bruker enheten 5 GHz-båndet når det er tilgjengelig."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Byttet til <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Enheten bruker <xliff:g id="NEW_NETWORK">%1$s</xliff:g> når <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ikke har Internett-tilgang. Avgifter kan påløpe."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Byttet fra <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> til <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index b8b0256..6d1c926 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"स्थान"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"यस यन्त्रको स्थानमाथि पहुँच"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> लाई यो यन्त्रको स्थानमाथि पहुँच राख्न दिने हो?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"तपाईं उक्त अनुप्रयोग प्रयोग गरिरहेका बेलामा त्यससँग स्थानमाथिको पहुँच रहने छ।"</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> लाई यो यन्त्रको स्थानमाथि पहुँच राख्न दिने हो?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"तपाईं उक्त अनुप्रयोग प्रयोग नगरिरहेका बेलामा पनि त्यससँग स्थानमाथिको पहुँच रहने छ।"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"पात्रो"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"तपाईंको पात्रोमाथि पहुँच गर्नुहोस्"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> लाई आफ्नो पात्रोमाथि पहुँच राख्न दिने हो?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"यस अनुप्रयोगले तपाईंको फोनमा पात्रोका कार्यक्रमहरू थप्न, हटाउन वा परिवर्तन गर्न सक्छ। यस अनुप्रयोगले पात्रोका मालिकहरू मार्फत आएको जस्तो लाग्ने सन्देशहरू पठाउन वा तिनीहरूका मालिकहरूलाई सूचित नगरिकन कार्यक्रमहरू परिवर्तन गर्न सक्छ।"</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"अधिक स्थान प्रदायक आदेशहरू पहुँच गर्नुहोस्"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"अनुप्रयोगलाई अतिरिक्त स्थान प्रदायक आदेशहरू पहुँच गर्न अनुमति दिन्छ। यो अनुप्रयोगलाई GPS वा अन्य स्थान स्रोतहरूको संचालन साथै हस्तक्षेप गर्न अनुमति दिन सक्छ।"</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"अग्रभूमिमा मात्र सटीक स्थानमाथि पहुँच राख्नुहोस्"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"यो अनुप्रयोगले अग्रभागमा चलिरहेको अवस्थामा मात्र तपाईंलाई स्थानको सटिक जानकारी दिन सक्छ। यी स्थानसम्बन्धी सेवाहरू अनिवार्य रूपमा सक्रिय गरिएका हुनु पर्छ र अनुप्रयोगले यिनीहरूको प्रयोग गर्न सकोस् भन्नाका खातिर तपाईंको फोनमै उपलब्ध हुन्छन्। यस कार्यले गर्दा ब्याट्री बढी खर्च हुन सक्छ।"</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"अनुमानित स्थान पहुँच गराउनुहोस् (नेटवर्कमा आधारित)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"यस अनुप्रयोगले सेलका टावर र Wi-Fi नेटवर्कहरू जस्ता नेटवर्कका स्रोतहरूको आधारमा तपाईंको स्थान बारे जानकारी प्राप्त गर्न सक्छ। यो अनुप्रयोग ती स्रोतहरूको प्रयोग गर्न सक्षम होस् भन्नका खातिर यी स्थान सम्बन्धी सेवाहरूलाई अनिवार्य रूपमा सक्रिय पार्नुपर्छ र यी तपाईंको ट्याब्लेटमा उपलब्ध हुनु पर्छ।"</string>
@@ -518,6 +520,64 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"फिंगरप्रिन्ट आइकन"</string>
+ <!-- no translation found for permlab_manageFace (2137540986007309781) -->
+ <skip />
+ <!-- no translation found for permdesc_manageFace (8919637120670185330) -->
+ <skip />
+ <!-- no translation found for permlab_useFaceAuthentication (8996134460546804535) -->
+ <skip />
+ <!-- no translation found for permdesc_useFaceAuthentication (5011118722951833089) -->
+ <skip />
+ <!-- no translation found for face_acquired_insufficient (5901287247766106330) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_bright (610606792381297174) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_dark (7229162716976778371) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_close (1980310037427755293) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_far (4494571381828850007) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_high (228411096134808372) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_low (4539774649296349109) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_right (1650292067226118760) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_left (2712489669456176505) -->
+ <skip />
+ <!-- no translation found for face_acquired_poor_gaze (8344973502980415859) -->
+ <skip />
+ <!-- no translation found for face_acquired_not_detected (5707782294589511391) -->
+ <skip />
+ <!-- no translation found for face_acquired_not_steady (3722829465011040042) -->
+ <skip />
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <!-- no translation found for face_error_hw_not_available (6255891785768984615) -->
+ <skip />
+ <!-- no translation found for face_error_timeout (4014326147867150054) -->
+ <skip />
+ <!-- no translation found for face_error_no_space (8224993703466381314) -->
+ <skip />
+ <!-- no translation found for face_error_canceled (283945501061931023) -->
+ <skip />
+ <!-- no translation found for face_error_lockout (3407426963155388504) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_permanent (8198354656746088890) -->
+ <skip />
+ <!-- no translation found for face_error_unable_to_process (238761109287767270) -->
+ <skip />
+ <!-- no translation found for face_error_not_enrolled (9166792142679691323) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (4737289254517095671) -->
+ <skip />
+ <!-- no translation found for face_name_template (7004562145809595384) -->
+ <skip />
+ <string-array name="face_error_vendor">
+ </string-array>
+ <!-- no translation found for face_icon_content_description (4024817159806482191) -->
+ <skip />
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"समीकरण सेटिङहरू पढ्नुहोस्"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"अनुप्रयोगलाई खाताको लागि सिंक सेटिङहरू पढ्न अनुमति दिन्छ। उदाहरणको लागि यसले व्यक्तिहरको अनुप्रयोग खातासँग सिंक भएको नभएको निर्धारण गर्न सक्दछ।"</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"टगल सिंक खुला र बन्द"</string>
@@ -1184,6 +1244,12 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi मार्फत इन्टरनेटमाथि पहुँच राख्न सकिँदैन"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"विकल्पहरूका लागि ट्याप गर्नुहोस्"</string>
+ <!-- no translation found for wifi_softap_config_change (8475911871165857607) -->
+ <skip />
+ <!-- no translation found for wifi_softap_config_change_summary (7601233252456548891) -->
+ <skip />
+ <!-- no translation found for wifi_softap_config_change_detailed (8022936822860678033) -->
+ <skip />
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> मा बदल्नुहोस्"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> मार्फत इन्टरनेटमाथि पहुँच राख्न नसकेको अवस्थामा यन्त्रले <xliff:g id="NEW_NETWORK">%1$s</xliff:g> प्रयोग गर्दछ। शुल्क लाग्न सक्छ।"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> बाट <xliff:g id="NEW_NETWORK">%2$s</xliff:g> मा परिवर्तन गरियो"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 05f0f3f..15f9dd0 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Locatie"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"de locatie van dit apparaat openen"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> toegang geven tot de locatie van dit apparaat?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"De app heeft alleen toegang tot de locatie wanneer je de app gebruikt."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> altijd toegang geven tot de locatie van dit apparaat?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"De app heeft altijd toegang tot de locatie, ook wanneer je de app niet gebruikt."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Agenda"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"toegang krijgen tot je agenda"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> toegang geven tot je agenda?"</string>
@@ -287,13 +290,13 @@
<string name="permgrouprequest_storage" msgid="7885942926944299560">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> toegang geven tot foto\'s, media en bestanden op je apparaat?"</string>
<string name="permgrouplab_microphone" msgid="171539900250043464">"Microfoon"</string>
<string name="permgroupdesc_microphone" msgid="4988812113943554584">"audio opnemen"</string>
- <string name="permgrouprequest_microphone" msgid="9167492350681916038">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> het volgende toestaan: audio opnemen."</string>
+ <string name="permgrouprequest_microphone" msgid="9167492350681916038">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> toestaan om audio op te nemen?"</string>
<string name="permgrouplab_camera" msgid="4820372495894586615">"Camera"</string>
<string name="permgroupdesc_camera" msgid="3250611594678347720">"foto\'s maken en video opnemen"</string>
<string name="permgrouprequest_camera" msgid="1299833592069671756">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> toestaan om foto\'s te maken en video op te nemen?"</string>
<string name="permgrouplab_calllog" msgid="8798646184930388160">"Gesprekkenlijsten"</string>
<string name="permgroupdesc_calllog" msgid="3006237336748283775">"gesprekkenlijst lezen en schrijven"</string>
- <string name="permgrouprequest_calllog" msgid="8487355309583773267">"Wil je <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> toegang tot je gesprekkenlijsten geven?"</string>
+ <string name="permgrouprequest_calllog" msgid="8487355309583773267">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> toegang geven tot je gesprekkenlijsten?"</string>
<string name="permgrouplab_phone" msgid="5229115638567440675">"Telefoon"</string>
<string name="permgroupdesc_phone" msgid="6234224354060641055">"telefoneren en oproepen beheren"</string>
<string name="permgrouprequest_phone" msgid="9166979577750581037">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> toestaan om telefoongesprekken te starten en te beheren?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Deze app kan agenda-afspraken toevoegen, verwijderen of wijzigen op je telefoon. Deze app kan berichten verzenden die afkomstig lijken te zijn van agenda-eigenaren of afspraken aanpassen zonder dit aan de eigenaar te melden."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"toegang tot extra opdrachten van locatieaanbieder"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Hiermee kan de app toegang krijgen tot extra opdrachten voor de locatieprovider. De app kan hiermee de werking van gps of andere locatiebronnen te verstoren."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"alleen toegang tot precieze locatie op de voorgrond"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Deze app kan je exacte locatie ophalen wanneer de app op de voorgrond wordt uitgevoerd. De app kan alleen gebruikmaken van deze locatieservices als ze zijn ingeschakeld en beschikbaar zijn op je telefoon. Hierdoor kan het batterijverbruik toenemen."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"toegang tot geschatte locatie (netwerkgebaseerd)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Deze app kan je locatie ophalen op basis van netwerkbronnen zoals zendmasten en wifi-netwerken. De app kan alleen gebruikmaken van deze locatieservices als ze zijn ingeschakeld en beschikbaar zijn op je tablet."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Vingerafdruk-pictogram"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"hardware voor gezichtsherkenning beheren"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Hiermee kan de app methoden aanroepen om gezichtstemplates toe te voegen en te verwijderen voor gebruik."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"hardware voor gezichtsherkenning gebruiken"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Hiermee kan de app hardware voor gezichtsherkenning gebruiken voor verificatie"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Kan gezicht niet verwerken. Probeer het opnieuw."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Gezicht is te helder. Probeer bij minder licht."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Gezicht is te donker. Laat meer licht toe."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Houd de sensor verder weg van je gezicht."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Houd de sensor dichter bij je gezicht."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Beweeg de sensor omhoog."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Beweeg de sensor omlaag."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Beweeg de sensor naar rechts."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Beweeg de sensor naar links."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Kijk naar de sensor."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Geen gezicht gedetecteerd."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Houd het gezicht stil voor het apparaat."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Hardware voor gezichtsherkenning niet beschikbaar."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Time-out voor gezicht bereikt. Probeer opnieuw."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Gezicht kan niet worden opgeslagen."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Bewerking voor gezichtsherkenning geannuleerd."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Te veel pogingen. Probeer het later opnieuw."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Te veel pogingen. Gezichtsherkenning inactief."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Probeer het opnieuw."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Geen gezicht geregistreerd."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Dit apparaat heeft geen sensor voor gezichtsherkenning"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Gezicht <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Gezichtspictogram"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"synchronisatie-instellingen lezen"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Hiermee kan de app de synchronisatie-instellingen voor een account lezen. Dit kan bijvoorbeeld bepalen of de app Personen wordt gesynchroniseerd met een account."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"synchronisatie in- en uitschakelen"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wifi-netwerk heeft geen internettoegang"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tik voor opties"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Wijzigingen in je hotspot-instellingen"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Je hotspot-band is gewijzigd."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Dit apparaat biedt geen ondersteuning voor je voorkeur voor alleen 5 GHz. In plaats daarvan gebruikt dit apparaat de 5-GHz-band wanneer deze beschikbaar is."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Overgeschakeld naar <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Apparaat gebruikt <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wanneer <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> geen internetverbinding heeft. Er kunnen kosten in rekening worden gebracht."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Overgeschakeld van <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> naar <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1553,7 +1589,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt u gevraagd je telefoon te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%3$d</xliff:g> seconden opnieuw."</string>
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Verwijderen"</string>
- <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Volume verhogen tot boven het aanbevolen niveau?\n\nAls u langere tijd op hoog volume naar muziek luistert, raakt je gehoor mogelijk beschadigd."</string>
+ <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Volume verhogen tot boven het aanbevolen niveau?\n\nAls je langere tijd op hoog volume naar muziek luistert, raakt je gehoor mogelijk beschadigd."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="8404780875025725199">"Sneltoets voor toegankelijkheid gebruiken?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Wanneer de snelkoppeling is ingeschakeld, kun je drie seconden op beide volumeknoppen drukken om een toegankelijkheidsfunctie te starten.\n\n Huidige toegankelijkheidsfunctie:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Je kunt de functie wijzigen in Instellingen > Toegankelijkheid."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Sneltoets uitschakelen"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index ad9c659..bf26de0 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"ଲୋକେଶନ୍"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"ଏହି ଡିଭାଇସ୍ର ଲୋକେଶନ୍ ଆକ୍ସେସ୍ କରେ"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>କୁ ଏହି ଡିଭାଇସ୍ର ଲୋକେଶନ୍ ଆକ୍ସେସ୍ କରିବା ପାଇଁ ଅନୁମତି ଦେବେ କି?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"ଆପଣ ଆପ୍ ବ୍ୟବହାର କରୁଥିବା ବେଳେ କେବଳ ଲୋକେସନ୍କୁ ଆପ୍ର ଆକ୍ସେସ୍ ରହିବ।"</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"ସଦାବେଳେ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b>କୁ ଏହି ଡିଭାଇସ୍ର ଲୋକେସନ୍ ଆକ୍ସେସ୍ କରିବା ପାଇଁ ଅନୁମତି ଦେବେ କି?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"ଆପଣ ଆପ୍ ବ୍ୟବହାର କରୁନଥିଲେ ମଧ୍ୟ, ଲୋକେସନ୍କୁ ସଦାବେଳେ ଆପ୍ର ଆକ୍ସେସ୍ ରହିବ।"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"କ୍ୟାଲେଣ୍ଡର୍"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"ଆପଣଙ୍କ କ୍ୟାଲେଣ୍ଡର୍ ଆକ୍ସେସ୍ କରେ"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>କୁ ଆପଣଙ୍କ କ୍ୟାଲେଣ୍ଡର୍କୁ ଆକ୍ସେସ୍ କରିବା ପାଇଁ ଅନୁମତି ଦେବେ କି?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"ଏହି ଆପ୍, ଆପଣଙ୍କ ଫୋନ୍ରେ କ୍ୟାଲେଣ୍ଡର୍ ଇଭେଣ୍ଟଗୁଡ଼ିକୁ ଯୋଡ଼ିପାରେ, ବାହାର କରିପାରେ କିମ୍ବା ବଦଳାଇପାରେ। କ୍ୟାଲେଣ୍ଡର୍ ମାଲିକଙ୍କ ପାଖରୁ ଆସିଥିବା ପରି ଜଣାପଡ଼ିବା ମେସେଜ୍କୁ ଏହି ଆପ୍ ପଠାଇପାରେ କିମ୍ବା ମାଲିକଙ୍କୁ ନଜଣାଇ ଇଭେଣ୍ଟ ବଦଳାଇପାରେ।"</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"ଅତିରିକ୍ତ ଲୋକେଶନ୍ ପ୍ରଦାନକାରୀ କମାଣ୍ଡକୁ ଆକ୍ସେସ୍ କରନ୍ତୁ"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"ଅତିରିକ୍ତ ଲୋକେଶନ୍ ପ୍ରଦାନକାରୀ କମାଣ୍ଡ ଆକ୍ସେସ୍ କରିବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦିଏ। GPS କିମ୍ବା ଅନ୍ୟ ଲୋକେଶନ୍ ସୋର୍ସଗୁଡିକରେ ଆପ୍ଟି ପ୍ରଭାବ ପକାଇପାରେ।"</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"କେବଳ ସମ୍ମୁଖଭାଗରେ ସଠିକ୍ ଲୋକେଶନ୍ର ଆକ୍ସେସ୍ କରନ୍ତୁ"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"ଏହି ଆପ୍ ଯେତେବେଳେ ସମ୍ମୁଖଭାଗରେ ଥିବାବେଳେ ଆପଣଙ୍କର ସଠିକ୍ ଲୋକେଶନ୍ ପ୍ରାପ୍ତ କରିପାରିବ। ଏହି ଲୋକେଶନ୍ ସେବାଗୁଡ଼ିକ ନିଶ୍ଚିତରୂପେ ଅନ୍ ରହିବା ଦରକାର ଏବଂ ଆପ୍ର ବ୍ୟବହାର ପାଇଁ ଫୋନ୍ରେ ଉପଲବ୍ଧ ଥିବା ଦରକାର। ଏହା ବ୍ୟାଟେରୀ ଅଧିକା ଖର୍ଚ୍ଚ କରିପାରେ।"</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"ପାଖାପାଖି ଲୋକେଶନ୍ ଆକ୍ସେସ୍ କରେ (ନେଟ୍ୱର୍କ-ଆଧାରିତ)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"ଏହି ଆପ୍, ନେଟ୍ୱର୍କ ସୋର୍ସ ଉପରେ ଆଧାର କରି ଆପଣଙ୍କ ଲୋକେଶନ୍ ପ୍ରାପ୍ତ କରିପାରେ, ଯେପରିକି ସେଲ୍ ଟାୱାର୍ ଓ ୱାଇ-ଫାଇ ନେଟ୍ୱର୍କ। ଏହି ଲୋକେଶନ୍ ସେବା, ଆପଣଙ୍କ ଟାବଲେଟ୍ରେ ଅନ୍ ରହିଥିବା ଓ ଉପଲବ୍ଧ ଥିବା ଦରକାର, ଯେଉଁଥିରୁ ଆପ୍ ସେଗୁଡ଼ିକର ବ୍ୟବହାର କରିପାରିବ।"</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ଆଇକନ୍"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"ଫେସ୍ ପ୍ରମାଣୀକରଣ ହାର୍ଡୱେର୍ର ପରିଚାଳନା କରନ୍ତୁ"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"ବ୍ୟବହାର ପାଇଁ ଆପ୍କୁ ଫେସିଆଲ୍ ଟେମ୍ପଲେଟ୍ ଯୋଡିବା ଓ ଡିଲିଟ୍ ର ପଦ୍ଧତି ପାଇଁ ଅନୁମତି ଦିଅନ୍ତୁ।"</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"ଫେସ୍ ପ୍ରମାଣୀକରଣ ହାର୍ଡୱେର୍ ବ୍ୟବହାର କରନ୍ତୁ"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"ଫେସ୍ ପ୍ରମାଣୀକରଣ ହାର୍ଡୱେର୍ର ପ୍ରମାଣ ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦିଅନ୍ତୁ।"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"ଫେସ୍ ଚିହ୍ନଟ ହେଲାନାହିଁ ।ଦୟାକରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"ଫେସ୍ଟି ବହୁତ ଉଜ୍ଵଳ ଦେଖାଯାଉଛି। ଦୟାକରି, କମ ଆଲୋକରେ ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"ଫେସ୍ଟି ବହୁତ କଳା ଦେଖାଯାଉଛି। ଦୟାକରି ଆଲୋକକୁ ଅନାବୃତ କରନ୍ତୁ।"</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"ଦୟାକରି ସେନ୍ସର୍କୁ ଫେସ୍ ପାଖରୁ ଦୂରେଇ ରଖନ୍ତୁ"</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"ଦୟାକରି ସେନ୍ସର୍କୁ ଫେସ୍ର ଅତି ନିକଟକୁ ଆଣନ୍ତୁ।"</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"ଦୟାକରି ସେନ୍ସର୍କୁ ଆହୁରି ଉପରକୁ ଘୁଞ୍ଚାନ୍ତୁ।"</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"ଦୟାକରି ସେନ୍ସର୍କୁ ତଳକୁ ଘୁଞ୍ଚାନ୍ତୁ।"</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"ଦୟାକରି ସେନ୍ସର୍କୁ ଦକ୍ଷିଣକୁ ଘୁଞ୍ଚାନ୍ତୁ।"</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"ଦୟାକରି ସେନ୍ସର୍କୁ ବାମକୁ ଘୁଞ୍ଚାନ୍ତୁ।"</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"ଦୟାକରି ସେନ୍ସର୍କୁ ଦେଖନ୍ତୁ"</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"କୌଣସି ଫେସ୍ ଚିହ୍ନଟ ହେଲା ନାହିଁ"</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"ଡିଭାଇସ୍ର ସାମ୍ନାରେ ଫେସ୍ ସିଧା ରଖନ୍ତୁ।"</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"ଫେସ୍ର ହାର୍ଡୱେୟାର୍ ଉପଲବ୍ଧ ନାହିଁ।"</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"ଫେସ୍ର ସମୟସୀମା ସରିଗଲା। ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"ଫେସ୍ ମେମୋରୀରେ ଷ୍ଟୋର୍ କରାଯାଇପାରିବ ନାହିଁ।"</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"ଫେସ୍ର ଅପରେଶନ୍ କ୍ୟାନ୍ସଲ୍ ହୋଇଗଲା"</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"ବାରମ୍ବାର ଚେଷ୍ଟା। ପରେ ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"ବାରମ୍ବାର ଚେଷ୍ଟା। ଫେସ୍ ପ୍ରମାଣୀକରଣ ଅକ୍ଷମ କରାଗଲା।"</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"କୌଣସି ଫେସ୍ ପଞ୍ଜୀକୃତ ହୋଇନଥିଲା।"</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"ଡିଭାଇସ୍ର ଗୋଟିଏ ଫେସ୍ ପ୍ରମାଣୀକରଣ ସେନ୍ସର୍ ନାହିଁ"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"<xliff:g id="FACEID">%d</xliff:g>ଙ୍କ ଫେସ୍"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"ଫେସ୍ ଆଇକନ୍"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"ସିଙ୍କ ସେଟିଙ୍ଗକୁ ପଢ଼ନ୍ତୁ"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"ଏକ ଆକାଉଣ୍ଟ ପାଇଁ ସିଙ୍କ ସେଟିଙ୍ଗ ପଢ଼ିବାକୁ ଆପ୍ଟିକୁ ଅନୁମତି ଦିଏ। ଉଦାହରଣସ୍ୱରୂପ, ଲୋକଙ୍କ ଆପ୍ ଏକ ଆକାଉଣ୍ଟରେ ସିଙ୍କ ହୋଇଛି କି ନାହିଁ ଏହା ଜାଣିପାରେ।"</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ସିଙ୍କ ଅନ୍ ଓ ଅଫ୍ ଟୋଗଲ୍ କରନ୍ତୁ"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"ୱାଇ-ଫାଇର କୌଣସି ଇଣ୍ଟରନେଟ୍ ଆକ୍ସେସ୍ ନାହିଁ"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ବିକଳ୍ପ ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"ଆପଣଙ୍କର ହଟ୍ସ୍ପଟ୍ ସେଟିଙ୍ଗକୁ ବଦଳିଯାଇଛି"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"ଆପଣଙ୍କର ହଟ୍ସ୍ପଟ୍ ପରିବର୍ତ୍ତନ କରାଯାଇଛି"</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"କେବଳ 5GHz ପାଇଁ, ଏହି ଡିଭାଇସ୍ ଆପଣଙ୍କର ପସନ୍ଦକୁ ସପୋର୍ଟ କରେନାହିଁ। ଏହା ପରିବର୍ତ୍ତେ, ଏହି ଡିଭାଇସ୍ 5GHz ବ୍ୟାଣ୍ଡ ବ୍ୟବହାର କରିବ।"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>କୁ ବଦଳାଗଲା"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>ର ଇଣ୍ଟରନେଟ୍ ଆକ୍ସେସ୍ ନଥିବାବେଳେ ଡିଭାଇସ୍ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ବ୍ୟବହାର କରିଥାଏ। ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ।"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ରୁ <xliff:g id="NEW_NETWORK">%2$s</xliff:g>କୁ ବଦଳାଗଲା"</string>
@@ -1698,8 +1734,7 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"ଆପଣଙ୍କ ଆଡମିନ୍ ଅପଡେଟ୍ କରିଛନ୍ତି"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"ଆପଣଙ୍କ ଆଡମିନ୍ ଡିଲିଟ୍ କରିଛନ୍ତି"</string>
<string name="battery_saver_description_with_learn_more" msgid="6323937147992667707">"ବ୍ୟାଟେରୀର କାର୍ଯ୍ୟକାଳକୁ ବଢ଼ାଇବା ପାଇଁ, ବ୍ୟାଟେରୀ ସେଭର୍ କିଛି ଡିଭାଇସ୍ ଫିଚର୍କୁ ବନ୍ଦ କରିବା ସହ କେତେକ ଆପ୍କୁ ଚାଲିବାରୁ ରୋକିଥାଏ। "<annotation id="url">"ଅଧିକ ଜାଣନ୍ତୁ"</annotation></string>
- <!-- no translation found for battery_saver_description (769989536172631582) -->
- <skip />
+ <string name="battery_saver_description" msgid="769989536172631582">"ଆପଣଙ୍କ ବ୍ୟାଟେରୀ ଆୟୁଶ ବଢାଇବାକୁ, ବ୍ୟାଟେରୀ ସେଭର୍ କିଛି ଡିଭାଇସ୍ ଫିଚର୍ଗୁଡିକୁ ବନ୍ଦ କରେ ଏବଂ ଆପ୍ଗୁଡିକୁ ପ୍ରତିବନ୍ଧିତ କରିଥାଏ।"</string>
<string name="data_saver_description" msgid="6015391409098303235">"ଡାଟା ବ୍ୟବହାର କମ୍ କରିବାରେ ସାହାଯ୍ୟ କରିବାକୁ, ଡାଟା ସେଭର୍ ବ୍ୟାକ୍ଗ୍ରାଉଣ୍ଡରେ ଡାଟା ପଠାଇବା କିମ୍ବା ପ୍ରାପ୍ତ କରିବାକୁ କିଛି ଆପ୍କୁ ବ୍ଲକ୍ କରେ। ଆପଣ ବର୍ତ୍ତମାନ ବ୍ୟବହାର କରୁଥିବା ଆପ୍, ଡାଟା ଆକ୍ସେସ୍ କରିପାରେ, କିନ୍ତୁ ଏହା କମ୍ ସମୟରେ କରିପାରେ। ଏହାର ଅର୍ଥ ହୋଇପାରେ, ଯେପରି, ଆପଣ ଟାପ୍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଯେଉଁ ଇମେଜ୍ ଦେଖାଯାଏ ନାହିଁ।"</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"ଡାଟା ସେଭର୍ ଅନ୍ କରିବେ?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"ଅନ୍ କରନ୍ତୁ"</string>
@@ -1878,10 +1913,8 @@
<string name="volume_dialog_ringer_guidance_silent" msgid="2128975224280276122">"କଲ୍ ଓ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ନିଃଶବ୍ଦ କରିଦିଆଯିବ"</string>
<string name="notification_channel_system_changes" msgid="5072715579030948646">"ସିଷ୍ଟମ୍ରେ ପରିବର୍ତ୍ତନ"</string>
<string name="notification_channel_do_not_disturb" msgid="6766940333105743037">"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ"</string>
- <!-- no translation found for zen_upgrade_notification_visd_title (3288313883409759733) -->
- <skip />
- <!-- no translation found for zen_upgrade_notification_visd_content (5533674060311631165) -->
- <skip />
+ <string name="zen_upgrade_notification_visd_title" msgid="3288313883409759733">"ନୂଆ: \"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ମୋଡ୍ ଅନ୍ ଥିବା ଯୋଗୁଁ ବିଜ୍ଞପ୍ତି ଲୁଚାଇ ଦିଆଯାଉଛି"</string>
+ <string name="zen_upgrade_notification_visd_content" msgid="5533674060311631165">"ଅଧିକ ଜାଣିବାକୁ ଟ୍ୟାପ୍ କରନ୍ତୁ ଏବଂ ବଦଳାନ୍ତୁ।"</string>
<string name="zen_upgrade_notification_title" msgid="3799603322910377294">"’ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ’ ବଦଳିଯାଇଛି"</string>
<string name="zen_upgrade_notification_content" msgid="1794994264692424562">"କ’ଣ ଅବରୋଧ ହୋଇଛି ଯାଞ୍ଚ କରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ।"</string>
<string name="notification_app_name_system" msgid="4205032194610042794">"ସିଷ୍ଟମ୍"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index c454a73..dc170c8 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"ਟਿਕਾਣਾ"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"ਇਸ ਡੀਵਾਈਸ ਦੇ ਨਿਰਧਾਰਤ ਟਿਕਾਣੇ ਤੱਕ ਪਹੁੰਚੋ"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"ਕੀ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ਨੂੰ ਇਸ ਡੀਵਾਈਸ ਦੇ ਟਿਕਾਣੇ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"ਤੁਹਾਡੇ ਵੱਲੋਂ ਐਪ ਦੀ ਵਰਤੋਂ ਕਰਨ ਵੇਲੇ ਹੀ ਐਪ ਕੋਲ ਟਿਕਾਣੇ ਤੱਕ ਪਹੁੰਚ ਹੋਵੇਗੀ।"</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"ਕੀ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ਨੂੰ ਹਮੇਸ਼ਾਂ ਇਸ ਡੀਵਾਈਸ ਦੇ ਟਿਕਾਣੇ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"ਐਪ ਕੋਲ ਹਮੇਸ਼ਾਂ ਟਿਕਾਣੇ ਤੱਕ ਪਹੁੰਚ ਹੋਵੇਗੀ, ਭਾਵੇਂ ਤੁਸੀਂ ਐਪ ਦੀ ਵਰਤੋਂ ਨਾ ਕਰ ਰਹੇ ਹੋਵੋ।"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"ਕੈਲੰਡਰ"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"ਤੁਹਾਡੇ ਕੈਲੰਡਰ ਤੱਕ ਪਹੁੰਚ ਕਰਨ"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"ਕੀ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ਨੂੰ ਤੁਹਾਡੇ ਕੈਲੰਡਰ ਤੱਕ ਪਹੁੰਚ ਕਰਨੀ ਦੇਣੀ ਹੈ?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"ਇਹ ਐਪ ਤੁਹਾਡੇ ਫ਼ੋਨ \'ਤੇ ਕੈਲੰਡਰ ਇਵੈਂਟਾਂ ਨੂੰ ਸ਼ਾਮਲ ਕਰ ਸਕਦੀ ਹੈ, ਹਟਾ ਸਕਦੀ ਹੈ, ਜਾਂ ਬਦਲ ਸਕਦੀ ਹੈ। ਇਹ ਐਪ ਉਹਨਾਂ ਸੁਨੇਹਿਆਂ ਨੂੰ ਭੇਜ ਸਕਦੀ ਹੈ ਜੋ ਕੈਲੰਡਰ ਮਾਲਕਾਂ ਤੋਂ ਆਉਂਦੇ ਜਾਪ ਸਕਦੇ ਹਨ, ਜਾਂ ਉਹਨਾਂ ਦੇ ਮਾਲਕਾਂ ਨੂੰ ਸੂਚਿਤ ਕੀਤੇ ਬਿਨਾਂ ਇਵੈਂਟਾਂ ਨੂੰ ਬਦਲ ਸਕਦੀ ਹੈ।"</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"ਵਾਧੂ ਟਿਕਾਣਾ ਪ੍ਰਦਾਤਾ ਕਮਾਂਡਾਂ ਤੱਕ ਪਹੁੰਚ"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"ਐਪ ਨੂੰ ਵਾਧੂ ਟਿਕਾਣਾ ਪ੍ਰਦਾਤਾ ਕਮਾਂਡਾਂ ਤੱਕ ਪਹੁੰਚ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਐਪ ਨੂੰ GPS ਜਾਂ ਹੋਰ ਟਿਕਾਣਾ ਸਰੋਤਾਂ ਦੇ ਓਪਰੇਸ਼ਨ ਵਿੱਚ ਵਿਘਨ ਪਾਉਣ ਦੀ ਆਗਿਆ ਦੇ ਸਕਦਾ ਹੈ।"</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"ਸਿਰਫ਼ ਫੋਰਗ੍ਰਾਊਂਡ ਵਿੱਚ ਸਟੀਕ ਟਿਕਾਣੇ ਤੱਕ ਪਹੁੰਚ ਕਰੋ"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"ਇਹ ਐਪ ਫੋਰਗ੍ਰਾਉਂਡ ਵਿੱਚ ਹੋਣ \'ਤੇ ਹੀ ਤੁਹਾਡਾ ਸਟੀਕ ਟਿਕਾਣਾ ਪਤਾ ਕਰ ਸਕਦੀ ਹੈ। ਐਪ ਵੱਲੋਂ ਟਿਕਾਣਾ ਸੇਵਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ ਇਹ ਸੇਵਾਵਾਂ ਤੁਹਾਡੇ ਫ਼ੋਨ \'ਤੇ ਉਪਲਬਧ ਹੋਣੀਆਂ ਅਤੇ ਚਾਲੂ ਕੀਤੀਆਂ ਹੋਣੀਆਂ ਲਾਜ਼ਮੀ ਹਨ। ਇਸ ਨਾਲ ਬੈਟਰੀ ਦੀ ਖਪਤ ਵਧ ਸਕਦੀ ਹੈ।"</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"ਅੰਦਾਜ਼ਨ ਟਿਕਾਣੇ \'ਤੇ ਪਹੁੰਚ ਕਰੋ (ਨੈੱਟਵਰਕ-ਆਧਾਰਿਤ)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"ਇਹ ਐਪ ਨੈੱਟਵਰਕ ਸਰੋਤਾਂ ਜਿਵੇਂ ਕਿ ਸੈੱਲ ਟਾਵਰਾਂ ਅਤੇ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕਾਂ \'ਤੇ ਆਧਾਰਿਤ ਤੁਹਾਡਾ ਟਿਕਾਣਾ ਪਤਾ ਕਰ ਸਕਦੀ ਹੈ। ਐਪ ਦੁਆਰਾ ਟਿਕਾਣਾ ਸੇਵਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕੀਤੇ ਜਾਣ ਦੇ ਯੋਗ ਹੋਣ ਲਈ ਇਹ ਸੇਵਾਵਾਂ ਤੁਹਾਡੇ ਟੈਬਲੈੱਟ \'ਤੇ ਉਪਲਬਧ ਹੋਣੀਆਂ ਅਤੇ ਚਾਲੂ ਕੀਤੀਆਂ ਹੋਣੀਆਂ ਲਾਜ਼ਮੀ ਹਨ।"</string>
@@ -518,6 +520,64 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਪ੍ਰਤੀਕ"</string>
+ <!-- no translation found for permlab_manageFace (2137540986007309781) -->
+ <skip />
+ <!-- no translation found for permdesc_manageFace (8919637120670185330) -->
+ <skip />
+ <!-- no translation found for permlab_useFaceAuthentication (8996134460546804535) -->
+ <skip />
+ <!-- no translation found for permdesc_useFaceAuthentication (5011118722951833089) -->
+ <skip />
+ <!-- no translation found for face_acquired_insufficient (5901287247766106330) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_bright (610606792381297174) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_dark (7229162716976778371) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_close (1980310037427755293) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_far (4494571381828850007) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_high (228411096134808372) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_low (4539774649296349109) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_right (1650292067226118760) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_left (2712489669456176505) -->
+ <skip />
+ <!-- no translation found for face_acquired_poor_gaze (8344973502980415859) -->
+ <skip />
+ <!-- no translation found for face_acquired_not_detected (5707782294589511391) -->
+ <skip />
+ <!-- no translation found for face_acquired_not_steady (3722829465011040042) -->
+ <skip />
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <!-- no translation found for face_error_hw_not_available (6255891785768984615) -->
+ <skip />
+ <!-- no translation found for face_error_timeout (4014326147867150054) -->
+ <skip />
+ <!-- no translation found for face_error_no_space (8224993703466381314) -->
+ <skip />
+ <!-- no translation found for face_error_canceled (283945501061931023) -->
+ <skip />
+ <!-- no translation found for face_error_lockout (3407426963155388504) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_permanent (8198354656746088890) -->
+ <skip />
+ <!-- no translation found for face_error_unable_to_process (238761109287767270) -->
+ <skip />
+ <!-- no translation found for face_error_not_enrolled (9166792142679691323) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (4737289254517095671) -->
+ <skip />
+ <!-- no translation found for face_name_template (7004562145809595384) -->
+ <skip />
+ <string-array name="face_error_vendor">
+ </string-array>
+ <!-- no translation found for face_icon_content_description (4024817159806482191) -->
+ <skip />
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"ਸਿੰਕ ਸੈਟਿੰਗਾਂ ਪੜ੍ਹੋ"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"ਐਪ ਨੂੰ ਕਿਸੇ ਖਾਤੇ ਲਈ ਸਮਕਾਲੀਕਰਨ ਸੈਟਿੰਗਾਂ ਪੜ੍ਹਨ ਦੇ ਯੋਗ ਬਣਾਉਂਦਾ ਹੈ। ਉਦਾਹਰਨ ਲਈ, ਇਹ ਪਤਾ ਕਰ ਸਕਦਾ ਹੈ ਕਿ People ਐਪ ਦਾ ਕਿਸੇ ਖਾਤੇ ਨਾਲ ਸਮਕਾਲੀਕਿਰਤ ਕੀਤਾ ਗਿਆ ਹੈ ਜਾਂ ਨਹੀਂ।"</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ਸਮਕਾਲੀਕਰਨ ਚਾਲੂ ਅਤੇ ਬੰਦ ਨੂੰ ਟੌਗਲ ਕਰੋ"</string>
@@ -1178,6 +1238,12 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"ਵਾਈ-ਫਾਈ ਦੀ ਕੋਈ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ਵਿਕਲਪਾਂ ਲਈ ਟੈਪ ਕਰੋ"</string>
+ <!-- no translation found for wifi_softap_config_change (8475911871165857607) -->
+ <skip />
+ <!-- no translation found for wifi_softap_config_change_summary (7601233252456548891) -->
+ <skip />
+ <!-- no translation found for wifi_softap_config_change_detailed (8022936822860678033) -->
+ <skip />
<string name="network_switch_metered" msgid="4671730921726992671">"ਬਦਲਕੇ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ਲਿਆਂਦਾ ਗਿਆ"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ਦੀ ਇੰਟਰਨੈੱਟ \'ਤੇ ਪਹੁੰਚ ਨਾ ਹੋਣ \'ਤੇ ਡੀਵਾਈਸ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰਦਾ ਹੈ। ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ।"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ਤੋਂ ਬਦਲਕੇ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> \'ਤੇ ਕੀਤਾ ਗਿਆ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index fa5d2ce..4b0db4a 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -282,6 +282,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Lokalizacja"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"dostęp do informacji o lokalizacji tego urządzenia"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Zezwolić aplikacji <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> na dostęp do lokalizacji urządzenia?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Aplikacja będzie mieć dostęp do lokalizacji tylko wtedy, gdy jest używana."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Zawsze zezwalać aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g> na dostęp do lokalizacji urządzenia?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Aplikacja będzie zawsze mieć dostęp do lokalizacji, nawet wtedy, gdy nie jest używana."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalendarz"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"dostęp do kalendarza"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Zezwolić aplikacji <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> na dostęp do kalendarza?"</string>
@@ -408,8 +411,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Ta aplikacja może dodawać, usuwać i zmieniać wydarzenia z kalendarza na telefonie. Ta aplikacja może wysyłać wiadomości wyglądające jak utworzone przez właścicieli kalendarza lub zmieniać wydarzenia bez wiedzy ich właścicieli."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"dostęp do dodatkowych poleceń dostawcy informacji o lokalizacji"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Pozwala aplikacji na dostęp do dodatkowych poleceń dostawcy informacji o lokalizacji. Aplikacje z tym uprawnieniem mogą wpływać na działanie GPS-a lub innych źródeł lokalizacji."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"dostęp do dokładnej lokalizacji tylko na pierwszym planie"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Ta aplikacja może określić Twoją dokładną lokalizację tylko wtedy, gdy działa na pierwszym planie. Te usługi lokalizacyjne muszą być włączone i dostępne na telefonie, by aplikacja mogła z nich korzystać. Może to zwiększyć zużycie baterii."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"dostęp do przybliżonej lokalizacji (na podstawie sieci)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Ta aplikacja może określać Twoją lokalizację na podstawie źródeł sieciowych, takich jak stacje bazowe i sieci Wi-Fi. Te usługi lokalizacyjne muszą być włączone i dostępne na tablecie, by aplikacja mogła z nich korzystać."</string>
@@ -524,6 +526,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Ikona odcisku palca"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"zarządzanie sprzętem do uwierzytelniania za pomocą twarzy"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Zezwala na aktywowanie przez aplikację metody dodawania i usuwania szablonów twarzy."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"używanie sprzętu do uwierzytelniania za pomocą twarzy"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Zezwala na używanie przez aplikację sprzętu do analizy twarzy na potrzeby uwierzytelniania"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Nie można przeanalizować twarzy. Spróbuj ponownie."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Zbyt jasna twarz. Spróbuj w ciemniejszym miejscu."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Zbyt ciemna twarz. Spróbuj w jaśniejszym miejscu."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Oddal czujnik od twarzy."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Przybliż czujnik do twarzy."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Przesuń czujnik wyżej."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Przesuń czujnik niżej."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Przesuń czujnik w prawo."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Przesuń czujnik w lewo."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Spójrz na czujnik."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Nie wykryto twarzy."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Nie ruszaj twarzą, patrząc na urządzenie."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Czujnik twarzy nie jest dostępny."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Upłynął limit czasu analizy twarzy. Spróbuj ponownie."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Nie można zapisać informacji o twarzy."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Analiza twarzy została anulowana."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Zbyt wiele prób. Spróbuj ponownie później."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Zbyt wiele prób. Wyłączono uwierzytelnianie za pomocą twarzy."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Spróbuj ponownie."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Nie zarejestrowano twarzy."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"To urządzenie nie jest wyposażone w czujnik twarzy"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Twarz <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Ikona twarzy"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"czytanie ustawień synchronizacji"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Zezwala aplikacji na odczyt ustawień synchronizacji konta. Pozwala to na przykład określić, czy aplikacja Ludzie jest zsynchronizowana z kontem."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"włączanie i wyłączanie synchronizacji"</string>
@@ -1222,6 +1255,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Sieć Wi-Fi nie ma dostępu do internetu"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Kliknij, by wyświetlić opcje"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Zmieniono ustawienia hotspotu"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Zmieniono pasmo hotspotu."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"To urządzenie nie może korzystać tylko z częstotliwości 5 GHz. Będzie korzystać z tego pasma, jeśli będzie ono dostępne."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Zmieniono na połączenie typu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Urządzenie korzysta z połączenia typu <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, gdy <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nie dostępu do internetu. Mogą zostać naliczone opłaty."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Przełączono z połączenia typu <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na <xliff:g id="NEW_NETWORK">%2$s</xliff:g>."</string>
@@ -1453,7 +1489,7 @@
<string name="add_account_button_label" msgid="3611982894853435874">"Dodaj konto"</string>
<string name="number_picker_increment_button" msgid="2412072272832284313">"Zwiększ"</string>
<string name="number_picker_decrement_button" msgid="476050778386779067">"Zmniejsz"</string>
- <string name="number_picker_increment_scroll_mode" msgid="5259126567490114216">"<xliff:g id="VALUE">%s</xliff:g> dotknij i przytrzymaj."</string>
+ <string name="number_picker_increment_scroll_mode" msgid="5259126567490114216">"<xliff:g id="VALUE">%s</xliff:g> naciśnij i przytrzymaj."</string>
<string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Przesuń w górę, by zwiększyć, i w dół, by zmniejszyć."</string>
<string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Zmień minutę na późniejszą"</string>
<string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Zmień minutę na wcześniejszą"</string>
@@ -1480,7 +1516,7 @@
<string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Nie udało się uruchomić aplikacji <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Udostępnij przez:"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Udostępnij przez <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
- <string name="content_description_sliding_handle" msgid="415975056159262248">"Uchwyt przesuwny. Dotknij i przytrzymaj."</string>
+ <string name="content_description_sliding_handle" msgid="415975056159262248">"Uchwyt przesuwny. Naciśnij i przytrzymaj."</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Przesuń, aby odblokować."</string>
<string name="action_bar_home_description" msgid="5293600496601490216">"Przejdź do strony głównej"</string>
<string name="action_bar_up_description" msgid="2237496562952152589">"Przejdź wyżej"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 2d846c1..16ce8c3 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Local"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"acesse o local do dispositivo"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Permitir que <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> acesse a localização deste dispositivo?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"O app só terá acesso ao local enquanto estiver sendo usado."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Sempre permitir que <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> acesse o local deste disp.?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"O app sempre terá acesso ao local, mesmo quando não estiver sendo usado."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Agenda"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"acesse sua agenda"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Permitir que <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> acesse sua agenda?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Este app pode adicionar, remover ou alterar eventos da agenda no seu smartphone. Ele também pode enviar mensagens que aparentem ser de autoria do proprietário da agenda ou alterar eventos sem notificar o proprietário."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"acessar comandos extras do provedor de localização"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Permite que o app acesse comandos do provedor não relacionados à localização. Isso pode permitir que o app interfira no funcionamento do GPS ou de outras fontes de localização."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"acessar localização precisa apenas em primeiro plano"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Este app pode ver sua localização exata a qualquer momento apenas quando está em primeiro plano. Esses serviços de localização precisam estar ativados e disponíveis no seu smartphone para que o app possa usá-los. Isso pode aumentar o consumo de bateria."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"acessar localização aproximada (com base na rede)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Este app pode ver seu local com base nas fontes de rede, como torres de celular e redes Wi-Fi. Esses serviços de localização precisam estar ativados e disponíveis no seu tablet para que o app possa usá-los."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Ícone de impressão digital"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"gerenciar hardware de autenticação facial"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Permite que o app execute métodos para adicionar e excluir modelos de rosto para uso."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"usar hardware de autenticação facial"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Permite que o app use o hardware de autenticação facial para autenticação"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Falha ao processar o rosto. Tente novamente."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Rosto muito iluminado. Tente com menos iluminação."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Rosto muito escuro. Acrescente uma fonte de luz."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Afaste o sensor do rosto."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Aproxime o sensor do rosto."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Mova o sensor para cima."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Mova o sensor para baixo."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Mova o sensor para a direita."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Mova o sensor para a esquerda."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Olhe para o sensor."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Nenhum rosto detectado."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Mantenha o rosto parado na frente do dispositivo."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Hardware de rosto não disponível."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Tempo máx. p/ captura facial atingido. Tente novamente."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Não é possível armazenar um rosto."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Operação facial cancelada."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Excesso de tentativas. Tente novamente mais tarde."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Excesso de tentativas. Autenticação facial desat."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Tente novamente."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Nenhum rosto registrado."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Este dispositivo não tem um sensor de autenticação facial"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Rosto <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Ícone facial"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"ler as configurações de sincronização"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Permite que o app leia as configurações de sincronização de uma conta. Por exemplo, pode determinar se o app People está sincronizado com uma conta."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ativar e desativar sincronização"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"O Wi‑Fi não tem acesso à Internet"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toque para ver opções"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Mudanças nas suas configurações de ponto de acesso"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Sua banda de ponto de acesso foi alterada."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Este dispositivo não é compatível com sua preferência apenas por 5 GHz. Em vez disso, o dispositivo usará a banda de 5 GHz quando ela estiver disponível."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Alternado para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"O dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Esse serviço pode ser cobrado."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Alternado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 1f5704a..b1c4b3b 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Localização"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"aceder à localização do seu dispositivo"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Pretende permitir que a aplicação <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> aceda à localização deste dispositivo?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"A aplicação tem acesso à localização apenas quando a estiver a utilizar."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Pretende permitir que a aplicação <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> aceda sempre à localização deste dispositivo?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"A aplicação terá sempre acesso à localização, mesmo quando não está a utilizá-la."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Calendário"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"aceder ao calendário"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Pretende permitir que a aplicação <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> aceda ao calendário?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Esta aplicação pode adicionar, remover ou alterar eventos do calendário no seu telemóvel. Esta aplicação pode enviar mensagens que parecem vir de proprietários do calendário ou alterar eventos sem notificar os respetivos proprietários."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"aceder a comandos adicionais do fornecedor de localização"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Permite que a aplicação aceda a comandos adicionais do fornecedor de localização. Esta opção pode permitir que a aplicação interfira com o funcionamento do GPS ou de outras fontes de localização."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"apenas aceder à localização exata em primeiro plano"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Esta aplicação apenas pode obter a sua localização exata quando estiver em primeiro plano. É necessário que estes Serviços de localização estejam ativados e disponíveis no seu telemóvel para que a aplicação os possa utilizar. Esta ação pode aumentar o consumo da bateria."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"aceder à localização aproximada (baseada na rede)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Esta aplicação pode obter a sua localização com base em fontes de rede, tais como torres de redes móveis e redes Wi-Fi. É necessário que estes serviços de localização estejam ativados e disponíveis no seu tablet para que a aplicação os possa utilizar."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Ícone de impressão digital"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"gerir hardware de autenticação facial"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Permite à aplicação invocar métodos para adicionar e eliminar modelos faciais para uso."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"utilizar hardware de autenticação facial"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Permite que a aplicação utilize hardware de autenticação facial para autenticação."</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Não foi possível processar o rosto. Tente de novo."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Rosto demasiado claro. Experimente com menos luz."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Rosto demasiado escuro. Destape a fonte de luz."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Afaste o sensor do rosto."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Aproxime o sensor do rosto."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Mova o sensor para cima."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Mova o sensor para baixo."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Mova o sensor para a direita."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Mova o sensor para a esquerda."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Olhe para o sensor."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Nenhum rosto detetado."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Mantenha o rosto parado em frente ao dispositivo."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"O hardware de rosto não está disponível."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Limite de tempo de rosto atingido. Tente novamente."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Não é possível armazenar o rosto."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Operação de rosto cancelada."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Demasiadas tentativas. Tente novamente mais tarde."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Demasiadas tentativas. Autenticação facial desativada."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Tente novamente."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Nenhum rosto inscrito."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Este dispositivo não tem sensor de autenticação facial."</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Rosto <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Ícone de rosto"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"ler definições de sincronização"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Permite que a aplicação leia as definições de sincronização de uma conta. Por exemplo, pode determinar se a aplicação Pessoas está sincronizada com uma conta."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ativar e desativar a sincronização"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"O Wi-Fi não tem acesso à Internet."</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toque para obter mais opções"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Alterações às definições de zona Wi-Fi"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"A banda da sua zona Wi-Fi foi alterada."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Este dispositivo não suporta a sua preferência apenas para 5 GHz. Em alternativa, este dispositivo vai utilizar a banda de 5 GHz quando estiver disponível."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Mudou para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"O dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Podem aplicar-se custos."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Mudou de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 2d846c1..16ce8c3 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Local"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"acesse o local do dispositivo"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Permitir que <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> acesse a localização deste dispositivo?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"O app só terá acesso ao local enquanto estiver sendo usado."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Sempre permitir que <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> acesse o local deste disp.?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"O app sempre terá acesso ao local, mesmo quando não estiver sendo usado."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Agenda"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"acesse sua agenda"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Permitir que <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> acesse sua agenda?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Este app pode adicionar, remover ou alterar eventos da agenda no seu smartphone. Ele também pode enviar mensagens que aparentem ser de autoria do proprietário da agenda ou alterar eventos sem notificar o proprietário."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"acessar comandos extras do provedor de localização"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Permite que o app acesse comandos do provedor não relacionados à localização. Isso pode permitir que o app interfira no funcionamento do GPS ou de outras fontes de localização."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"acessar localização precisa apenas em primeiro plano"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Este app pode ver sua localização exata a qualquer momento apenas quando está em primeiro plano. Esses serviços de localização precisam estar ativados e disponíveis no seu smartphone para que o app possa usá-los. Isso pode aumentar o consumo de bateria."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"acessar localização aproximada (com base na rede)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Este app pode ver seu local com base nas fontes de rede, como torres de celular e redes Wi-Fi. Esses serviços de localização precisam estar ativados e disponíveis no seu tablet para que o app possa usá-los."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Ícone de impressão digital"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"gerenciar hardware de autenticação facial"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Permite que o app execute métodos para adicionar e excluir modelos de rosto para uso."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"usar hardware de autenticação facial"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Permite que o app use o hardware de autenticação facial para autenticação"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Falha ao processar o rosto. Tente novamente."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Rosto muito iluminado. Tente com menos iluminação."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Rosto muito escuro. Acrescente uma fonte de luz."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Afaste o sensor do rosto."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Aproxime o sensor do rosto."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Mova o sensor para cima."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Mova o sensor para baixo."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Mova o sensor para a direita."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Mova o sensor para a esquerda."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Olhe para o sensor."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Nenhum rosto detectado."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Mantenha o rosto parado na frente do dispositivo."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Hardware de rosto não disponível."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Tempo máx. p/ captura facial atingido. Tente novamente."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Não é possível armazenar um rosto."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Operação facial cancelada."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Excesso de tentativas. Tente novamente mais tarde."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Excesso de tentativas. Autenticação facial desat."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Tente novamente."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Nenhum rosto registrado."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Este dispositivo não tem um sensor de autenticação facial"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Rosto <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Ícone facial"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"ler as configurações de sincronização"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Permite que o app leia as configurações de sincronização de uma conta. Por exemplo, pode determinar se o app People está sincronizado com uma conta."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ativar e desativar sincronização"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"O Wi‑Fi não tem acesso à Internet"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toque para ver opções"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Mudanças nas suas configurações de ponto de acesso"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Sua banda de ponto de acesso foi alterada."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Este dispositivo não é compatível com sua preferência apenas por 5 GHz. Em vez disso, o dispositivo usará a banda de 5 GHz quando ela estiver disponível."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Alternado para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"O dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Esse serviço pode ser cobrado."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Alternado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index af4d3f4..2554107 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -279,6 +279,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Locație"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"acceseze locația acestui dispozitiv"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Permiteți <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> să acceseze locația acestui dispozitiv?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Aplicația va avea acces la locație doar atunci când o folosiți."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Permiteți <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> să acceseze locația dispozitivului?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Aplicația va avea în permanență acces la locație, chiar și atunci când nu o folosiți."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Calendar"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"acceseze calendarul"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Permiteți <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> să vă acceseze calendarul?"</string>
@@ -405,8 +408,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Această aplicație poate să adauge, să elimine sau să modifice evenimente din calendarul de pe telefon. Această aplicație poate să trimită mesaje care par trimise de proprietarii calendarului sau să modifice evenimentele fără notificarea acestora."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"accesare comenzi suplimentare ale furnizorului locației"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Permite aplicației să acceseze comenzi suplimentare pentru furnizorul locației. Aplicația ar putea să utilizeze această permisiune pentru a influența operațiile GPS sau ale altor surse de locații."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"să acceseze locația exactă în prim-plan"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Aplicația vă poate obține locația exactă numai când rulează în prim-plan. Serviciile de localizare trebuie să fie activate și disponibile pe telefon pentru ca aplicația să le poată folosi. Acest lucru poate accelera descărcarea bateriei."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"să acceseze locația aproximativă (bazată pe rețea)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Această aplicație vă poate obține locația cu ajutorul surselor rețelei, cum ar fi turnurile de telefonie mobilă și rețelele Wi-Fi. Aceste servicii de localizare trebuie să fie activate și disponibile pe tabletă pentru ca aplicația să le poată folosi."</string>
@@ -521,6 +523,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Pictograma amprentă"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"să gestioneze hardware-ul de autentificare facială"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Permite aplicației să invoce metode pentru a adăuga și a șterge șabloane faciale pentru utilizare."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"să folosească hardware de autentificare facială"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Permite aplicației să folosească hardware de autentificare facială pentru autentificare"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Chipul nu a putut fi procesat. Încercați din nou."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Chip prea luminat. Încercați cu mai puțină lumină."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Chip prea întunecat. Măriți sursa de lumină."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Deplasați senzorul mai departe de chip."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Aduceți senzorul mai aproape de chip."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Deplasați senzorul mai sus."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Deplasați senzorul mai jos."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Deplasați senzorul spre dreapta."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Deplasați senzorul spre stânga."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Priviți spre senzor."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Nu s-a detectat niciun chip."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Țineți chipul nemișcat în fața dispozitivului."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Hardware-ul pentru chip nu este disponibil."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Timpul pentru reunoaștere facială a expirat. Încercați din nou."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Chipul nu poate fi stocat."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Operațiunea privind chipul a fost anulată."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Prea multe încercări. Reîncercați mai târziu."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Prea multe încercări. Autentificarea facială este dezactivată."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Încercați din nou."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Nu au fost înregistrate chipuri."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Dispozitivul nu are un senzor de autentificare a chipului"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Chip <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Pictograma chip"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"citire setări sincronizare"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Permite aplicației să citească setările de sincronizare ale unui cont. De exemplu, cu această permisiune aplicația poate determina dacă aplicația Persoane este sincronizată cu un anumit cont."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"activează/dezactivează sincronizarea"</string>
@@ -1200,6 +1233,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Rețeaua Wi-Fi nu are acces la internet"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Atingeți pentru opțiuni"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Modificări aduse setărilor pentru hotspot"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"S-a schimbat banda de frecvență a hotspotului."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Dispozitivul nu acceptă doar preferința pentru 5 GHz. Dispozitivul va folosi banda de 5 GHz când este disponibilă."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"S-a comutat la <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Dispozitivul folosește <xliff:g id="NEW_NETWORK">%1$s</xliff:g> când <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nu are acces la internet. Se pot aplica taxe."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"S-a comutat de la <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> la <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 9365c4f..a56e9d3 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -278,22 +278,25 @@
<string name="managed_profile_label" msgid="8947929265267690522">"Переключиться на рабочий профиль"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Контакты"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"доступ к контактам"</string>
- <string name="permgrouprequest_contacts" msgid="6032805601881764300">"Разрешить приложению <b>\"<xliff:g id="APP_NAME">%1$s</xliff:g>\"</b> доступ к контактам?"</string>
+ <string name="permgrouprequest_contacts" msgid="6032805601881764300">"Разрешить приложению <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> доступ к контактам?"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Местоположение"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"доступ к данным о местоположении устройства"</string>
- <string name="permgrouprequest_location" msgid="3788275734953323491">"Разрешить приложению <b>\"<xliff:g id="APP_NAME">%1$s</xliff:g>\"</b> доступ к данным о местоположении устройства?"</string>
+ <string name="permgrouprequest_location" msgid="3788275734953323491">"Разрешить приложению <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> доступ к данным о местоположении устройства?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Доступ будет открыт, только когда вы пользуетесь приложением."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Всегда разрешать приложению <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> доступ к геоданным устройства?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Доступ будет открыт, даже когда вы не пользуетесь приложением."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Календарь"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"доступ к календарю"</string>
- <string name="permgrouprequest_calendar" msgid="289900767793189421">"Разрешить приложению <b>\"<xliff:g id="APP_NAME">%1$s</xliff:g>\"</b> доступ к календарю?"</string>
+ <string name="permgrouprequest_calendar" msgid="289900767793189421">"Разрешить приложению <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> доступ к календарю?"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
<string name="permgroupdesc_sms" msgid="4656988620100940350">"отправлять и просматривать SMS-сообщения"</string>
- <string name="permgrouprequest_sms" msgid="7168124215838204719">"Разрешить приложению <b>\"<xliff:g id="APP_NAME">%1$s</xliff:g>\"</b> отправлять и просматривать SMS?"</string>
+ <string name="permgrouprequest_sms" msgid="7168124215838204719">"Разрешить приложению <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> отправлять и просматривать SMS?"</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"Хранилище"</string>
<string name="permgroupdesc_storage" msgid="637758554581589203">"доступ к фото, мультимедиа и файлам на вашем устройстве"</string>
<string name="permgrouprequest_storage" msgid="7885942926944299560">"Разрешить приложению <b>\"<xliff:g id="APP_NAME">%1$s</xliff:g>\"</b> доступ к фото, мультимедиа и файлам на устройстве?"</string>
<string name="permgrouplab_microphone" msgid="171539900250043464">"Микрофон"</string>
<string name="permgroupdesc_microphone" msgid="4988812113943554584">"записывать аудио"</string>
- <string name="permgrouprequest_microphone" msgid="9167492350681916038">"Разрешить приложению <b>\"<xliff:g id="APP_NAME">%1$s</xliff:g>\"</b> записывать аудио?"</string>
+ <string name="permgrouprequest_microphone" msgid="9167492350681916038">"Разрешить приложению <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> записывать аудио?"</string>
<string name="permgrouplab_camera" msgid="4820372495894586615">"Камера"</string>
<string name="permgroupdesc_camera" msgid="3250611594678347720">"снимать фото и видео"</string>
<string name="permgrouprequest_camera" msgid="1299833592069671756">"Разрешить приложению <b>\"<xliff:g id="APP_NAME">%1$s</xliff:g>\"</b> снимать фото и видео?"</string>
@@ -302,7 +305,7 @@
<string name="permgrouprequest_calllog" msgid="8487355309583773267">"Разрешить приложению <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> доступ к списку вызовов?"</string>
<string name="permgrouplab_phone" msgid="5229115638567440675">"Телефон"</string>
<string name="permgroupdesc_phone" msgid="6234224354060641055">"осуществлять вызовы и управлять ими"</string>
- <string name="permgrouprequest_phone" msgid="9166979577750581037">"Разрешить приложению <b>\"<xliff:g id="APP_NAME">%1$s</xliff:g>\"</b> совершать звонки и управлять ими?"</string>
+ <string name="permgrouprequest_phone" msgid="9166979577750581037">"Разрешить приложению <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> совершать звонки и управлять ими?"</string>
<string name="permgrouplab_sensors" msgid="416037179223226722">"Нательные датчики"</string>
<string name="permgroupdesc_sensors" msgid="7147968539346634043">"доступ к данным датчиков о состоянии организма"</string>
<string name="permgrouprequest_sensors" msgid="6349806962814556786">"Разрешить приложению <b>\"<xliff:g id="APP_NAME">%1$s</xliff:g>\"</b> доступ к данным датчиков о состоянии организма?"</string>
@@ -408,8 +411,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Приложение может добавлять, удалять или изменять мероприятия в календаре на телефоне. Оно также может отправлять сообщения от имени владельцев календаря, а также изменять мероприятия без ведома владельца."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"Доступ к дополнительным командам управления источниками геоданных"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Доступ к дополнительным командам управления источниками геоданных и вмешательство в работу системы GPS или других источников геоданных."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"Доступ к точному местоположению только в фоновом режиме"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Приложение может получать сведения о вашем точном местоположении только в фоновом режиме. Для этого необходимо включить соответствующие параметры на телефоне и разрешить использовать геоданные. Может увеличиться расход заряда батареи."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"Доступ к примерному местоположению (по координатам сети)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Приложение может получать сведения о вашем местоположении от сетевых источников, таких как вышки сотовой связи и точки доступа Wi-Fi. Необходимо включить соответствующие параметры на планшете и разрешить приложению использовать геоданные."</string>
@@ -524,6 +526,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Значок отпечатка пальца"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"Управлять оборудованием для распознавания лиц"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Приложение сможет добавлять и удалять шаблоны лиц."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"Использовать оборудование для распознавания лиц"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Приложение сможет использовать распознающее оборудование для аутентификации."</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Не удалось распознать лицо. Повторите попытку."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Лицо слишком яркое. Притушите свет."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Лицо слишком темное. Сделайте свет ярче."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Уберите устройство дальше от лица"</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Поднесите устройство ближе к лицу"</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Поднимите устройство выше"</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Опустите устройство ниже"</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Сдвиньте устройство правее"</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Сдвиньте устройство левее"</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Посмотрите в камеру устройства"</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Лица не обнаружены"</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Расположите лицо напротив устройства"</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Оборудование для распознавания лица недоступно"</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Превышено время ожидания. Повторите попытку."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Невозможно сохранить распознанное лицо"</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Распознавание отменено"</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Слишком много попыток. Повторите позже."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Слишком много попыток. Сканер отключен."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Попробуйте ещё раз"</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Нет зарегистрированных лиц"</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"На этом устройстве нет сканера для распознавания лица"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Лицо <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Значок лица"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"Просмотр настроек синхронизации"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Приложение сможет просматривать настройки синхронизации аккаунта, например определять, включена ли синхронизация для приложения \"Контакты\"."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"Включение/выключение синхронизации"</string>
@@ -1222,6 +1255,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Сеть Wi-Fi не подключена к Интернету"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Нажмите, чтобы показать варианты."</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Изменения в настройках точки доступа"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Частота точки доступа изменена."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Устройство не может работать только на частоте 5 ГГц. Эта частота будет использоваться, когда это возможно."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Новое подключение: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Устройство использует <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, если подключение к сети <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> недоступно. Может взиматься плата за передачу данных."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Устройство отключено от сети <xliff:g id="NEW_NETWORK">%2$s</xliff:g> и теперь использует <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index b382e67..ad1a64d 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"ස්ථානය"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"මෙම උපාංගයේ ස්ථානයට ප්රවේශ කරන්න"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"<b><xliff:g id="APP_NAME">%1$s</xliff:g><b> වෙත මෙම උපාංගයේ ස්ථානය ලබා ගැනීමට ඉඩ දෙන්නද?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"ඔබ යෙදුම භාවිතා විට පමණක් යෙදුමට ස්ථානයට ප්රවේශය ඇත."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"<b><xliff:g id="APP_NAME">%1$s</xliff:g><b> වෙත මෙම උපාංගයේ ස්ථානය ලබා ගැනීමට සැම විට ඉඩ දෙන්නද?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"ඔබ යෙදුම භාවිතා නොකරන විට පවා යෙදුමට සැම විටම ස්ථානයට ප්රවේශය ඇත."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"දින දර්ශනය"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"ඔබේ දින දර්ශනයට පිවිසෙන්න"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"<b><xliff:g id="APP_NAME">%1$s</xliff:g><b> වෙත ඔබගේ දින දර්ශනය ප්රවේශ කිරීමට ඉඩ දෙන්නද?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"මෙම යෙදුමට ඔබේ දුරකථනය මත දින දර්ශන සිදුවීම් එක් කිරීමට, ඉවත් කිරීමට, හෝ වෙනස් කිරීමට හැකිය. මෙම යෙදුමට දින දර්ශන හිමිකරුවන් වෙතින් වන ඒවා ලෙස දිස් විය හැකි පණිවිඩ එවීමට, හෝ සිදුවීම්වල හිමිකරුවන්ට දැනුම් දීමෙන් තොරව ඒවා වෙනස් කිරීමට හැකිය."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"අමතර ස්ථාන සැපයුම්කරු විධාන වෙත ප්රවේශ වීම"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"ස්ථානය සපයන අමතර අණ වලට ප්රවේශය කිරීමට යෙදුමට අවසර දෙන්න. GPS ක්රියාවන් හෝ වෙනත් ස්ථාන මූලාශ්ර සමඟ මැදිහත් වීමට මෙයින් යෙදුමට ඉඩ ලැබේ."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"පෙරබිම තුළ පමණක් නිශ්චිත ස්ථානය වෙත පිවිසෙන්න"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"මෙම යෙදුම පෙරබිම තුළ ඇති විට පමණක් එයට ඔබේ නිශ්චිත ස්ථානය ලබා ගත හැකිය. යෙදුමට ඒවා භාවිත කිරීමට හැකි වීමට මෙම ස්ථාන සේවා ක්රියාත්මක කර සහ ඔබේ දුරකථනය මත ලබා ගත හැකිව තිබිය යුතුය. මෙය බැටරි පරිභෝජනය වැඩි කළ හැකිය."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"ආසන්නතම ස්ථානයට (ජාලය-පාදක වූ) පිවිසීම"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"මෙම යෙදුමට ජංගම දුරකථන කුළුණු සහ Wi-Fi ජාල වැනි ජාල මූලාශ්ර පදනම්ව ඔබගේ ස්ථානය ලබා ගත හැකිය. යෙදුමට ඒවා භාවිත කිරීමට හැකි වීමට මෙම ස්ථාන සේවා ක්රියාත්මක කර සහ ඔබේ ටැබ්ලට් පරිගණකය මත ලබා ගත හැකිව තිබිය යුතුය."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"ඇඟිලි සලකුණු නිරූපකය"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"මුහුණු සත්යාපක දෘඪාංග කළමනාකරණය කරන්න"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"මුහුණු අච්චු එකතු කිරීමට සහ ඉවත් කිරීමට අදාළ ක්රම භාවිතය සඳහා මෙම යෙදුමට ඉඩ දෙයි."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"මුහුණු සත්යාපක දෘඪාංග භාවිතා කරන්න"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"සත්යාපනය සඳහා සත්යාපක දෘඪාංග භාවිත කිරීමට යෙදුමට ඉඩ දෙයි"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"මුහුණ සැකසීමට නොහැකි විය. කරුණාකර නැවත උත්සාහ කර."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"මුහුණ දීප්තිමත් වැඩිය. කරුණාකර අඩු ආලෝකය උත්සාහ කරන්න."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"මුහුණ අඳුරු වැඩිය. කරුණාර ආලෝක ප්රභවය නිරාවරණය කරන්න."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"කරුණාකර සංවේදකය මුහුණෙන් වඩා ඈත් කරන්න."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"කරුණාකර සංවේදකය මුහුණ සමීපයට ගෙන එන්න."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"කරුණාකර සංවේදකය ඉහළට ගෙන යන්න."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"කරුණාකර සංවේදකය පහළට ගෙන යන්න."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"කරුණාකර සංවේදකය දකුණට ගෙන යන්න."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"කරුණාකර සංවේදකය වමට ගෙන යන්න."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"කරුණාකර සංවේදකය දෙස බලන්න."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"මුහුණ අනාවරණය කර නොගන්නා ලදී."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"උපාංගය ඉදිරියේ මුහුණ ස්ථාවරව තබන්න."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"මුහුණු දෘඪාංගය ලද නොහැකිය."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"මුහුණු කාල නිමාව ළඟා විය. නැවත උත්සාහ කරන්න."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"මුහුණ ගබඩා කළ නොහැක."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"මුහුණු මෙහෙයුම අවලංගු කරන ලදී."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"උත්සාහයන් ඉතා වැඩි ගණනකි. කරුණාකර පසුව නැවත උත්සාහ කරන්න."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"උත්සාහයන් ඉතා වැඩි ගණනකි. මුහුණු සත්යාපනය අබල කරන ලදී."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"නැවත උත්සාහ කරන්න."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"මුහුණක් ඇතුළත් කර නොමැත."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"මෙම උපාංගයේ මුහුණු සත්යාපක සංවේදකයක් නොමැත"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"මුහුණු <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"මුහුණ නිරූපකය"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"සමමුහුර්ත සැකසීම් කියවන්න"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"ගිණුම සඳහා සමමුහුර්ත සැකසීම් කියවීමට යෙදුමට අවසර දෙන්න. උදාහරණයක් ලෙස, ගිණුමක් සමඟ පුද්ගල යෙදුම සමමුහුර්ත දැයි මෙයට හඳුනා ගත හැක."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"සමමුහුර්ත කිරීම සක්රිය කරන්න සහ අක්රිය කරන්න"</string>
@@ -1180,6 +1213,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi සඳහා අන්තර්ජාල ප්රවේශය නැත"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"විකල්ප සඳහා තට්ටු කරන්න"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"ඔබගේ හොට්ස්පොට් සැකසීම්වලට වෙනස් කිරීම්"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"ඔබගේ හොට්ස්පොට් කලාපය වෙනස් වී ඇත."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"මෙම උපාංගය 5GHz සඳහා ඔබේ මනාපවලට සහාය නොදක්වයි. ඒ වෙනුවට, මෙම උපාංගය ලබා ගත හැකි විට 5GHz කලාපය භාවිතා කරනු ඇත."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> වෙත මාරු විය"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"උපාංගය <xliff:g id="NEW_NETWORK">%1$s</xliff:g> <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> සඳහා අන්තර්ජාල ප්රවේශය නැති විට භාවිත කරයි. ගාස්තු අදාළ විය හැකිය."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> සිට <xliff:g id="NEW_NETWORK">%2$s</xliff:g> වෙත මාරු විය"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 041cece..42af270 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -282,6 +282,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Poloha"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"prístup k polohe tohto zariadenia"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Povoliť aplikácii <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> prístup k polohe tohto zariadenia?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Aplikácia bude mať prístup k polohe iba vtedy, keď ju budete používať."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Chcete vždy povoliť aplikácii <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> prístup k polohe tohto zariadenia?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Aplikácia bude mať vždy prístup k polohe, aj keď ju nebudete používať."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalendár"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"prístup ku kalendáru"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Povoliť aplikácii <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> prístup ku kalendáru?"</string>
@@ -408,8 +411,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Táto aplikácia môže pridávať, odstraňovať alebo meniť udalosti kalendára vo vašom telefóne. Táto aplikácia môže odosielať správy od vlastníkov kalendára alebo meniť udalosti bez upozornenia ich vlastníkov."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"prístup k ďalším príkazom poskytovateľa polohy"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Umožňuje aplikácii pristupovať k ďalším príkazom poskytovateľa informácií o polohe. Aplikácii to môže umožniť zasahovať do činnosti systému GPS alebo iných zdrojov informácií o polohe."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"prístup k presnej polohe iba v popredí"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Táto aplikácia dokáže získať vašu presnú polohu iba vtedy, keď je spustená v popredí. Na to, aby mohla používať služby určovania polohy, musia byť tieto služby zapnuté a k dispozícii v telefóne. Môže to zvýšiť spotebu batérie."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"prístup k približnej polohe (pomocou siete)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Táto aplikácia môže získať údaje o vašej polohe na základe sieťových zdrojov, ako sú mobilné veže a siete Wi‑Fi. Na to, aby aplikácia mohla používať služby určovania polohy, musia byť tieto služby zapnuté a k dispozícii na tablete."</string>
@@ -524,6 +526,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Ikona odtlačku prsta"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"správa hardvéru na overenie tváre"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Umožňuje aplikácii vyvolať metódy, ktoré pridávajú a odstraňujú šablóny tvárí."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"používanie hardvéru na overenie tváre"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Umožňuje aplikácii používať na overenie totožnosti hardvér na overenie tváre"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Tvár sa nepodarilo spracovať. Skúste to znova."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Tvár je príliš svetlá. Skúste to pri nižšom osvetlení."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Tvár je príliš tmavá. Zvýšte osvetlenie."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Oddiaľte senzor od tváre."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Priblížte senzor k tvári."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Pohnite senzor vyššie."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Pohnite senzor nižšie."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Pohnite senzor doprava."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Pohnite senzor doľava."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Pozerajte sa na senzor."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Nebola rozpoznaná žiadna tvár."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Udržte tvár nehybne oproti zariadeniu."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Hardvér na snímanie tváre nie je k dispozícii"</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Limit rozpoznania tváre vypršal. Skúste to znova."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Tvár sa nedá uchovať."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Operácia týkajúca sa tváre bola zrušená"</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Príliš veľa pokusov. Skúste to znova neskôr."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Príliš veľa pokusov. Overenie tváre je zakázané."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Skúste to znova."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Nemáte zaregistrovanú žiadnu tvár."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Toto zariadenie nemá senzor na overenie tváre."</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Tvár <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Ikona tváre"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"čítať nastavenia synchronizácie"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Umožňuje aplikácii čítať nastavenia synchronizácie v účte. Môže napríklad určiť, či je s účtom synchronizovaná aplikácia Ľudia."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"zapnúť alebo vypnúť synchronizáciu"</string>
@@ -1222,6 +1255,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Sieť Wi‑Fi nemá prístup k internetu"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Klepnutím získate možnosti"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Zmeny nastavení hotspotu"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Pásmo vášho hotspotu sa zmenilo."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Toto zariadenie nepodporuje vašu predvoľbu používať iba 5 GHz. Namiesto toho bude pásmo 5 GHz používať vtedy, keď bude k dispozícii."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Prepnuté na sieť: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Keď <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nemá prístup k internetu, zariadenie používa <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Môžu sa účtovať poplatky."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Prepnuté zo siete <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na sieť <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 9809ee8..ecfbec1 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -282,6 +282,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Lokacija"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"dostop do lokacije te naprave"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Želite aplikaciji <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> omogočiti dostop do lokacije te naprave?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Aplikacija bo imela dostop do lokacije samo, ko aplikacijo uporabljate."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Želite aplikaciji <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> vedno dovoliti dostop do lokacije te naprave?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Aplikacija bo vedno imela dostop do lokacije, tudi ko aplikacije ne uporabljate."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Koledar"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"dostop do koledarja"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Želite aplikaciji <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> omogočiti dostop do koledarja?"</string>
@@ -408,8 +411,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Ta aplikacija lahko dodaja, odstranjuje in spreminja dogodke v koledarju, ki so shranjeni v telefonu. Ta aplikacija lahko pošilja sporočila, ki bodo morda videti, kot da prihajajo od lastnikov koledarjev, ali spreminja dogodke brez vednosti lastnikov."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"dostopanje do ukazov ponudnika dodatnih lokacij"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Aplikaciji omogoča dostop do dodatnih ukazov ponudnika lokacij. S tem lahko aplikacija moti delovanje sistema GPS ali drugih virov lokacije."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"dostop do točne lokacije samo, ko deluje v ospredju"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Ta aplikacija lahko pridobi vašo točno lokacijo samo, ko deluje v ospredju. Če želite aplikaciji omogočiti uporabo teh lokacijskih storitev, morajo biti te vklopljene in na voljo v telefonu. Poraba energije akumulatorja bo morda večja."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"dostop do približne lokacije (na podlagi podatkov omrežja)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Ta aplikacija lahko pridobi vašo lokacijo na podlagi omrežnih virov, kot so bazne postaje in omrežja Wi-Fi. Če želite aplikaciji omogočiti uporabo teh lokacijskih storitev, morajo biti te vklopljene in na voljo v tabličnem računalniku."</string>
@@ -524,6 +526,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Ikona prstnih odtisov"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"upravljanje strojne opreme za preverjanje pristnosti obraza"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Aplikaciji omogoča sprožanje načinov za dodajanje in brisanje predlog z obrazi za uporabo."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"uporaba strojne opreme za preverjanje pristnosti obraza"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Aplikaciji omogoča uporabo strojne opreme za preverjanje pristnosti obraza"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Obraza ni bilo mogoče obdelati. Poskusite znova."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Obraz je presvetel. Poskusite pri manj svetlobe."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Obraz je pretemen. Odkrijte vir svetlobe."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Tipalo premaknite dlje od obraza."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Tipalo premaknite bliže obrazu."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Tipalo premaknite višje."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Tipalo premaknite nižje."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Tipalo premaknite v desno."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Tipalo premaknite v levo."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Poglejte v tipalo."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Ni zaznanih obrazov."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Obraz naj bo pri miru in pred napravo."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Strojna oprema za prepoznavo obraza ni na voljo."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Dosežena časovna omejitev za obraz. Poskusite znova."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Obraza ni mogoče shraniti."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Dejanje z obrazom je bilo preklicano."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Preveč poskusov. Poskusite znova pozneje."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Preveč poskusov. Preverjanje pristnosti obraza je onemogočeno."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Poskusite znova."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Ni prijavljenih obrazov."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Ta naprava nima tipala za preverjanje pristnosti obraza"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Obraz <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Ikona obraza"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"branje nastavitev sinhronizacije"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Aplikaciji omogoča branje nastavitev sinhronizacije za račun. S tem lahko aplikacija na primer ugotovi, ali je aplikacija Ljudje sinhronizirana z računom."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"vklop in izklop sinhronizacije"</string>
@@ -1222,6 +1255,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Omrežje Wi-Fi nima dostopa do interneta"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Dotaknite se za možnosti"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Spremembe nastavitev dostopne točke"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Pas dostopne točke je spremenjen."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Ta naprava ne podpira prednostne nastavitve samo za 5-GHz pas. Namesto tega bo ta naprava uporabljala 5-GHz pas, ko bo na voljo."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Preklopljeno na omrežje vrste <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Naprava uporabi omrežje vrste <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, ko omrežje vrste <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nima dostopa do interneta. Prenos podatkov se lahko zaračuna."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Preklopljeno z omrežja vrste <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na omrežje vrste <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index bc92b50..6ee1c76 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Vendndodhja"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"qaset te vendndodhja e kësaj pajisjeje"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Të lejohet që <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> të ketë qasje te vendndodhja e kësaj pajisjeje?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Aplikacioni do të ketë qasje te vendndodhja vetëm kur po e përdor aplikacionin."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Të lejohet gjithmonë që <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> të ketë qasje te vendndodhja?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Aplikacioni do të ketë gjithmonë qasje te vendndodhja, edhe kur nuk po e përdor aplikacionin."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalendari"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"qasje te kalendari yt"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Të lejohet që <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> të ketë qasje te kalendari yt?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Ky aplikacion mund të shtojë, të heqë ose të ndryshojë ngjarjet e kalendarit në telefonin tënd. Ky aplikacion mund të dërgojë mesazhe që mund të duket se vijnë nga zotëruesit e kalendarit ose të ndryshojë ngjarjet pa i njoftuar zotëruesit e tyre."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"qasje në komandat shtesë të ofruesit të vendndodhjes"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Lejon aplikacionin të ketë qasje në komandat shtesë të ofruesit për vendndodhjen. Kjo mund ta lejojë aplikacionin të ndërhyjë në operacionin e GPS-së apo të burimeve të tjera për vendndodhjen."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"qasu në vendndodhjen e saktë vetëm në plan të parë"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Ky aplikacion mund të marrë vendndodhjen tënde të saktë në çdo kohë kur është në plan të parë. Këto shërbime të vendndodhjes duhet të jenë të aktivizuara dhe në dispozicion në telefonin tënd që aplikacioni të mund t\'i përdorë. Kjo gjë mund të rritë konsumin e baterisë."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"qasu te vendndodhja e përafërt (bazuar në rrjet)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Ky aplikacion mund të marrë vendndodhjen tënde bazuar në burimet e rrjetit si antenat e operatorëve celulare dhe rrjetet Wi-Fi. Këto shërbime të vendndodhjes duhet të jenë të aktivizuara dhe në dispozicion në tabletin tënd që aplikacioni të mund t\'i përdorë."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Ikona e gjurmës së gishtit"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"menaxho harduerin për vërtetimin e fytyrës"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Lejon aplikacionin të aktivizojë mënyra për shtim e fshirje të shablloneve të përdorura."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"përdor harduerin për vërtetimin e fytyrës"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Lejon aplikacionin të përdorë harduer vërtetimi të fytyrës për procesin e vërtetimit"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Fytyra nuk mund të përpunohej. Provo sërish."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Fytyra ka shumë ndriçim. Provo me më pak ndriçim."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Fytyra shumë e errët. Zbulo burimin e dritës."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Lëvize sensorin pak më larg fytyrës."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Sille sensorin më pranë fytyrës."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Lëvize sensorin më lart."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Lëvize sensorin më poshtë."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Lëvize sensorin djathtas."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Lëvize sensorin majtas."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Shiko nga sensori"</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Nuk u diktua fytyrë"</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Mbaje fytyrën pa lëvizur përpara pajisjes."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Nuk ka harduer për fytyrën."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Mbaroi afati për fytyrën. Provo sërish."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Fytyra nuk mund të ruhet."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Veprimi me fytyrën u anulua."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Shumë përpjekje. Provo sërish më vonë."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Shumë përpjekje. Vërtetimi për fytyrën joaktiv."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Provo sërish."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Nuk ka fytyrë të regjistruar."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Kjo pajisje nuk ka sensor vërtetimi për fytyrën"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Fytyra <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Ikona e fytyrës"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"lexo cilësimet e sinkronizimit"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Lejon aplikacionin të lexojë cilësimet e sinkronizimit për një llogari. Për shembull, kjo mund të përcaktojë nëse aplikacioni \"Kontaktet\" është i sinkronizuar me një llogari."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ndiz ose fik sinkronizimin"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi nuk ka qasje në internet"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Trokit për opsionet"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Ndryshimet në cilësimet e zonës së qasjes për internet"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Brezi yt i zonës së qasjes për internet ka ndryshuar."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Kjo pajisje nuk e mbështet preferencën për vetëm 5 GHz. Përkundrazi, pajisja do të përdorë brezin 5 GHz nëse ka."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Kaloi te <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Pajisja përdor <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kur <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nuk ka qasje në internet. Mund të zbatohen tarifa."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Kaloi nga <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> te <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 2001cf7..2bc76a1 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -279,6 +279,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Локација"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"приступи локацији овог уређаја"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Желите ли да омогућите да <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> приступа локацији овог уређаја?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Апликација ће имати приступ локацији само док користите апликацију."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Желите ли да омогућите да <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> приступа локацији овог уређаја?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Апликација ће увек имати приступ локацији, чак и када не користите апликацију."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Календар"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"приступи календару"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Желите ли да омогућите да <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> приступа календару?"</string>
@@ -405,8 +408,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Ова апликацији може да додаје, уклања или мења догађаје из календара на телефону. Ова апликација може да шаље поруке које изгледају као да их шаљу власници календара или да мења догађаје без знања власника."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"приступ додатним командама добављача локације"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Омогућава апликацији да приступа додатним командама даваоца услуга локације. То може да омогући апликацији да утиче на рад GPS-а или других извора локације."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"приступ прецизној локацији само у првом плану"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Ова апликација може да одреди вашу тачну локацију само када ради у првом плану. Ове услуге локације морају да буду укључене и доступне на телефону да би апликација могла да их користи. То може да повећа потрошњу батерије."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"приступ приближној локацији (утврђена преко мреже)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Ова апликација може да приступи вашој локацији помоћу извора мреже, као што су мобилни предајници и Wi-Fi мреже. Ове услуге локације морају да буду укључене и доступне на таблету да би апликација могла да их користи."</string>
@@ -521,6 +523,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Икона отиска прста"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"управљање хардв. за потврду идентитета помоћу лица"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Дозвољава да апликација активира методе за додавање и брисање шаблона лица ради коришћења."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"коришћење хардв. за потврду идентитета помоћу лица"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Дозвољава да апликација користи хардвер за потврду идентитета помоћу лица"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Обрада лица није успела. Пробајте поново."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Лице је пресветло. Пробајте са слабијим осветљењем."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Лице је исувише тамно. Откријте извор светла."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Удаљите сензор од лица."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Приближите сензор лицу."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Померите сензор навише."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Померите сензор наниже."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Померите сензор удесно."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Померите сензор улево."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Гледајте у сензор."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Није откривено ниједно лице."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Задржите лице испред уређаја без померања."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Харвдер за лице није доступан."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Истекло је време за проверу лица. Пробајте поново."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Није могуће сачувати лице."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Обрада лица је отказана."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Превише покушаја. Пробајте поново касније."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Више покушаја. Потврда идентитета је онемогућена."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Пробајте поново."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Није регистровано ниједно лице."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Овај уређај нема сензор за потврду идентитета помоћу лица"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Лице <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Икона лица"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"читање подешавања синхронизације"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Дозвољава апликацији да чита подешавања синхронизације за налог. На пример, овако може да се утврди да ли је апликација Људи синхронизована са налогом."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"укључивање и искључивање синхронизације"</string>
@@ -1200,6 +1233,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi нема приступ интернету"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Додирните за опције"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Промене подешавања за хотспот"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Опсег хотспота је промењен."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Овај уређај не подржава подешавање само за 5 GHz. Уређај ће користити опсег од 5 GHz када буде доступан."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Прешли сте на тип мреже <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Уређај користи тип мреже <xliff:g id="NEW_NETWORK">%1$s</xliff:g> када тип мреже <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> нема приступ интернету. Можда ће се наплаћивати трошкови."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Прешли сте са типа мреже <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на тип мреже <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 223e7f3..a94ce4e 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -272,19 +272,22 @@
<string name="managed_profile_label" msgid="8947929265267690522">"Byt till jobbprofilen"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakter"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"få tillgång till dina kontakter"</string>
- <string name="permgrouprequest_contacts" msgid="6032805601881764300">"Vill du ge <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> åtkomstbehörighet till dina kontakter?"</string>
+ <string name="permgrouprequest_contacts" msgid="6032805601881764300">"Vill du ge <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> åtkomst till dina kontakter?"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Plats"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"komma åt enhetens platsuppgifter"</string>
- <string name="permgrouprequest_location" msgid="3788275734953323491">"Vill du ge <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> åtkomstbehörighet till enhetens plats?"</string>
+ <string name="permgrouprequest_location" msgid="3788275734953323491">"Vill du ge <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> åtkomst till enhetens plats?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Appen har endast åtkomst till platsen när du använder den."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Vill du ge <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> åtkomst till enhetens plats?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Appen har alltid åtkomst till platsen, även om du inte använder den."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalender"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"få tillgång till din kalender"</string>
- <string name="permgrouprequest_calendar" msgid="289900767793189421">"Vill du ge <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> åtkomstbehörighet till din kalender?"</string>
+ <string name="permgrouprequest_calendar" msgid="289900767793189421">"Vill du ge <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> åtkomst till din kalender?"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"Sms"</string>
<string name="permgroupdesc_sms" msgid="4656988620100940350">"skicka och visa sms"</string>
<string name="permgrouprequest_sms" msgid="7168124215838204719">"Vill du ge <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> behörighet att skicka och visa sms?"</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"Lagring"</string>
<string name="permgroupdesc_storage" msgid="637758554581589203">"få åtkomst till foton, media och filer på din enhet"</string>
- <string name="permgrouprequest_storage" msgid="7885942926944299560">"Vill du ge <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> åtkomstbehörighet till foton, mediafiler och andra filer på enheten?"</string>
+ <string name="permgrouprequest_storage" msgid="7885942926944299560">"Vill du ge <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> åtkomst till foton, mediefiler och andra filer på enheten?"</string>
<string name="permgrouplab_microphone" msgid="171539900250043464">"Mikrofon"</string>
<string name="permgroupdesc_microphone" msgid="4988812113943554584">"spela in ljud"</string>
<string name="permgrouprequest_microphone" msgid="9167492350681916038">"Vill du ge <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> behörighet att spela in ljud?"</string>
@@ -299,7 +302,7 @@
<string name="permgrouprequest_phone" msgid="9166979577750581037">"Vill du ge <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> behörighet att ringa och hantera telefonsamtal?"</string>
<string name="permgrouplab_sensors" msgid="416037179223226722">"Kroppssensorer"</string>
<string name="permgroupdesc_sensors" msgid="7147968539346634043">"få åtkomst till sensordata om dina vitalparametrar"</string>
- <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Vill du ge <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> åtkomstbehörighet till sensordata om vitalparametrar?"</string>
+ <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Vill du ge <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> åtkomst till sensordata om vitalparametrar?"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Hämta fönsterinnehåll"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Granska innehållet i ett fönster som du interagerar med."</string>
<string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Aktivera Explore by touch"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Appen kan lägga till, ta bort eller ändra kalenderhändelser på mobilen. Appen kan skicka meddelanden som ser ut att komma från kalenderns ägare eller ändra uppgifter utan ägarens vetskap."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"få åtkomst till extra kommandon för platsleverantör"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Tillåter att appen får åtkomst till extra kommandon för platsleverantör. Detta kan innebära att appen tillåts störa funktionen för GPS eller andra platskällor."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"endast åtkomst till exakt plats i förgrunden"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Den här appen kan endast få information om din exakta plats när den körs i förgrunden. Platstjänsterna måste ha aktiverats och finnas på mobilen om appen ska kunna använda dem. Detta kan leda till ökad batteriförbrukning."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"få åtkomst till din ungefärliga position (nätverksbaserad)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Appen kan få information om din plats från källor i nätverket, som mobilmaster och Wi-Fi-nätverk. De platstjänsterna måste ha aktiverats och finnas på surfplattan om appen ska kunna använda dem."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Ikon för fingeravtryck"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"hantera maskinvara för ansiktsautentisering"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Tillåter att appen anropar metoder för att lägga till och radera ansiktsmallar."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"använda maskinvara för ansiktsautentisering"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Tillåter att appen använder maskinvara för ansiktsigenkänning vid autentisering"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Det gick inte att läsa av ansiktet. Försök igen."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Ansiktet är för ljust. Testa i svagare belysning."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Ansiktet är för mörkt. Testa i starkare belysning."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Flytta sensorn längre ifrån ansiktet."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Ha sensorn närmare ansiktet."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Flytta sensorn uppåt."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Flytta sensorn nedåt."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Flytta sensorn åt höger."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Flytta sensorn åt vänster."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Titta på sensorn."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Inget ansikte hittades."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Håll ansiktet stilla framför enheten."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Maskinvara för ansiktsigenkänning saknas."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Tidsgränsen för ansikte har nåtts. Försök igen."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Det gick inte att lagra ansiktet."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Ansiktsåtgärden har avbrutits."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Du har gjort för många försök. Försök igen senare."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"För många försök. Ansiktsautentisering inaktiverad"</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Försök igen."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Inget ansikte har registrerats."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Enheten har ingen sensor för ansiktsautentisering"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Ansikte <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Ansikte"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"läsa synkroniseringsinställningar"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Tillåter att appen läser synkroniseringsinställningarna för ett konto. Detta kan användas till exempel för att avgöra om appen Personer är synkroniserad med ett konto."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"aktivera/inaktivera synkronisering"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi-nätverket är inte anslutet till internet"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tryck för alternativ"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Ändringar i inställningarna för surfzon"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Frekvensbandet för surfzonen har ändrats."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Den här enheten har inte stöd för inställningen för att endast använda 5 GHz. I stället används 5 GHz när det är möjligt."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Byte av nätverk till <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> används på enheten när det inte finns internetåtkomst via <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Avgifter kan tillkomma."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Byte av nätverk från <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> till <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 995ed14..28916b4 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -71,10 +71,10 @@
<string name="RuacMmi" msgid="7827887459138308886">"Ukataaji wa simu zinazokera zisizohitajika"</string>
<string name="CndMmi" msgid="3116446237081575808">"Kuonyeshwa kwa nambari inayopiga"</string>
<string name="DndMmi" msgid="1265478932418334331">"Usinisumbue"</string>
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Chaguo msingi za ID ya mpigaji simu za kutozuia. Simu ifuatayo: Imezuiliwa"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Chaguo msingi za kitambulisho cha mpigaji simu huwa kuzuiwa. Simu ifuatayo: Haijazuiliwa"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Chaguo msingi za ID ya mpigaji simu za kutozuia. Simu ifuatayo:Imezuiliwa"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Chaguo msingi za ID ya mpigaji simu za kutozuia. Simu ifuatayo: Haijazuiliwa"</string>
+ <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Chaguomsingi za ID ya mpigaji simu za kutozuia. Simu ifuatayo: Imezuiliwa"</string>
+ <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Chaguomsingi za kitambulisho cha mpigaji simu huwa kuzuiwa. Simu ifuatayo: Haijazuiliwa"</string>
+ <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Chaguomsingi za ID ya mpigaji simu za kutozuia. Simu ifuatayo:Imezuiliwa"</string>
+ <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Chaguomsingi za ID ya mpigaji simu za kutozuia. Simu ifuatayo: Haijazuiliwa"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Huduma haitathminiwi."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Hauwezi kubadilisha mpangilio wa kitambulisho cha anayepiga."</string>
<string name="RestrictedOnDataTitle" msgid="5221736429761078014">"Hakuna huduma ya data kwa vifaa vya mkononi"</string>
@@ -274,6 +274,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Mahali"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"itambue mahali kifaa hiki kilipo"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Ungependa kuiruhusu <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> itambue mahali kifaa kilipo?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Programu itafikia tu data ya mahali ulipo unaipotumia."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Ungependa kuruhusu <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ifikie data ya mahali kifaa hiki kilipo kila wakati?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Programu itaweza kufikia data ya mahali kifaa kilipo hata wakati huitumii."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalenda"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"ifikie kalenda yako"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Ungependa kuiruhusu <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ifikie kalenda yako?"</string>
@@ -400,8 +403,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Programu hii inaweza kuongeza, kuondoa au kubadilisha matukio kwenye simu yako. Pogramu hii inaweza kutuma ujumbe unaoonekana kuwa umetoka kwa wamiliki wa kalenda au kurekebisha matukio bila kuwataarifu wamiliki."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"fikia amri za ziada za mtoa huduma ya mahali"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Ruhusu programu kufikia amri za ziada za mtoa huduma za mahali. Hii huenda ikaruhusu programu ikatize matumizi ya GPS au vyanzo vingine vya eneo."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"kufikia mahali mahususi ikiwa tu programu imefunguliwa kwenye skrini"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Programu hii inaweza kupata mahali halisi ikiwa tu umeifungua kwenye skrini. Ni lazima uwashe huduma hizi za mahali na zipatikane kwenye simu yako ili programu iweze kuzitumia. Hatua hii inaweza kuongeza utumiaji wa betri."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"fikia mahali karibu na hapo (inategemea mtandao)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Programu hii inaweza kupata eneo lako kulingana na vyanzo vya mtandao kama vile minara ya simu na mitandao ya Wi-Fi. Huduma hizi za mahali lazima ziwashwe na zipatikane kwenye kompyuta yako kibao ili programu iweze kuzitumia."</string>
@@ -516,6 +518,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Aikoni ya kitambulisho"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"dhibiti maunzi ya kuthibitisha uso"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Huruhusu programu iombe njia za kuongeza na kufuta violezo vya uso vitakavyotumiwa."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"tumia maunzi ya kuthibistiha uso"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Huruhusu programu ithibitishe uso kwa kutumia maunzi ya kuthibitisha"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Imeshindwa kuchakata uso. Tafadhali jaribu tena."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Uso unang\'aa sana. Tafadhalia punguza mwangaza."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Uso hauna mwangaza wa kutosha. Tafadhali ongeza mwangaza."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Tafadhali sogeza kitambuzi mbali na uso."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Tafadhali sogeza kitambuzi karibu na uso."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Tafadhali sogeza kitambuzi juu."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Tafadhali sogeza kitambuzi chini."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Tafadhali sogeza kitambuzi kulia."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Tafadhali sogeza kitambuzi kushoto."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Tafadhali angalia kitambuzi."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Haikutambua uso wowote"</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Weka uso vizuri mbele ya kifaa."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Maunzi ya uso hayapatikani."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Muda wa kutambua uso umeisha. Jaribu tena."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Huwezi kuhifadhi uso."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Utendaji wa kitambulisho umeghairiwa."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Umejaribu mara nyingi mno. Jaribu tena baadaye."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Umejaribu mara nyingi mno. Kitambuzi cha uso kimezimwa."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Jaribu tena."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Hujasajili uso wowote."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Kifaa hiki hakina kitambuzi kinachothibitisha uso"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Uso wa <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Aikoni ya uso"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"kusoma mipangilio ya usawazishaji"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Inaruhusu programu kusoma mipangilio ya upatanishi wa akaunti. Kwa mfano, huku kunaweza kuamua kama programu ya Watu imepatanishwa na akaunti."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"kuwasha na kuzima usawazishaji"</string>
@@ -773,9 +806,9 @@
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Umejaribu kufungua kompyuta kibao kwa njia isiyo sahihi mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukijaribu tena mara <xliff:g id="NUMBER_1">%2$d</xliff:g> bila mafanikio, kompyuta ndogo itarejeshwa kwenye mipangilio iliyotoka nayo kiwandani na data yote iliyomo itafutwa."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="950408382418270260">"Umekosea majaribio ya kufungua runinga mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukikosea majaribio <xliff:g id="NUMBER_1">%2$d</xliff:g> zaidi, runinga itarejeshwa katika hali iliyotoka nayo kiwandani na data yote ya watumiaji itafutwa."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Umejaribu kufungua simu kwa njia isiyo sahihi mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukijaribu tena mara <xliff:g id="NUMBER_1">%2$d</xliff:g> bila mafanikio, simu itarejeshwa kwenye mipangilio iliyotoka nayo kiwandani na data yote iliyomo itafutwa."</string>
- <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Umejaribu kufungua kompyuta ndogo kwa njia isiyo sahihi mara <xliff:g id="NUMBER">%d</xliff:g>. Kompyuta ndogo haitaweza kuwekwa upya kwa kiwanda chaguo msingi."</string>
+ <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Umejaribu kufungua kompyuta ndogo kwa njia isiyo sahihi mara <xliff:g id="NUMBER">%d</xliff:g>. Kompyuta ndogo haitaweza kuwekwa upya kwa kiwanda chaguomsingi."</string>
<string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="3195755534096192191">"Umekosea majaribio ya kufungua runinga mara <xliff:g id="NUMBER">%d</xliff:g>. Sasa runinga itarejeshwa katika mipangilio iliyotoka nayo kiwandani."</string>
- <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Umejaribu kufungua kompyuta ndogo kwa njia isiyo sahihi mara <xliff:g id="NUMBER">%d</xliff:g>. Kompyuta ndogo haitaweza kuwekwa upya kwa kiwanda chaguo msingi."</string>
+ <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Umejaribu kufungua kompyuta ndogo kwa njia isiyo sahihi mara <xliff:g id="NUMBER">%d</xliff:g>. Kompyuta ndogo haitaweza kuwekwa upya kwa kiwanda chaguomsingi."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Jaribu tena kwa sekunde <xliff:g id="NUMBER">%d</xliff:g>."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Umesahau mchoro?"</string>
<string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Fungua akaunti"</string>
@@ -1065,9 +1098,9 @@
<string name="whichImageCaptureApplication" msgid="3680261417470652882">"Piga picha ukitumia"</string>
<string name="whichImageCaptureApplicationNamed" msgid="8619384150737825003">"Piga picha ukitumia %1$s"</string>
<string name="whichImageCaptureApplicationLabel" msgid="6390303445371527066">"Piga picha"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Tumia kama chaguo msingi la kitendo hiki."</string>
+ <string name="alwaysUse" msgid="4583018368000610438">"Tumia kama chaguomsingi la kitendo hiki."</string>
<string name="use_a_different_app" msgid="8134926230585710243">"Tumia programu tofauti"</string>
- <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Futa chaguo msingi katika mipangilio ya Mfumo > Apps > iliyopakuliwa."</string>
+ <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Futa chaguomsingi katika mipangilio ya Mfumo > Apps > iliyopakuliwa."</string>
<string name="chooseActivity" msgid="7486876147751803333">"Chagua kitendo"</string>
<string name="chooseUsbActivity" msgid="6894748416073583509">"Chagua programu ya kifaa cha USB"</string>
<string name="noApplications" msgid="2991814273936504689">"Hakuna programu zinazoweza kufanya tendo hili."</string>
@@ -1142,8 +1175,8 @@
<string name="volume_icon_description_incall" msgid="8890073218154543397">"Sauti ya simu"</string>
<string name="volume_icon_description_media" msgid="4217311719665194215">"Sauti ya faili"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Sauti ya arifa"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Mlio chaguo msingi"</string>
- <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Chaguo msingi (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_default" msgid="3789758980357696936">"Mlio chaguomsingi"</string>
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Chaguomsingi (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Hamna"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Toni za mlio"</string>
<string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sauti za kengele"</string>
@@ -1176,6 +1209,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi haina muunganisho wa intaneti"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Gusa ili upate chaguo"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Mabadiliko kwenye mipangilio ya mtandao-hewa"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Bendi ya mtandao-hewa wako imebadilika."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Kifaa hiki hakitumii mapendeleo yako ya GHz 5 pekee. Badala yake, kifaa hiki kitatumia bendi ya GHz 5 itakapopatikana."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Sasa inatumia <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Kifaa hutumia <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wakati <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> haina intaneti. Huenda ukalipishwa."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Imebadilisha mtandao kutoka <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na sasa inatumia <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1540,12 +1576,12 @@
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Umeingiza nenosiri lako kwa makosa mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Umeingiza nenosiri lako kwa makosa mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Umechora ruwaza yako ya kufunga kwa makosa mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Umejaribu kufungua kompyuta ndogo kwa njia isiyo sahihi mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%2$d</xliff:g> zaidi yasiyofaulu, kompyuta ndogo itarejeshwa katika mfumo chaguo msingi ilivyotoka kiwandani data yote ya mtumiaji itapotea."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Umejaribu kufungua kompyuta ndogo kwa njia isiyo sahihi mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%2$d</xliff:g> zaidi yasiyofaulu, kompyuta ndogo itarejeshwa katika mfumo chaguomsingi ilivyotoka kiwandani data yote ya mtumiaji itapotea."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="5621231220154419413">"Umekosea majaribio ya kufungua runinga mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukikosea majaribio mengine <xliff:g id="NUMBER_1">%2$d</xliff:g>, runinga itarejeshwa katika hali iliyotoka nayo kiwandani na data yote ya watumiaji itafutwa."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Umejaribu kufungua simu kwa njia isiyo sahihi mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%2$d</xliff:g> zaidi yasiyofaulu, simu itarejeshwa katika mfumo chaguo msingi ilivyotoka kiwandani na data yote ya mtumiaji itapotea."</string>
- <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Umejaribu kufungua kompyuta ndogo kwa njia isiyo sahihi mara <xliff:g id="NUMBER">%d</xliff:g>. Sasa kompyuta ndogo itarejeshwa katika mfumo chaguo msingi ilivyotoka kiwandani."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Umejaribu kufungua simu kwa njia isiyo sahihi mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%2$d</xliff:g> zaidi yasiyofaulu, simu itarejeshwa katika mfumo chaguomsingi ilivyotoka kiwandani na data yote ya mtumiaji itapotea."</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Umejaribu kufungua kompyuta ndogo kwa njia isiyo sahihi mara <xliff:g id="NUMBER">%d</xliff:g>. Sasa kompyuta ndogo itarejeshwa katika mfumo chaguomsingi ilivyotoka kiwandani."</string>
<string name="kg_failed_attempts_now_wiping" product="tv" msgid="4987878286750741463">"Umekosea majaribio ya kufungua runinga mara <xliff:g id="NUMBER">%d</xliff:g>. Sasa runinga itarejeshwa katika hali iliyotoka nayo kiwandani."</string>
- <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Umejaribu kufungua simu kwa njia isiyo sahihi mara <xliff:g id="NUMBER">%d</xliff:g>. Sasa simu itarejeshwa katika mfumo chaguo msingi ilivyotoka kiwandani."</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Umejaribu kufungua simu kwa njia isiyo sahihi mara <xliff:g id="NUMBER">%d</xliff:g>. Sasa simu itarejeshwa katika mfumo chaguomsingi ilivyotoka kiwandani."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Umekosea katika kuweka mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%2$d</xliff:g> bila kufaulu, utaombwa kufungua kompyuta yako ndogo kwa kutumia akaunti yako ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%3$d</xliff:g>."</string>
<string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"Umekosea kuchora mchoro wa kufungua mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukikosea majaribio mengine <xliff:g id="NUMBER_1">%2$d</xliff:g>, utaombwa ufungue runinga yako ukitumia akaunti ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%3$d</xliff:g>."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Umekosea kuchora mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%2$d</xliff:g> yasiyofaulu, utaombwa kufungua simu yako kwa kutumia akaunti ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%3$d</xliff:g>."</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 34a7798..958570f 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"இருப்பிடம்"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"இந்தச் சாதனத்தின் இருப்பிடத்தை அறிந்து கொள்ள"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"இந்தச் சாதனத்தின் இருப்பிடத்தை அணுகுவதற்கு <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> பயன்பாட்டை அனுமதிக்கவா?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"இந்த ஆப்ஸைப் பயன்படுத்தும் சமயத்தில் மட்டுமே, இது உங்கள் இருப்பிடத்தை அணுகும்."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"இதன் இருப்பிடத்தை எப்போதுமே <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> அணுக அனுமதிக்கவா?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"இந்த ஆப்ஸைப் பயன்படுத்தாத சமயங்களில் கூட, இது உங்கள் இருப்பிடத்தை அணுகும்."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"கேலெண்டர்"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"கேலெண்டரை அணுகலாம்"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"கேலெண்டரை அணுகுவதற்கு <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> பயன்பாட்டை அனுமதிக்கவா?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"இந்தப் பயன்பாடு உங்கள் மொபைலில் கேலெண்டர் நிகழ்வுகளைச் சேர்க்கலாம், அகற்றலாம் அல்லது மாற்றலாம். இந்தப் பயன்பாடு கேலெண்டர் உரிமையாளர்கள் அனுப்பியது போல் தோன்றும் செய்திகளை அனுப்பலாம் அல்லது உரிமையாளர்களிடம் தெரிவிக்காமலே கேலெண்டரில் நிகழ்வுகளை மாற்றலாம்."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"கூடுதல் இட வழங்குநரின் கட்டளைகளின் அணுகல்"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"கூடுதல் இட வழங்குநர் கட்டளைகளை அணுகப் பயன்பாட்டை அனுமதிக்கிறது. இது, GPS அல்லது பிற இருப்பிட மூலங்களின் செயல்பாட்டை இடைமறிக்க பயன்பாட்டை அனுமதிக்கலாம்."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"முன்புலத்தில் இயங்கும்போது மட்டும் துல்லியமான இருப்பிடத்தைக் கண்டறிதல்"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"இந்த ஆப்ஸ் முன்புலத்தில் இயங்கும்போது மட்டுமே நீங்கள் இருக்கும் இடத்தைத் துல்லியமாகக் கண்டறியும். உங்கள் மொபைலில், இருப்பிடச் சேவைகளை ஆப்ஸ் பயன்படுத்துவதற்கு வசதியாக, அவை ஆன் செய்யப்பட்டிருக்க வேண்டும். இதனால் பேட்டரி அதிகம் பயன்படுத்தப்படலாம்."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"தோராயமான இருப்பிடத்தை அணுகுதல் (நெட்வொர்க் அடிப்படையில்)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"இந்தப் பயன்பாடு நெட்வொர்க் மூலங்களின் (செல் கோபுரங்கள், வைஃபை நெட்வொர்க்குகள் போன்றவை) அடிப்படையில் உங்கள் இருப்பிடத்தைப் பெறலாம். பயன்பாடு பயன்படுத்தும் வகையில், உங்கள் டேப்லெட்டில் இந்த இருப்பிடச் சேவைகள் இயக்கப்பட்டு, கிடைக்கும்படி இருக்க வேண்டும்."</string>
@@ -518,6 +520,64 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"கைரேகை ஐகான்"</string>
+ <!-- no translation found for permlab_manageFace (2137540986007309781) -->
+ <skip />
+ <!-- no translation found for permdesc_manageFace (8919637120670185330) -->
+ <skip />
+ <!-- no translation found for permlab_useFaceAuthentication (8996134460546804535) -->
+ <skip />
+ <!-- no translation found for permdesc_useFaceAuthentication (5011118722951833089) -->
+ <skip />
+ <!-- no translation found for face_acquired_insufficient (5901287247766106330) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_bright (610606792381297174) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_dark (7229162716976778371) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_close (1980310037427755293) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_far (4494571381828850007) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_high (228411096134808372) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_low (4539774649296349109) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_right (1650292067226118760) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_left (2712489669456176505) -->
+ <skip />
+ <!-- no translation found for face_acquired_poor_gaze (8344973502980415859) -->
+ <skip />
+ <!-- no translation found for face_acquired_not_detected (5707782294589511391) -->
+ <skip />
+ <!-- no translation found for face_acquired_not_steady (3722829465011040042) -->
+ <skip />
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <!-- no translation found for face_error_hw_not_available (6255891785768984615) -->
+ <skip />
+ <!-- no translation found for face_error_timeout (4014326147867150054) -->
+ <skip />
+ <!-- no translation found for face_error_no_space (8224993703466381314) -->
+ <skip />
+ <!-- no translation found for face_error_canceled (283945501061931023) -->
+ <skip />
+ <!-- no translation found for face_error_lockout (3407426963155388504) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_permanent (8198354656746088890) -->
+ <skip />
+ <!-- no translation found for face_error_unable_to_process (238761109287767270) -->
+ <skip />
+ <!-- no translation found for face_error_not_enrolled (9166792142679691323) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (4737289254517095671) -->
+ <skip />
+ <!-- no translation found for face_name_template (7004562145809595384) -->
+ <skip />
+ <string-array name="face_error_vendor">
+ </string-array>
+ <!-- no translation found for face_icon_content_description (4024817159806482191) -->
+ <skip />
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"ஒத்திசைவு அமைப்புகளைப் படித்தல்"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"கணக்கிற்கான ஒத்திசைவு அமைப்புகளைப் படிக்க பயன்பாட்டை அனுமதிக்கிறது. எடுத்துக்காட்டாக, பீப்பிள் பயன்பாடு கணக்குடன் ஒத்திசைக்கப்பட்டுள்ளதா என்பதை இது தீர்மானிக்கலாம்."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ஒத்திசைவை இயக்குவதையும், முடக்குவதையும் மாற்றுதல்"</string>
@@ -1178,6 +1238,12 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"வைஃபையில் இண்டர்நெட் அணுகல் இல்லை"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"விருப்பங்களுக்கு, தட்டவும்"</string>
+ <!-- no translation found for wifi_softap_config_change (8475911871165857607) -->
+ <skip />
+ <!-- no translation found for wifi_softap_config_change_summary (7601233252456548891) -->
+ <skip />
+ <!-- no translation found for wifi_softap_config_change_detailed (8022936822860678033) -->
+ <skip />
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>க்கு மாற்றப்பட்டது"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> நெட்வொர்க்கில் இண்டர்நெட் அணுகல் இல்லாததால், சாதனமானது <xliff:g id="NEW_NETWORK">%1$s</xliff:g> நெட்வொர்க்கைப் பயன்படுத்துகிறது. கட்டணங்கள் விதிக்கப்படலாம்."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> இலிருந்து <xliff:g id="NEW_NETWORK">%2$s</xliff:g>க்கு மாற்றப்பட்டது"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index d45be72..bc21a99 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"స్థానం"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"ఈ పరికర స్థానాన్ని యాక్సెస్ చేయడానికి"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"ఈ పరికర స్థానాన్ని యాక్సెస్ చేయడానికి <b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ని అనుమతించాలా?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"మీరు యాప్ని ఉపయోగిస్తున్నప్పుడు మాత్రమే యాప్ స్థానానికి యాక్సెస్ కలిగి ఉంటుంది."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"ఈ పరికర స్థానాన్ని యాక్సెస్ చేయడానికి <b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ని ఎల్లప్పుడూ అనుమతించాలా?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"ఈ యాప్ ఎల్లప్పుడూ స్థానానికి యాక్సెస్ కలిగి ఉంటుంది, మీరు యాప్ని ఉపయోగించనప్పుడు కూడా."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"క్యాలెండర్"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"మీ క్యాలెండర్ను యాక్సెస్ చేయడానికి"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"మీ క్యాలెండర్ని యాక్సెస్ చేయడానికి <b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ని అనుమతించాలా?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"ఈ యాప్ మీ ఫోన్లో క్యాలెండర్ ఈవెంట్లను జోడించగలదు, తీసివేయగలదు లేదా మార్చగలదు. ఈ యాప్ క్యాలెండర్ యజమానుల నుండి వచ్చినట్లుగా సందేశాలను పంపగలదు లేదా ఈవెంట్లను వాటి యజమానులకు తెలియకుండానే మార్చగలదు."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"అదనపు స్థాన ప్రదాత ఆదేశాలను యాక్సెస్ చేయడం"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"అదనపు స్థాన ప్రదాత ఆదేశాలను యాక్సెస్ చేయడానికి యాప్ను అనుమతిస్తుంది. ఇది GPS లేదా ఇతర స్థాన మూలాల నిర్వహణలో యాప్ ప్రమేయం ఉండేలా అనుమతించవచ్చు."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"స్క్రీన్పై ఉన్నప్పుడు మాత్రమే ఖచ్చితమైన స్థానాన్ని యాక్సెస్ చేయండి"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"ఈ యాప్ స్క్రీన్పై ఉన్నప్పుడు మాత్రమే అది మీ ఖచ్చితమైన స్థానాన్ని తెలుసుకోగలదు. యాప్ ఉపయోగించడానికి మీ ఫోన్లో ఈ స్థాన సేవలను తప్పనిసరిగా ఆన్ చేయాలి మరియు అందుబాటులో ఉండాలి. ఇది బ్యాటరీ వినియోగాన్ని పెంచవచ్చు."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"ఇంచుమించు స్థానాన్ని (నెట్వర్క్-ఆధారితం) యాక్సెస్ చేయడం"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"ఈ యాప్ సెల్ టవర్లు మరియు Wi-Fi నెట్వర్క్ల వంటి నెట్వర్క్ మూలాధారాల ఆధారంగా మీ స్థానాన్ని తెలుసుకోగలదు. యాప్ ఉపయోగించడానికి మీ టాబ్లెట్లో ఈ స్థాన సేవలను తప్పనిసరిగా ఆన్ చేయాలి మరియు అందుబాటులో ఉండాలి."</string>
@@ -518,6 +520,64 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"వేలిముద్ర చిహ్నం"</string>
+ <!-- no translation found for permlab_manageFace (2137540986007309781) -->
+ <skip />
+ <!-- no translation found for permdesc_manageFace (8919637120670185330) -->
+ <skip />
+ <!-- no translation found for permlab_useFaceAuthentication (8996134460546804535) -->
+ <skip />
+ <!-- no translation found for permdesc_useFaceAuthentication (5011118722951833089) -->
+ <skip />
+ <!-- no translation found for face_acquired_insufficient (5901287247766106330) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_bright (610606792381297174) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_dark (7229162716976778371) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_close (1980310037427755293) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_far (4494571381828850007) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_high (228411096134808372) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_low (4539774649296349109) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_right (1650292067226118760) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_left (2712489669456176505) -->
+ <skip />
+ <!-- no translation found for face_acquired_poor_gaze (8344973502980415859) -->
+ <skip />
+ <!-- no translation found for face_acquired_not_detected (5707782294589511391) -->
+ <skip />
+ <!-- no translation found for face_acquired_not_steady (3722829465011040042) -->
+ <skip />
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <!-- no translation found for face_error_hw_not_available (6255891785768984615) -->
+ <skip />
+ <!-- no translation found for face_error_timeout (4014326147867150054) -->
+ <skip />
+ <!-- no translation found for face_error_no_space (8224993703466381314) -->
+ <skip />
+ <!-- no translation found for face_error_canceled (283945501061931023) -->
+ <skip />
+ <!-- no translation found for face_error_lockout (3407426963155388504) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_permanent (8198354656746088890) -->
+ <skip />
+ <!-- no translation found for face_error_unable_to_process (238761109287767270) -->
+ <skip />
+ <!-- no translation found for face_error_not_enrolled (9166792142679691323) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (4737289254517095671) -->
+ <skip />
+ <!-- no translation found for face_name_template (7004562145809595384) -->
+ <skip />
+ <string-array name="face_error_vendor">
+ </string-array>
+ <!-- no translation found for face_icon_content_description (4024817159806482191) -->
+ <skip />
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"సమకాలీకరణ సెట్టింగ్లను చదవడం"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"ఖాతా యొక్క సమకాలీకరణ సెట్టింగ్లను చదవడానికి యాప్ను అనుమతిస్తుంది. ఉదాహరణకు, వ్యక్తుల యాప్ ఖాతాతో సమకాలీకరించబడాలా లేదా అనే విషయాన్ని ఇది నిశ్చయించవచ్చు."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"సమకాలీకరణను ఆన్ మరియు ఆఫ్కు టోగుల్ చేయడం"</string>
@@ -1178,6 +1238,12 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fiకి ఇంటర్నెట్ యాక్సెస్ లేదు"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ఎంపికల కోసం నొక్కండి"</string>
+ <!-- no translation found for wifi_softap_config_change (8475911871165857607) -->
+ <skip />
+ <!-- no translation found for wifi_softap_config_change_summary (7601233252456548891) -->
+ <skip />
+ <!-- no translation found for wifi_softap_config_change_detailed (8022936822860678033) -->
+ <skip />
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>కి మార్చబడింది"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"పరికరం <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>కి ఇంటర్నెట్ యాక్సెస్ లేనప్పుడు <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ని ఉపయోగిస్తుంది. ఛార్జీలు వర్తించవచ్చు."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> నుండి <xliff:g id="NEW_NETWORK">%2$s</xliff:g>కి మార్చబడింది"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 884ee5c..5f96065 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"ตำแหน่ง"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"เข้าถึงตำแหน่งของอุปกรณ์นี้"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"อนุญาตให้ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> เข้าถึงตำแหน่งของอุปกรณ์นี้ไหม"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"แอปจะมีสิทธิ์เข้าถึงตำแหน่งได้ในขณะที่คุณกำลังใช้แอปเท่านั้น"</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"อนุญาตให้ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> เข้าถึงตำแหน่งของอุปกรณ์นี้ทุกครั้งไหม"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"แอปจะมีสิทธิ์เข้าถึงตำแหน่งเสมอแม้ว่าคุณจะไม่ได้ใช้แอป"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"ปฏิทิน"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"เข้าถึงปฏิทิน"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"อนุญาตให้ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> เข้าถึงปฏิทินไหม"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"แอปนี้สามารถเพิ่ม นำออก หรือเปลี่ยนกิจกรรมในปฏิทินบนโทรศัพท์ของคุณ แอปนี้สามารถส่งข้อความที่ดูเหมือนว่ามาจากเจ้าของปฏิทิน หรือเปลี่ยนแปลงกิจกรรมโดยไม่แจ้งให้เจ้าของทราบ"</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"เข้าถึงคำสั่งของโปรแกรมแจ้งตำแหน่งพิเศษ"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"อนุญาตให้แอปเข้าถึงคำสั่งของผู้ให้บริการตำแหน่งเพิ่มเติม ซึ่งอาจทำให้แอปสามารถแทรกแซงการทำงานของ GPS หรือต้นทางของตำแหน่งอื่นๆ ได้"</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"เข้าถึงตำแหน่งที่แม่นยำเมื่ออยู่เบื้องหน้าเท่านั้น"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"แอปนี้รับตำแหน่งที่แม่นยำของคุณได้เมื่อทำงานอยู่เบื้องหน้าเท่านั้น แอปจะใช้บริการตำแหน่งเหล่านี้ได้ต่อเมื่อคุณเปิดบริการและบริการพร้อมใช้งานในโทรศัพท์ของคุณ ซึ่งอาจทำให้มีการใช้แบตเตอรี่มากขึ้น"</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"เข้าถึงตำแหน่งโดยประมาณ (อิงจากเครือข่าย)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"แอปนี้สามารถรับตำแหน่งของคุณโดยอิงจากแหล่งข้อมูลเครือข่าย เช่น เสาสัญญาณมือถือและเครือข่าย Wi-Fi แอปจะใช้บริการตำแหน่งเหล่านี้ได้ต่อเมื่อคุณเปิดบริการและบริการพร้อมใช้งานในแท็บเล็ตของคุณ"</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"ไอคอนลายนิ้วมือ"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"จัดการฮาร์ดแวร์ตรวจสอบสิทธิ์ด้วยใบหน้า"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"อนุญาตให้แอปเรียกใช้วิธีเพิ่มและลบเทมเพลตใบหน้าสำหรับการใช้งาน"</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"ใช้ฮาร์ดแวร์ตรวจสอบสิทธิ์ด้วยใบหน้า"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"อนุญาตให้แอปใช้ฮาร์ดแวร์ตรวจสอบสิทธิ์ด้วยใบหน้าเพื่อตรวจสอบสิทธิ์"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"ประมวลผลใบหน้าไม่ได้ โปรดลองอีกครั้ง"</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"ใบหน้าสว่างเกินไป โปรดลดแสง"</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"ใบหน้ามืดเกินไป โปรดเปิดแหล่งกำเนิดแสง"</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"โปรดขยับเซ็นเซอร์ให้ห่างจากใบหน้ามากขึ้น"</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"โปรดขยับเซ็นเซอร์ให้ใกล้ใบหน้ามากขึ้น"</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"โปรดขยับเซ็นเซอร์ให้สูงขึ้น"</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"โปรดขยับเซ็นเซอร์ให้ต่ำลง"</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"โปรดขยับเซ็นเซอร์ไปทางขวา"</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"โปรดขยับเซ็นเซอร์ไปทางซ้าย"</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"โปรดมองที่เซ็นเซอร์"</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"ไม่พบใบหน้า"</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"ให้ใบหน้าอยู่นิ่งๆ หน้าอุปกรณ์"</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"ฮาร์ดแวร์รู้จำใบหน้าไม่พร้อมใช้งาน"</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"หมดเวลาใช้ใบหน้าแล้ว โปรดลองอีกครั้ง"</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"จัดเก็บข้อมูลใบหน้าไม่ได้"</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"ยกเลิกการดำเนินการกับใบหน้าแล้ว"</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"ดำเนินการหลายครั้งเกินไป ลองอีกครั้งในภายหลัง"</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"ดำเนินการหลายครั้งเกินไป ปิดใช้การตรวจสอบสิทธิ์ด้วยใบหน้าแล้ว"</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"ลองอีกครั้ง"</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"ไม่ได้ลงทะเบียนใบหน้าไว้"</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"อุปกรณ์นี้ไม่มีเซ็นเซอร์ตรวจสอบสิทธิ์ด้วยใบหน้า"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"ใบหน้า <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"ไอคอนใบหน้า"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"อ่านการตั้งค่าการซิงค์แล้ว"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"อนุญาตให้แอปพลิเคชันอ่านการตั้งค่าการซิงค์ของบัญชี ตัวอย่างเช่น การอนุญาตนี้สามารถระบุได้ว่าแอปพลิเคชัน People ซิงค์กับบัญชีหรือไม่"</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"สลับระหว่างเปิดและปิดการซิงค์"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi เชื่อมต่ออินเทอร์เน็ตไม่ได้"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"แตะเพื่อดูตัวเลือก"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"มีการเปลี่ยนแปลงการตั้งค่าฮอตสปอต"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"ย่านความถี่ฮอตสปอตมีการเปลี่ยนแปลง"</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"อุปกรณ์นี้ไม่รองรับค่ากำหนดของคุณเฉพาะสำหรับ 5 GHz เท่านั้น และจะใช้ย่านความถี่ 5 GHz แทน เมื่อใช้ได้"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"เปลี่ยนเป็น <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"อุปกรณ์จะใช้ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> เมื่อ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> เข้าถึงอินเทอร์เน็ตไม่ได้ โดยอาจมีค่าบริการ"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"เปลี่ยนจาก <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> เป็น <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 8e037b5..7586a79 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Lokasyon"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"i-access ang lokasyon ng device na ito"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Payagan ang <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> na i-access ang lokasyon ng device na ito?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Maa-access lang ng app ang lokasyon habang ginagamit mo ang app."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Laging payagan ang <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> na i-access ang lokasyon?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Palaging maa-access ng app ang lokasyon, kahit na hindi mo ginagamit ang app."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalendaryo"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"i-access ang iyong kalendaryo"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Payagan ang <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> na i-access ang iyong kalendaryo?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Makakapagdagdag, makakapag-alis o makakapagbago ang app na ito ng mga event sa kalendaryo sa iyong telepono. Magagawa ng app na ito na magpadala ng mga mensahe na maaaring mukhang mula sa mga may-ari ng kalendaryo o magbago ng mga event nang hindi inaabisuhan ang mga may-ari nito."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"i-access ang mga dagdag na command ng provider ng lokasyon"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Nagbibigay-daan sa app na mag-access ng mga karagdagang command ng provider ng lokasyon. Maaari nitong bigyang-daan ang app na gambalain ang pagpapatakbo ng GPS o ng iba pang mga pinagmulan ng lokasyon."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"i-access lang ang tumpak na lokasyon sa foreground"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Makukuha lang ng app na ito ang iyong eksaktong lokasyon kapag nasa foreground ito. Ang mga serbisyo ng lokasyon na ito ay dapat naka-on at available sa iyong telepono para magamit ng app ang mga ito. Maaaring lumakas ang pagkonsumo ng baterya dahil dito."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"i-access ang tinatantyang lokasyon (batay sa network)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Makukuha ng app na ito ang iyong lokasyon batay sa mga pinagmulan ng network gaya ng mga cell tower at Wi-Fi network. Ang mga serbisyo ng lokasyon na ito ay dapat naka-on at available sa iyong tablet para sa app upang magamit ang mga ito."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Icon ng fingerprint"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"pamahalaan ang hardware sa authentication ng mukha"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Pumapayag na mag-invoke ang app ng paraang magdagdag at mag-delete ng template ng mukha."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"gumamit ng hardware sa pag-authenticate ng mukha"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Pumapayag na gumamit ng face authentication hardware ang app para sa pag-authenticate"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Hindi maiproseso ang mukha. Pakisubukang muli."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Masyadong maliwanag. Pakisubukan sa mas madilim."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Masyadong madilim. Huwag takpan ang ilaw."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Pakilayo sa mukha ang sensor."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Pakilapit sa mukha ang sensor."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Pakitaas ang sensor."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Pakibaba ang sensor."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Pakiusog pakanan ang sensor."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Pakiusog pakaliwa ang sensor."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Tumingin sa sensor."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Walang natukoy na mukha."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Panatilihin sa harap ng device ang mukha."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Hindi available ang hardware para sa mukha."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Nag-time out ang mukha. Subukang muli."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Hindi ma-store ang mukha."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Nakansela ang operation kaugnay ng mukha."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Masyadong maraming pagsubok. Subukang muli mamaya."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Sobrang pagsubok. Bawal na: facial authentication."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Subukang muli."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Walang naka-enroll na mukha."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Walang sensor ng pag-authenticate ng mukha ang device na ito"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Mukha <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Face icon"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"basahin ang mga setting ng sync"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Pinapayagan ang app na basahin ang mga setting ng pag-sync para sa isang account. Halimbawa, matutukoy nito kung naka-sync ang app na Mga Tao sa isang account."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"I-toggle on at off ang pag-sync"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Walang access sa internet ang Wi-Fi"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"I-tap para sa mga opsyon"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Mga pagbabago sa mga setting ng iyong hotspot"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Nagbago ang band ng iyong hotspot."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Hindi sinusuportahan ng device na ito ang kagustuhan mong gumamit lang ng 5GHz. Sa halip, gagamitin ng device na ito ang 5GHz na band kapag available."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Lumipat sa <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Ginagamit ng device ang <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kapag walang access sa internet ang <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Maaaring may mga malapat na singilin."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Lumipat sa <xliff:g id="NEW_NETWORK">%2$s</xliff:g> mula sa <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 34fc23e..e15e52d 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Konum"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"bu cihazın konumuna erişme"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> uygulamasının bu cihazın konumuna erişmesine izin verilsin mi?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Bu uygulama konum bilgisine yalnızca kullanıldığı sırada erişebilecektir."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> uygulamasının bu cihazın konumuna erişmesine her zaman izin verilsin mi?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Bu uygulama, kullanılmadığında bile konum bilgisine her zaman erişebilecektir."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Takvim"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"takviminize erişme"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> uygulamasının takviminize erişmesine izin verilsin mi?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Bu uygulama, telefonunuza takvim etkinlikleri ekleyebilir, mevcut etkinlikleri kaldırabilir ve değiştirebilir. Bu uygulama, takvim sahiplerinden gelmiş gibi görünen iletiler gönderebilir veya takvim sahiplerinin bilgisi olmadan etkinlikleri değiştirebilir."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"ek konum sağlayıcı komutlarına eriş"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Uygulamanın, ekstra konum sağlayıcı komutlarına erişmesine izin verir. Bu izin, uygulamanın GPS veya diğer konum kaynaklarının çalışmasını kesmesine olanak sağlayabilir."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"yalnızca ön planda kesin konuma erişme"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Bu uygulama yalnızca ön plandayken kesin konumunuzu alabilir. Uygulamanın bu hizmetleri kullanabilmesi için telefonunuzda bu konum hizmetleri açık ve kullanılabilir olmalıdır. Bu, pil tüketimini artırabilir."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"konum bilgilerine yaklaşık olarak erişme (ağ tabanlı)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Bu uygulama baz istasyonu ve kablosuz ağ gibi ağ kaynaklarını kullanarak konumunuzu belirleyebilir. Uygulamanın bu hizmetleri kullanabilmesi için tabletinizde bu konum hizmetleri açık ve kullanılabilir olmalıdır."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Parmak izi simgesi"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"yüz kimlik doğrulaması donanımını yönetme"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Uygulamanın, kullanılacak yüz şablonlarını ekleme ve silme yöntemlerini başlatmasına izin verir."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"yüz kimlik doğrulaması donanımını kullanma"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Uygulamanın yüz kimlik doğrulaması donanımı kullanmasına izin verir"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Yüz işlenemedi. Lütfen tekrar deneyin."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Yüzünüz çok parlak. Lütfen ışığı kısmayı deneyin."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Yüzünüz çok karanlık. Lütfen ışığı artırın."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Lütfen sensörü yüzünüzden biraz uzaklaştırın."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Lütfen sensörü yüzünüze yaklaştırın."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Lütfen sensörü daha yukarı kaldırın."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Lütfen sensörü daha aşağı indirin."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Lütfen sensörü sağa kaydırın."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Lütfen sensörü sola kaydırın."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Lütfen sensöre bakın."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Yüz algılanmadı."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Yüzünüzü cihazın önünde sabit bir şekilde tutun."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Yüz donanımı kullanılamıyor."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Yüz için zaman aşımı oluştu. Tekrar deneyin."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Yüz kaydedilemiyor."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Yüz işlemi iptal edildi."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Çok fazla deneme yapıldı. Daha sonra tekrar deneyin."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Çok fazla deneme yapıldı. Yüz kimlik doğrulaması devre dışı bırakıldı."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Tekrar deneyin."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Herhangi bir yüz kaydedilmedi."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Bu cihazda yüz kimlik doğrulaması sensörü yok"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Yüz <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Yüz simgesi"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"senk. ayarlarını okuma"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Uygulamaya bir hesaba ait senkronizasyon ayarlarını okuma izni verir. Örneğin, bu izne sahip bir uygulama Kişiler uygulamasının bir hesapla senkronize olup olmadığını belirleyebilir."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"senkronizasyonu açma/kapatma"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Kablosuz bağlantının internet erişimi yok"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Seçenekler için dokunun"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Hotspot ayarlarınızı değiştirir"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Hotspot bandı değişti."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Bu cihaz yalnızca 5 GHz bandının kullanılmasına yönelik tercihinizi desteklemiyor. Bunun yerine, bu cihaz 5 GHz bandını mevcut olduğunda kullanacak."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ağına geçildi"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ağının internet erişimi olmadığında cihaz <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ağını kullanır. Bunun için ödeme alınabilir."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ağından <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ağına geçildi"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 8729d67..d9ec3fe 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -282,6 +282,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Геодані"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"доступ до геоданих пристрою"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Надати додатку <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> доступ до геоданих пристрою?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Додаток матиме доступ до геоданих, лише коли ви ним користуєтеся."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Завжди надавати додатку <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> доступ до геоданих цього пристрою?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Додаток матиме доступ до геоданих, навіть коли ви ним не користуєтеся."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Календар"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"отримувати доступ до календаря"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Надати додатку <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> доступ до календаря?"</string>
@@ -408,8 +411,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Цей додаток може додавати, вилучати та змінювати події календаря на вашому телефоні. Він також може надсилати повідомлення від імені власників календаря або редагувати події без відома власників."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"отр. дост. до додат. команд пров. місцезн."</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Додаток отримуватиме доступ до додаткових команд постачальника геоданих. Можливе втручання додатка в роботу GPS чи інших джерел геоданих."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"отримувати доступ до даних про точне місцезнаходження лише в активному режимі"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Цей додаток може отримувати дані про ваше точне місцезнаходження лише в активному режимі. Щоб додаток користувався службами локації, вони мають бути наявні й увімкнені на вашому телефоні. Через це може швидше розряджатись акумулятор."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"отримувати дані про приблизне місцезнаходження (на основі мережі)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Цей додаток може отримувати дані про ваше місцезнаходження на основі джерел мережі, як-от антен мобільного зв’язку та мереж Wi-Fi. Щоб додаток міг користуватися цими службами локації, вони мають бути доступними й увімкненими на вашому планшеті."</string>
@@ -524,6 +526,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Значок відбитка пальця"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"керувати обладнанням для автентифікації облич"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Додаток може активувати способи додавання й видалення шаблонів облич."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"застосовувати обладнання для автентифікації облич"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Додаток може застосовувати обладнання для автентифікації облич"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Не вдалося розпізнати обличчя. Повторіть спробу."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Обличчя засвітле. Спробуйте знизити яскравість."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Обличчя затемне. Не заступайте джерело світла."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Перемістіть сканер далі від обличчя."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Перемістіть сканер ближче до обличчя."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Перемістіть сканер вище."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Перемістіть сканер нижче."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Перемістіть сканер праворуч."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Перемістіть сканер ліворуч."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Дивіться на сканер."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Обличчя не виявлено."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Тримайте обличчя нерухомо перед пристроєм."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Обладнання для сканування облич недоступне."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Час очікування обличчя минув. Повторіть спробу."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Не вдається зберегти обличчя."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Дію з обличчям скасовано."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Забагато спроб. Повторіть пізніше."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Забагато спроб. Автентифікацію обличчя вимкнено."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Повторіть спробу."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Немає зареєстрованих облич."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"На цьому пристрої немає сканера для автентифікації облич"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Обличчя <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Значок обличчя"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"читати налаштування синхронізації"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Дозволяє програмі читати налаштування синхронізації для облікового запису, наприклад, визначати, чи програма Люди синхронізується з обліковим записом."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"вмикати й вимикати синхронізацію"</string>
@@ -1222,6 +1255,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Мережа Wi-Fi не має доступу до Інтернету"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Торкніться, щоб відкрити опції"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Зміни в налаштуваннях точки доступу"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Діапазон точки доступу змінено."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"На цьому пристрої не підтримується налаштування лише 5 ГГц. Замість цього буде використовуватися діапазон 5 ГГц, якщо доступно."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Пристрій перейшов на мережу <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Коли мережа <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> не має доступу до Інтернету, використовується <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Може стягуватися плата."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Пристрій перейшов з мережі <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на мережу <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 1fc3e2c..ab5125e 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"مقام"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"اس آلہ کے مقام تک رسائی حاصل کریں"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> کو اس آلہ کے مقام تک رسائی کی اجازت دیں؟"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"جب آپ ایپ استعمال کریں گے تبھی ایپ کو مقام تک رسائی حاصل ہوگی۔"</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> کو ہمیشہ اس آلہ کے مقام تک رسائی کرنے کی اجازت دیں؟"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"اگرچہ آپ ایپ استعمال نہ کر رہے ہوں تب بھی ایپ کو ہمیشہ مقام تک رسائی حاصل ہوگی۔"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"کیلنڈر"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"اپنے کیلنڈر تک رسائی حاصل کریں"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> کو آپ کے کیلنڈر تک رسائی کی اجازت دیں؟"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"یہ اپپ آپ کے فون پر کیلنڈر ایونٹس کو شامل، ہٹا یا ترمیم کر سکتی ہے۔ یہ ایپ وہ پیغامات بھیج سکتی ہے جو کیلنڈر کے مالکان کی جانب سے آنے والے معلوم ہو سکتے ہیں یا ان مالکان کو اطلاع دیے بغیر ایونٹس تبدیل کر سکتی ہے۔"</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"اضافی مقام فراہم کنندہ کی کمانڈز تک رسائی حاصل کریں"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"ایپ کو اضافی مقام فراہم کنندہ کی کمانڈز تک رسائی حاصل کرنے کی اجازت دیتی ہے۔ یہ ایپ کو GPS یا دوسرے مقام کے مآخذ کے عمل کے ساتھ مداخلت کرنے کی اجازت دے سکتی ہے۔"</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"صرف پیش منظر میں درست مقام تک رسائی حاصل کریں"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"یہ ایپ جب پس منظر میں ہوتی ہے تبھی یہ آپ کا صحیح مقام حاصل کر سکتی ہے۔ ایپ کو ان مقام کی سروسز کو استعمال کر سکنے کیلئے ان کا آن ہونا اور آپ کے فون پر دستیاب ہونا ضروری ہے۔"</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"تخمینی مقام تک رسائی حاصل کریں (نیٹ ورک پر مبنی)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"نیٹ ورک مآخذات جیسے کہ سیل ٹاورز اور Wi-Fi نیٹ ورکس کی بنیاد پر یہ ایپ آپ کا مقام حاصل کر سکتی ہے۔ ایپ کو ان مقام کی سروسز کو استعمال کرنے کیلئے ان کا آن ہونا اور آپ کے ٹیبلیٹ پر دستیاب ہونا ضروری ہے۔"</string>
@@ -518,6 +520,64 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"فنگر پرنٹ آئیکن"</string>
+ <!-- no translation found for permlab_manageFace (2137540986007309781) -->
+ <skip />
+ <!-- no translation found for permdesc_manageFace (8919637120670185330) -->
+ <skip />
+ <!-- no translation found for permlab_useFaceAuthentication (8996134460546804535) -->
+ <skip />
+ <!-- no translation found for permdesc_useFaceAuthentication (5011118722951833089) -->
+ <skip />
+ <!-- no translation found for face_acquired_insufficient (5901287247766106330) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_bright (610606792381297174) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_dark (7229162716976778371) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_close (1980310037427755293) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_far (4494571381828850007) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_high (228411096134808372) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_low (4539774649296349109) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_right (1650292067226118760) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_left (2712489669456176505) -->
+ <skip />
+ <!-- no translation found for face_acquired_poor_gaze (8344973502980415859) -->
+ <skip />
+ <!-- no translation found for face_acquired_not_detected (5707782294589511391) -->
+ <skip />
+ <!-- no translation found for face_acquired_not_steady (3722829465011040042) -->
+ <skip />
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <!-- no translation found for face_error_hw_not_available (6255891785768984615) -->
+ <skip />
+ <!-- no translation found for face_error_timeout (4014326147867150054) -->
+ <skip />
+ <!-- no translation found for face_error_no_space (8224993703466381314) -->
+ <skip />
+ <!-- no translation found for face_error_canceled (283945501061931023) -->
+ <skip />
+ <!-- no translation found for face_error_lockout (3407426963155388504) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_permanent (8198354656746088890) -->
+ <skip />
+ <!-- no translation found for face_error_unable_to_process (238761109287767270) -->
+ <skip />
+ <!-- no translation found for face_error_not_enrolled (9166792142679691323) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (4737289254517095671) -->
+ <skip />
+ <!-- no translation found for face_name_template (7004562145809595384) -->
+ <skip />
+ <string-array name="face_error_vendor">
+ </string-array>
+ <!-- no translation found for face_icon_content_description (4024817159806482191) -->
+ <skip />
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"مطابقت پذیری کی ترتیبات پڑھیں"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"ایپ کو کسی اکاؤنٹ کیلئے مطابقت پذیری کی ترتیبات پڑھنے کی اجازت دیتا ہے۔ مثلا، یہ تعین کرسکتا ہے کہ آیا People ایپ کسی اکاؤنٹ کے ساتھ مطابقت پذیر ہے۔"</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"مطابقت پذیری آن اور آف ٹوگل کریں"</string>
@@ -1178,6 +1238,12 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi کو انٹرنیٹ تک رسائی نہیں ہے"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"اختیارات کیلئے تھپتھپائیں"</string>
+ <!-- no translation found for wifi_softap_config_change (8475911871165857607) -->
+ <skip />
+ <!-- no translation found for wifi_softap_config_change_summary (7601233252456548891) -->
+ <skip />
+ <!-- no translation found for wifi_softap_config_change_detailed (8022936822860678033) -->
+ <skip />
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> پر سوئچ ہو گیا"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"جب <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> کو انٹرنیٹ تک رسائی نہیں ہوتی ہے تو آلہ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> کا استعمال کرتا ہے۔ چارجز لاگو ہو سکتے ہیں۔"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> سے <xliff:g id="NEW_NETWORK">%2$s</xliff:g> پر سوئچ ہو گیا"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index c9df779..e544942 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Joylashuv"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"shu qurilmaning joylashuvi haqidagi axborotga kirish"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> uchun bu qurilmaning joylashuvi haqidagi axborotdan foydalanishiga ruxsat berilsinmi?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Bu ilovadan foydalanilayotdangina u joylashuv axborotidan foydalana oladi."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> uchun bu qurilmaning joylashuvi haqidagi axborotdan foydalanishiga ruxsat berilsinmi?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Bu ilovadan foydalanilmaganda ham u doim joylashuv axborotidan foydalana oladi."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Taqvim"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"taqvimingizga kirish"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> uchun taqvimingizga ruxsat berilsinmi?"</string>
@@ -402,15 +405,14 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Bu ilova telefonga taqvim tadbirlarini qo‘shishi, olib tashlashi yoki o‘zgartirishi mumkin. Bu ilova taqvim egalari nomidan ko‘rinadigan SMS yuborishi yoki egalarini ogohlantirmasdan tadbirlarni o‘zgartirishi mumkin."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"qo‘shimcha manzillarga kirish buyruqlari"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Ilovaga qo‘shimcha joylashuv xizmati buyruqlaridan foydalanishga ruxsat beradi. Uning yordamida ilova GPS yoki boshqa joylashuv ma’lumoti manbalarining ishlashiga xalaqit qilishi mumkin."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
- <string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Bu ilova faqat fon rejimida aniq joylashuv axborotingizdan foydalanishi mumkin. Ilova ushbu joylashuv xizmatlaridan foydalana olishi uchun ular telefoningizda yoniq bo‘lishi va ishlashi kerak. Bunda batareya sarfi oshishi mumkin."</string>
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"aniq joylashuv axborotini olishga faqat old fonda ruxsat"</string>
+ <string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Bu ilova faqat fon rejimida aniq joylashuv axborotingizdan foydalanishi mumkin. Ilova ushbu joylashuv xizmatlaridan foydalana olishi uchun ular telefoningizda yoniq turishi va ishlashi kerak. Bunda batareya sarfi oshishi mumkin."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"taxminiy joylashuv (tarmoq asosida) ma’lumotlaridan foydalanishga ruxsat"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Bu ilova Wi-Fi va uyali tarmoq antennalari kabi tarmoq manbalari asosida joylashuvingiz axborotini olishi mumkin. Ilova ushbu joylashuv xizmatlaridan foydalana olishi uchun ular planshetda yoniq bo‘lishi va ishlashi kerak."</string>
<string name="permdesc_accessCoarseLocation" product="tv" msgid="1884022719818788511">"Bu ilova Wi-Fi va uyali tarmoq antennalari kabi tarmoq manbalari asosida joylashuvingiz axborotini olishi mumkin. Ilova ushbu joylashuv xizmatlaridan foydalana olishi uchun ular televizorda yoniq bo‘lishi va ishlashi kerak."</string>
<string name="permdesc_accessCoarseLocation" product="default" msgid="7788009094906196995">"Bu ilova Wi-Fi va uyali tarmoq antennalari kabi tarmoq manbalari asosida joylashuvingiz axborotini olishi mumkin. Ilova ushbu joylashuv xizmatlaridan foydalana olishi uchun ular telefoningizda yoniq bo‘lishi va ishlashi kerak."</string>
- <string name="permlab_accessBackgroundLocation" msgid="5742466381902568536">"joylashuv axborotiga ruxsat fon rejimida"</string>
- <string name="permdesc_accessBackgroundLocation" msgid="6371533283380774135">"Bu ilova fon rejimida aniq joylashuv axborotingizdan foydalanishi mumkin. Ilova ushbu joylashuv xizmatlaridan foydalana olishi uchun ular telefoningizda yoniq bo‘lishi va ishlashi kerak. Bunda batareya sarfi oshishi mumkin."</string>
+ <string name="permlab_accessBackgroundLocation" msgid="5742466381902568536">"fonda joylashuv axborotini olishga ruxsat"</string>
+ <string name="permdesc_accessBackgroundLocation" msgid="6371533283380774135">"Bu ilova fon rejimida aniq joylashuv axborotingizdan foydalanishi mumkin. Ilova ushbu joylashuv xizmatlaridan foydalana olishi uchun ular telefoningizda yoniq turishi va ishlashi kerak. Bunda batareya sarfi oshishi mumkin."</string>
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"audio sozlamalaringizni o‘zgartirish"</string>
<string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Ilovalarga tovush va ovoz chiqarish uchun foydalaniladigan karnay kabi global audio sozlamalarini o‘zgartirish uchun ruxsat beradi."</string>
<string name="permlab_recordAudio" msgid="3876049771427466323">"ovoz yozib olish"</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Barmoq izi belgisi"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"yuzni aniqlash qurilmasini boshqarish"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Ilova foydalanish uchun yuz namunalarini qo‘shish va o‘chirish usullarini tatbiq qilishi mumkin."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"yuzni aniqlash qurilmasidan foydalanish"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Haqiqiylikni tekshirish uchun skanerdan foydalanish imkonini beradi"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Yuz aniqlanmadi. Qaytadan urining."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Yuz juda yorqin. Yorug‘likni kamaytiring."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Yuz juda xira. Yorug‘likni oshiring."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Qurilmani yuzingizdan uzoqroq tuting."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Qurilmani yuzga yaqin tuting."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Qurilmani teparoq ko‘taring."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Qurilmani pastroq tushiring."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Qurilmani o‘ngroq suring."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Qurilmani chaproq suring."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Qurilma kamerasiga qarang."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Yuz aniqlanmadi."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Yuzingizni qurilmaga qarating."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Yuzni aniqlash uchun qurilma mavjud emas."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Yuzni aniqlash vaqti tugadi. Qaytadan urining."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Aniqlangan yuz saqlanmadi."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Yuzni aniqlash bekor qilindi."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Juda ko‘p urinildi. Keyinroq qaytadan urining."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Juda ko‘p urinildi. Skaner faolsizlantirildi."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Qaytadan urining."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Hech qanday yuz qayd qilinmagan."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Bu qurilmada yuzni aniqlash uchun skaner mavjud emas"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Yuz <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Yuz belgisi"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"sinx-sh sozlamalarini o‘qish"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Ilovaga hisobning sinxronlash sozlamalarini o‘qish uchun ruxsat beradi. Masalan, bu \"Odamlar\" ilovasi hisob bilan sinxronlangan yoki aksini aniqlay oladi."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"sinx.ni yoqish/o‘chirish"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi tarmoqda internet aloqasi yo‘q"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Variantlarni ko‘rsatish uchun bosing"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Hotspot sozlamalari o‘zgartirildi"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Hotspot chastotasi o‘zgartirildi."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Qurilma faqat 5 GGs chastotasida ishlay olmaydi. Imkon qadar bu chastotadan foydalaniladi."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> tarmog‘iga ulanildi"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Agar <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tarmoqda internet uzilsa, qurilma <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ga ulanadi. Sarflangan trafik uchun haq olinishi mumkin."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> tarmog‘idan <xliff:g id="NEW_NETWORK">%2$s</xliff:g> tarmog‘iga o‘tildi"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index f0ee98c..54a7e76 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Vị trí"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"truy cập vị trí của thiết bị này"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Cho phép <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> truy cập vào vị trí của thiết bị này?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Ứng dụng sẽ chỉ có quyền truy cập vào vị trí khi bạn sử dụng."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Luôn cho phép <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> truy cập vị trí thiết bị?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Ứng dụng sẽ luôn có quyền truy cập vào vị trí, ngay cả khi bạn không sử dụng."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Lịch"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"truy cập lịch của bạn"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Cho phép <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> truy cập vào lịch của bạn?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Ứng dụng này có thể thêm, xóa hoặc thay đổi sự kiện lịch trên điện thoại của bạn. Ứng dụng này có thể gửi các tin nhắn trông có vẻ như được gửi từ các chủ sở hữu lịch hoặc thay đổi sự kiện mà không thông báo cho chủ sở hữu."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"truy cập vào các lệnh của nhà cung cấp vị trí bổ sung"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Cho phép ứng dụng truy cập vào các lệnh của nhà cung cấp vị trí bổ sung. Điều này có thể cho phép ứng dụng can thiệp vào hoạt động của Hệ thống định vị toàn cầu (GPS) hoặc các nguồn vị trí khác."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"chỉ truy cập vị trí chính xác trong nền trước"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Bất cứ khi nào chạy trong nền trước, ứng dụng này có thể nhận thông tin vị trí chính xác của bạn. Để ứng dụng có thể sử các dụng dịch vụ vị trí, điện thoại của bạn phải có các dịch vụ này và dịch vụ ở trạng thái bật. Hoạt động này có thể tăng mức tiêu thụ pin."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"truy cập vị trí gần đúng (dựa vào mạng)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Ứng dụng này có thể nhận thông tin vị trí của bạn dựa trên các nguồn mạng như tháp phát sóng di động và mạng Wi-Fi. Các dịch vụ vị trí này phải được bật và khả dụng trên máy tính bảng của bạn để ứng dụng có thể sử dụng chúng."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Biểu tượng vân tay"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"quản lý phần cứng xác thực khuôn mặt"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Cho phép ứng dụng gọi ra các phương pháp để thêm và xóa mẫu khuôn mặt sử dụng."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"sử dụng phần cứng xác thực khuôn mặt"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Cho phép ứng dụng sử dụng phần cứng xác thực khuôn mặt để tiến hành xác thực"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Không thể xử lý khuôn mặt. Vui lòng thử lại."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Khuôn mặt quá sáng. Hãy thử dưới ánh sáng yếu hơn."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Khuôn mặt quá tối. Hãy tìm nguồn sáng tốt hơn."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Hãy đưa cảm biến ra xa khuôn mặt hơn."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Hãy đưa cảm biến lại gần khuôn mặt hơn."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Hãy đưa cảm biến lên cao hơn."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Hãy đưa cảm biến xuống thấp hơn."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Hãy đưa cảm biến sang bên phải."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Hay đưa cảm biến sang bên trái."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Hãy nhìn vào cảm biến."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Không phát hiện được khuôn mặt nào."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Hãy giữ yên khuôn mặt trước thiết bị."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Không truy cập được phần cứng nhận dạng khuôn mặt."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Đã hết thời gian chờ khuôn mặt. Hãy thử lại."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Không thể lưu khuôn mặt."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Đã hủy thao tác dùng khuôn mặt."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Bạn đã thử quá nhiều lần. Hãy thử lại sau."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Đã thử quá nhiều lần. Đã tắt xác thực khuôn mặt."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Hãy thử lại."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Bạn chưa đăng ký khuôn mặt."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Thiết bị này không có cảm biến xác thực khuôn mặt"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Khuôn mặt <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Biểu tượng khuôn mặt"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"đọc cài đặt đồng bộ hóa"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Cho phép ứng dụng đọc cài đặt đồng bộ hóa cho tài khoản. Ví dụ: việc này có thể xác định liệu ứng dụng Mọi người đã được đồng bộ hóa với tài khoản chưa."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"chuyển đổi bật và tắt đồng bộ hóa"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi không có quyền truy cập Internet"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Nhấn để biết tùy chọn"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Những thay đổi trong mục cài đặt điểm phát sóng của bạn"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Bằng tần của điểm phát sóng đã thay đổi."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Thiết bị này không hỗ trợ tùy chọn chỉ sử dụng băng tần 5 GHz. Thay vào đó, thiết bị này sẽ sử dụng băng tần 5 GHz khi có thể."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Đã chuyển sang <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Thiết bị sử dụng <xliff:g id="NEW_NETWORK">%1$s</xliff:g> khi <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> không có quyền truy cập Internet. Bạn có thể phải trả phí."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Đã chuyển từ <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> sang <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index a97553f..e498c03 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"位置信息"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"获取此设备的位置信息"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"允许<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>获取此设备的位置信息吗?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"只有当您使用该应用时,该应用才有权获取位置信息。"</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"一律允许<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>获取此设备的位置信息吗?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"即使您并未使用该应用,该应用也将始终有权获取位置信息。"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"日历"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"访问您的日历"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"允许<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>访问您的日历吗?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"此应用可在手机上添加、移除或更改日历活动。此应用可能会以日历所有者的身份发送消息,或在不通知所有者的情况下更改活动。"</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"获取额外的位置信息提供程序命令"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"允许该应用使用其他的位置信息提供程序命令。此权限使该应用可以干扰GPS或其他位置信息源的运作。"</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"只能在前台获取精确的位置信息"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"此应用只有在前台运行时才能获取您的精确位置信息。您的手机必须支持并开启这些位置信息服务,此应用才能使用这些服务。这可能会增加耗电量。"</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"访问大致位置信息(以网络为依据)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"此应用可根据网络来源(例如基站和 WLAN 网络)获取您的位置信息。您的平板电脑必须支持并开启这些位置信息服务,此应用才能使用这些服务。"</string>
@@ -518,6 +520,64 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"指纹图标"</string>
+ <!-- no translation found for permlab_manageFace (2137540986007309781) -->
+ <skip />
+ <!-- no translation found for permdesc_manageFace (8919637120670185330) -->
+ <skip />
+ <!-- no translation found for permlab_useFaceAuthentication (8996134460546804535) -->
+ <skip />
+ <!-- no translation found for permdesc_useFaceAuthentication (5011118722951833089) -->
+ <skip />
+ <!-- no translation found for face_acquired_insufficient (5901287247766106330) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_bright (610606792381297174) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_dark (7229162716976778371) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_close (1980310037427755293) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_far (4494571381828850007) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_high (228411096134808372) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_low (4539774649296349109) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_right (1650292067226118760) -->
+ <skip />
+ <!-- no translation found for face_acquired_too_left (2712489669456176505) -->
+ <skip />
+ <!-- no translation found for face_acquired_poor_gaze (8344973502980415859) -->
+ <skip />
+ <!-- no translation found for face_acquired_not_detected (5707782294589511391) -->
+ <skip />
+ <!-- no translation found for face_acquired_not_steady (3722829465011040042) -->
+ <skip />
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <!-- no translation found for face_error_hw_not_available (6255891785768984615) -->
+ <skip />
+ <!-- no translation found for face_error_timeout (4014326147867150054) -->
+ <skip />
+ <!-- no translation found for face_error_no_space (8224993703466381314) -->
+ <skip />
+ <!-- no translation found for face_error_canceled (283945501061931023) -->
+ <skip />
+ <!-- no translation found for face_error_lockout (3407426963155388504) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_permanent (8198354656746088890) -->
+ <skip />
+ <!-- no translation found for face_error_unable_to_process (238761109287767270) -->
+ <skip />
+ <!-- no translation found for face_error_not_enrolled (9166792142679691323) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (4737289254517095671) -->
+ <skip />
+ <!-- no translation found for face_name_template (7004562145809595384) -->
+ <skip />
+ <string-array name="face_error_vendor">
+ </string-array>
+ <!-- no translation found for face_icon_content_description (4024817159806482191) -->
+ <skip />
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"读取同步设置"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"允许该应用读取某个帐号的同步设置。例如,此权限可确定“联系人”应用是否与某个帐号同步。"</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"启用和停用同步"</string>
@@ -1178,6 +1238,12 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"此 WLAN 网络无法访问互联网"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"点按即可查看相关选项"</string>
+ <!-- no translation found for wifi_softap_config_change (8475911871165857607) -->
+ <skip />
+ <!-- no translation found for wifi_softap_config_change_summary (7601233252456548891) -->
+ <skip />
+ <!-- no translation found for wifi_softap_config_change_detailed (8022936822860678033) -->
+ <skip />
<string name="network_switch_metered" msgid="4671730921726992671">"已切换至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"设备会在<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>无法访问互联网时使用<xliff:g id="NEW_NETWORK">%1$s</xliff:g>(可能需要支付相应的费用)。"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"已从<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>切换至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 8d94421..cb32875 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"位置資訊"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"存取此裝置的位置"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<b></b>存取此裝置的位置資訊嗎?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"只有在您使用此應用程式時,應用程式才能存取位置資訊。"</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"要一律允許「<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>」存取此裝置的位置資訊嗎?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"即使您沒有使用此應用程式,應用程式亦一直能夠存取位置資訊。"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"日曆"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"存取您的日曆"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<b></b>存取您的日曆嗎?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"此應用程式可以加入、移除或變更您的手機中的日曆活動。此應用程式可以傳送看似來自日曆擁有者的訊息,或變更活動而不通知其擁有者。"</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"接收額外的位置提供者指令"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"允許應用程式存取額外的位置提供者指令。這項設定可能會使應用程式干擾 GPS 或其他位置來源的運作。"</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"只在前景存取精確位置"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"此應用程式只可在前台運行時獲取您的確實位置資訊。您的手機必須支援並啟用這些位置資訊服務,應用程式方可使用這項功能,但這樣做可能會增加耗電量。"</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"存取約略位置 (根據網絡)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"此應用程式可以根據您的網絡來源 (例如手機訊號塔和 Wi-Fi 網絡) 取得您的位置。您的平板電腦必須支援並啟用這些位置資訊服務,應用程式方可使用這項功能。"</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"指紋圖示"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"管理臉孔驗證硬件"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"允許應用程式調用方法,以加入和刪除可用的臉孔範本。"</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"使用臉孔驗證硬件"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"允許應用程式使用臉孔驗證硬件來驗證"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"無法識別臉孔,請再試一次。"</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"臉孔太光亮,請在較暗的光線下嘗試。"</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"臉孔太暗,請尋找更佳光源。"</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"請將感應器移離臉孔。"</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"請將感應器靠近臉孔。"</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"請將感應器向上移。"</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"請將感應器向下移。"</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"請將感應器向右移。"</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"請將感應器向左移。"</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"請看著感應器。"</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"未偵測到任何臉孔。"</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"請在裝置前保持臉孔不動。"</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"無法使用臉孔識別硬件。"</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"臉孔操作已逾時,請再試一次。"</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"無法儲存臉孔。"</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"臉孔操作已取消。"</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"嘗試次數過多,請稍後再試。"</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"嘗試次數過多,臉孔驗證已停用。"</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"請再試一次。"</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"未註冊任何臉孔。"</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"此裝置沒有臉孔驗證感應器"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"臉孔 <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"臉孔圖示"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"讀取同步處理設定"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"允許應用程式讀取帳戶的同步設定,例如確定「通訊錄」應用程式是否和某個帳戶保持同步。"</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"開啟和關閉同步功能"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi 並未連接互聯網"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"輕按即可查看選項"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"您的熱點設定變更"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"您的熱點頻段已變更。"</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"此裝置不支援只限 5 GHz 的偏好設定,但會在 5 GHz 頻段可用時採用。"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"已切換至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"裝置會在 <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> 無法連線至互聯網時使用<xliff:g id="NEW_NETWORK">%1$s</xliff:g> (可能需要支付相關費用)。"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"已從<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>切換至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 0e04dc7..b6e71cf 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"位置"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"存取這台裝置的位置資訊"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」存取這個裝置的位置資訊嗎?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"該應用程式只有在你使用時,才能存取位置資訊。"</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"要一律允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<b></b>存取這個裝置的位置資訊嗎?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"該應用程式即使在你未使用時,也隨時可以存取位置資訊。"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"日曆"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"存取你的日曆"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」存取你的日曆嗎?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"這個應用程式可在手機上新增、移除或變更日曆活動。提醒你,這個應用程式可能會以日曆擁有者的名義傳送訊息,或是在不通知日曆擁有者的情況下變更活動內容。"</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"接收額外的位置提供者指令"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"允許應用程式存取額外位置資訊提供者指令。這項設定可能會造成應用程式干擾 GPS 或其他位置資訊來源的運作。"</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"僅可在前景中取得精確位置"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"這個應用程式只能在前景中取得你的確切位置。你必須在手機上開啟這些定位服務,才能讓這個應用程式取得確切位置。請注意,這麼做可能會增加耗電量。"</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"存取概略位置 (以網路為依據)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"這個應用程式可根據網路來源 (例如基地台和 Wi-Fi 網路) 取得你的位置資訊。你必須在平板電腦上開啟這類定位服務,才能讓這個應用程式取得位置資訊。"</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"指紋圖示"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"管理臉孔驗證硬體"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"允許應用程式呼叫方法來新增及移除可用的臉孔範本。"</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"使用臉孔驗證硬體"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"允許應用程式使用臉孔驗證硬體進行驗證"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"無法處理臉孔,請再試一次。"</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"臉孔過亮。請移至光線適中的場所,然後再試一次。"</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"臉孔過暗。請增添光源,然後再試一次。"</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"請將感應器移到距離臉孔較遠處。"</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"請將感應器靠近臉孔。"</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"請將感應器往上移動。"</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"請將感應器往下移動。"</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"請將感應器往右移動。"</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"請將感應器往左移動。"</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"請直視感應器。"</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"未偵測到任何臉孔。"</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"請將臉孔保持在裝置前方。"</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"無法使用臉孔硬體。"</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"臉孔處理作業逾時,請再試一次。"</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"無法儲存臉孔。"</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"臉孔處理作業已取消。"</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"嘗試次數過多,請稍後再試。"</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"嘗試次數過多,臉孔驗證功能已停用。"</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"請再試一次。"</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"未登錄任何臉孔。"</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"這個裝置沒有臉孔驗證感應器"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"臉孔 <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"臉孔圖示"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"讀取同步處理設定"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"允許應用程式讀取帳戶的同步處理設定,例如判斷「使用者」應用程式是否和某個帳戶進行同步處理。"</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"開啟及關閉同步功能"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"Wi-Fi 沒有網際網路連線"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"輕觸即可查看選項"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"無線基地台設定變更"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"你的無線基地台頻帶已變更。"</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"這個裝置不支援你的偏好設定 (僅限 5GHz),而是會在 5GHz 可用時使用該頻帶。"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"已切換至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"裝置會在無法連上「<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>」時切換至「<xliff:g id="NEW_NETWORK">%1$s</xliff:g>」(可能需要支付相關費用)。"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"已從 <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> 切換至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index d085068..85c63b9 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -276,6 +276,9 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Indawo"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"finyelela kundawo yale divayisi"</string>
<string name="permgrouprequest_location" msgid="3788275734953323491">"Vumela i-<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ukuthi ingene kundawo yale divayisi?"</string>
+ <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"Uhlelo lokusebenza luzoba nokufinyelela kundawo kuphela uma usebenzisa uhlelo lokusebenza."</string>
+ <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"Hlala uvumela i-<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ukuthi ifinyelele indawo yale divayisi?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"Uhlelo lokusebenza luzohlala lunokufinyelela kundawo, nanoma ungasebenzisi uhlelo lokusebenza."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Ikhalenda"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"finyelela kukhalenda yakho"</string>
<string name="permgrouprequest_calendar" msgid="289900767793189421">"Vumela i-<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ukuthi ifinyelele kukhalenda yakho?"</string>
@@ -402,8 +405,7 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Lolu hlelo lokusebenza lungangeza, lisuse, noma lishintshe imicimbi yekhalenda efonini yakho. Lolu hlelo lokusebenza lingathumela imilayezo engabonakala ivela kusuka kubanikazi bekhalenda, noma lishintshe imicimbi ngaphandle kokwazisa abanikazi."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"finyelela kweminye imiyalo yokunikeza indawo"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Ivumela uhlelo lokusebenza ukufinyelela imiyalo eyengeziwe yabahlinzeki bendawo. Lokhu kungase kuvumele uhlelo lokusebenza ukuthi liphazamisane nomsebenzi we-GPS noma eminye imithombo yendawo."</string>
- <!-- no translation found for permlab_accessFineLocation (6265109654698562427) -->
- <skip />
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"finyelela indawo eqondile kuphela phambili"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Lolu hlelo lokusebenza lungakutholela indawo eqondile kuphela uma liphambili. Lawa masevisi endawo kufanele avulwe futhi atholakale efonini yakho ukuze uhlelo lokusebenza lukwazi ukuwasebenzisa. Lokhu kungakhulisa ukusebenza kwebhethri."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"finyelela kundawo elinganiselwe (esuselwa kunethiwekhi)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"Lolu hlelo lokusebenza lungathola indawo yakho ngokususelwe kumithombo yenethiwekhi njengamathawa eseli namanethiwekhi e-Wi-Fi. Lawa masevisi endawo kufanele avulwe futhi atholakale kuthebhulethi yakho ukuze uhlelo lokusebenza lukwazi ukuwasebenzisa."</string>
@@ -518,6 +520,37 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Isithonjana sezigxivizo zeminwe"</string>
+ <string name="permlab_manageFace" msgid="2137540986007309781">"phatha izingxenyekazi zekhompuyutha zokufakazela ubuqiniso zobuso"</string>
+ <string name="permdesc_manageFace" msgid="8919637120670185330">"Ivumela uhlelo lokusebenza ukuthi luhoxise izindlela zokungeza nokususa amathempulethi obuso azosetshenziswa."</string>
+ <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"sebenzisa izingxenyekazi zekhompuyutha zokufakazela ubuqiniso kobuso"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Ivumela uhlelo lokusebenza ukuthi lusebenzise ukufakazela ubuqiniso bobuso bezingxenyekazi ukuze kufakazelwe ubuqiniso"</string>
+ <string name="face_acquired_insufficient" msgid="5901287247766106330">"Ayikwazanga ukucubungula ubuso. Sicela uzame futhi."</string>
+ <string name="face_acquired_too_bright" msgid="610606792381297174">"Ubuso bukhanya kakhulu. Sicela uzame ekukhanyeni okuncane."</string>
+ <string name="face_acquired_too_dark" msgid="7229162716976778371">"Ubuso bumnyama kakhulu. Sicela uvule umthombo wokukhanya."</string>
+ <string name="face_acquired_too_close" msgid="1980310037427755293">"Sicela uhambise inzwa kude kunobuso."</string>
+ <string name="face_acquired_too_far" msgid="4494571381828850007">"Sicela ulethe inzwa eduze kobuso."</string>
+ <string name="face_acquired_too_high" msgid="228411096134808372">"Sicela uhambise inzwa phezulu."</string>
+ <string name="face_acquired_too_low" msgid="4539774649296349109">"Sicela uhambise inzwa ngezansi."</string>
+ <string name="face_acquired_too_right" msgid="1650292067226118760">"Sicela uhambise inzwa ngakwesokudla."</string>
+ <string name="face_acquired_too_left" msgid="2712489669456176505">"Sicela uhambise inzwa ngakwesokunxele."</string>
+ <string name="face_acquired_poor_gaze" msgid="8344973502980415859">"Sicela ubheke kunzwa."</string>
+ <string name="face_acquired_not_detected" msgid="5707782294589511391">"Abukho ubuso obutholiwe."</string>
+ <string name="face_acquired_not_steady" msgid="3722829465011040042">"Gcina ubuso bumile ngaphambi kwedivayisi."</string>
+ <string-array name="face_acquired_vendor">
+ </string-array>
+ <string name="face_error_hw_not_available" msgid="6255891785768984615">"Izingxenyekazi zekhompuyutha zobuso azitholakali."</string>
+ <string name="face_error_timeout" msgid="4014326147867150054">"Kufinyelelwe kusikhathi sokuvala sobuso. Zama futhi."</string>
+ <string name="face_error_no_space" msgid="8224993703466381314">"Ubuso abukwazi ukugcinwa."</string>
+ <string name="face_error_canceled" msgid="283945501061931023">"Umsebenzi wobuso ukhanselwe."</string>
+ <string name="face_error_lockout" msgid="3407426963155388504">"Imizamo eminingi kakhulu. Zama futhi emuva kwesikhathi."</string>
+ <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Imizamo eminingi kakhulu. Ukufakazela ubuqiniso kobuso kukhutshaziwe."</string>
+ <string name="face_error_unable_to_process" msgid="238761109287767270">"Zama futhi."</string>
+ <string name="face_error_not_enrolled" msgid="9166792142679691323">"Abukho ubuso obubhalisiwe."</string>
+ <string name="face_error_hw_not_present" msgid="4737289254517095671">"Le divayisi ayinayo inzwa yokufakazela ubuqiniso yobuso"</string>
+ <string name="face_name_template" msgid="7004562145809595384">"Ubuso be-<xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string-array name="face_error_vendor">
+ </string-array>
+ <string name="face_icon_content_description" msgid="4024817159806482191">"Isithonjana sobuso"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"funda izilungiselelo zokuvumelanisa"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Ivumela uhlelo lokusebenza ukufunda izilungiselelo zokuvumelanisa ze-akhawunti. Isibonelo, lokhu kungacacisa ukuthi noma ngabe uhlelo lokusebenza le-People livumelanisiwe ne-akhawunti."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"shintsha phakathi kokuvula kanye nokucisha ukuvumelanisa"</string>
@@ -1178,6 +1211,9 @@
<skip />
<string name="wifi_no_internet" msgid="8938267198124654938">"I-Wi-Fi ayinakho ukufinyelela kwe-inthanethi"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Thepha ukuze uthole izinketho"</string>
+ <string name="wifi_softap_config_change" msgid="8475911871165857607">"Ushintsho kuzilungiselelo zakho ze-hotspot"</string>
+ <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Ibhendi yakho ye-hotspot ishintshile."</string>
+ <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Le divayisi ayisekeli okuncamelayo kwe-5GHz kuphela. Kunalokho, le divayisi izosebenzisa ibhendi ye-5GHz uma itholakala."</string>
<string name="network_switch_metered" msgid="4671730921726992671">"Kushintshelwe ku-<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="775163331794506615">"Idivayisi isebenzisa i-<xliff:g id="NEW_NETWORK">%1$s</xliff:g> uma i-<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> inganakho ukufinyelela kwe-inthanethi. Kungasebenza izindleko."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"Kushintshelewe kusuka ku-<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> kuya ku-<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index c4fa190..4c96c1b 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1580,6 +1580,7 @@
<attr name="banner" />
<attr name="logo" />
<attr name="permissionGroup" />
+ <attr name="backgroundPermission" />
<attr name="description" />
<attr name="request" />
<attr name="protectionLevel" />
@@ -1610,6 +1611,9 @@
<attr name="logo" />
<attr name="description" />
<attr name="request" />
+ <attr name="requestDetail" />
+ <attr name="backgroundRequest" />
+ <attr name="backgroundRequestDetail" />
<attr name="permissionGroupFlags" />
<attr name="priority" />
</declare-styleable>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7ffe866..381758f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -42,13 +42,13 @@
<item><xliff:g id="id">@string/status_bar_phone_evdo_signal</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_phone_signal</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_secure</xliff:g></item>
- <item><xliff:g id="id">@string/status_bar_bluetooth</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_managed_profile</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_cast</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_vpn</xliff:g></item>
+ <item><xliff:g id="id">@string/status_bar_bluetooth</xliff:g></item>
+ <item><xliff:g id="id">@string/status_bar_location</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_mute</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_volume</xliff:g></item>
- <item><xliff:g id="id">@string/status_bar_location</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_zen</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_ethernet</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_wifi</xliff:g></item>
@@ -491,13 +491,21 @@
Note also: the order of this is important. The first upstream type
for which a satisfying network exists is used.
- -->
+ -->
<integer-array translatable="false" name="config_tether_upstream_types">
<item>1</item>
<item>7</item>
<item>0</item>
</integer-array>
+ <!-- When true, the tethering upstream network follows the current default
+ Internet network (except when the current default network is mobile,
+ in which case a DUN network will be used if required).
+
+ When true, overrides the config_tether_upstream_types setting above.
+ -->
+ <bool translatable="false" name="config_tether_upstream_automatic">true</bool>
+
<!-- If the DUN connection for this CDMA device supports more than just DUN -->
<!-- traffic you should list them here. -->
<!-- If this device is not CDMA this is ignored. If this list is empty on -->
@@ -2604,8 +2612,8 @@
<item>lockdown</item>
<item>logout</item>
<item>bugreport</item>
- <item>emergency</item>
<item>screenshot</item>
+ <item>emergency</item>
</string-array>
<!-- Number of milliseconds to hold a wake lock to ensure that drawing is fully
@@ -2905,6 +2913,9 @@
<!-- Keyguard component -->
<string name="config_keyguardComponent" translatable="false">com.android.systemui/com.android.systemui.keyguard.KeyguardService</string>
+ <!-- Limit for the number of face templates per user -->
+ <integer name="config_face_MaxTemplatesPerUser">1</integer>
+
<!-- For performance and storage reasons, limit the number of fingerprints per user -->
<integer name="config_fingerprintMaxTemplatesPerUser">5</integer>
@@ -3471,4 +3482,6 @@
<!-- Whether or not swipe up gesture's opt-in setting is available on this device -->
<bool name="config_swipe_up_gesture_setting_available">false</bool>
+ <!-- Whether or not we should show the option to show battery percentage -->
+ <bool name="config_battery_percentage_setting_available">true</bool>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 9dccc88..8847ec8 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -539,15 +539,6 @@
<!-- status message in phone options dialog for when airplane mode is off -->
<string name="global_actions_airplane_mode_off_status">Airplane mode is OFF</string>
- <!-- label for item that enables battery saver in phone options dialog -->
- <string name="global_action_toggle_battery_saver">Battery saver</string>
-
- <!-- status message in phone options dialog for when battery saver is enabled -->
- <string name="global_action_battery_saver_on_status">Battery saver is OFF</string>
-
- <!-- status message in phone options dialog for when battery saver is disabled -->
- <string name="global_action_battery_saver_off_status">Battery saver is ON</string>
-
<!-- label for item that launches settings in phone options dialog [CHAR LIMIT=15]-->
<string name="global_action_settings">Settings</string>
@@ -671,7 +662,7 @@
<string name="permgrouplab_contacts">Contacts</string>
<!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgroupdesc_contacts">access your contacts</string>
- <!-- Message shown to the user when the apps requests permission from this group -->
+ <!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgrouprequest_contacts">Allow
<b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g></b> to access your contacts?</string>
@@ -679,15 +670,22 @@
<string name="permgrouplab_location">Location</string>
<!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgroupdesc_location">access this device\'s location</string>
- <!-- Message shown to the user when the apps requests permission from this group -->
+ <!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgrouprequest_location">Allow
<b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g></b> to access this device\'s location?</string>
+ <!-- Subtitle of the message shown to the user when the apps requests permission to use the location only while app is in foreground [CHAR LIMIT=150]-->
+ <string name="permgrouprequestdetail_location">The app will only have access to the location while you\u2019re using the app.</string>
+ <!-- Message shown to the user when the apps requests permission to use the location while app is in foreground and background. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
+ <string name="permgroupbackgroundrequest_location">Always allow
+ <b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g></b> to access this device\u2019s location?</string>
+ <!-- Subtitle of the message shown to the user when the apps requests permission to use the location while app is in foreground and background [CHAR LIMIT=150] -->
+ <string name="permgroupbackgroundrequestdetail_location">The app will always have access to the location, even when you\u2019re not using the app.</string>
<!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgrouplab_calendar">Calendar</string>
<!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgroupdesc_calendar">access your calendar</string>
- <!-- Message shown to the user when the apps requests permission from this group -->
+ <!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgrouprequest_calendar">Allow
<b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g></b> to access your calendar?</string>
@@ -695,7 +693,7 @@
<string name="permgrouplab_sms">SMS</string>
<!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgroupdesc_sms">send and view SMS messages</string>
- <!-- Message shown to the user when the apps requests permission from this group -->
+ <!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgrouprequest_sms">Allow
<b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g></b> to send and view SMS messages?</string>
@@ -703,7 +701,7 @@
<string name="permgrouplab_storage">Storage</string>
<!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgroupdesc_storage">access photos, media, and files on your device</string>
- <!-- Message shown to the user when the apps requests permission from this group -->
+ <!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgrouprequest_storage">Allow
<b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g></b> to access photos, media, and files on your device?</string>
@@ -711,7 +709,7 @@
<string name="permgrouplab_microphone">Microphone</string>
<!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgroupdesc_microphone">record audio</string>
- <!-- Message shown to the user when the apps requests permission from this group -->
+ <!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgrouprequest_microphone">Allow
<b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g></b> to record audio?</string>
@@ -719,7 +717,7 @@
<string name="permgrouplab_camera">Camera</string>
<!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgroupdesc_camera">take pictures and record video</string>
- <!-- Message shown to the user when the apps requests permission from this group -->
+ <!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgrouprequest_camera">Allow
<b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g></b> to take pictures and record video?</string>
@@ -727,7 +725,7 @@
<string name="permgrouplab_calllog">Call logs</string>
<!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgroupdesc_calllog">read and write phone call log</string>
- <!-- Message shown to the user when the apps requests permission from this group -->
+ <!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgrouprequest_calllog">Allow
<b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g></b> to access your phone call logs?</string>
@@ -735,7 +733,7 @@
<string name="permgrouplab_phone">Phone</string>
<!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgroupdesc_phone">make and manage phone calls</string>
- <!-- Message shown to the user when the apps requests permission from this group -->
+ <!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgrouprequest_phone">Allow
<b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g></b> to make and manage phone calls?</string>
@@ -743,7 +741,7 @@
<string name="permgrouplab_sensors">Body Sensors</string>
<!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgroupdesc_sensors">access sensor data about your vital signs</string>
- <!-- Message shown to the user when the apps requests permission from this group -->
+ <!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgrouprequest_sensors">Allow
<b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g></b> to access sensor data about your vital signs?</string>
@@ -1401,6 +1399,72 @@
<!-- Content description which should be used for the fingerprint icon. -->
<string name="fingerprint_icon_content_description">Fingerprint icon</string>
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=50] -->
+ <string name="permlab_manageFace">manage face authentication hardware</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=90] -->
+ <string name="permdesc_manageFace">Allows the app to invoke methods to add and delete facial templates for use.</string>
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=50] -->
+ <string name="permlab_useFaceAuthentication">use face authentication hardware</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=90] -->
+ <string name="permdesc_useFaceAuthentication">Allows the app to use face authentication hardware for authentication</string>
+
+ <!-- Message shown during face acquisition when the face cannot be recognized [CHAR LIMIT=50] -->
+ <string name="face_acquired_insufficient">Couldn\u2019t process face. Please try again.</string>
+ <!-- Message shown during face acquisition when the image is too bright [CHAR LIMIT=50] -->
+ <string name="face_acquired_too_bright">Face is too bright. Please try in lower light.</string>
+ <!-- Message shown during face acquisition when the image is too dark [CHAR LIMIT=50] -->
+ <string name="face_acquired_too_dark">Face is too dark. Please uncover light source.</string>
+ <!-- Message shown during face acquisition when the user is too close to sensor [CHAR LIMIT=50] -->
+ <string name="face_acquired_too_close">Please move sensor farther from face.</string>
+ <!-- Message shown during face acquisition when the user is too far from sensor [CHAR LIMIT=50] -->
+ <string name="face_acquired_too_far">Please bring sensor closer to face.</string>
+ <!-- Message shown during face acquisition when the user is too high relatively to sensor [CHAR LIMIT=50] -->
+ <string name="face_acquired_too_high">Please move sensor higher.</string>
+ <!-- Message shown during face acquisition when the user is too low relatively to sensor [CHAR LIMIT=50] -->
+ <string name="face_acquired_too_low">Please move sensor lower.</string>
+ <!-- Message shown during face acquisition when the user is too right relatively to sensor [CHAR LIMIT=50] -->
+ <string name="face_acquired_too_right">Please move sensor to the right.</string>
+ <!-- Message shown during face acquisition when the user is too left relatively to sensor [CHAR LIMIT=50] -->
+ <string name="face_acquired_too_left">Please move sensor to the left.</string>
+ <!-- Message shown during face acquisition when the user is not front facing the sensor [CHAR LIMIT=50] -->
+ <string name="face_acquired_poor_gaze">Please look at the sensor.</string>
+ <!-- Message shown during face acquisition when the user is not detected [CHAR LIMIT=50] -->
+ <string name="face_acquired_not_detected">No face detected.</string>
+ <!-- Message shown during face acquisition when the face is not kept steady infront of device [CHAR LIMIT=50] -->
+ <string name="face_acquired_not_steady">Keep face steady infront of device.</string>
+ <!-- Array containing custom messages shown during face acquisition from vendor. Vendor is expected to add and translate these strings -->
+ <string-array name="face_acquired_vendor">
+ </string-array>
+
+ <!-- Error message shown when the face hardware can't be accessed. [CHAR LIMIT=50] -->
+ <string name="face_error_hw_not_available">Face hardware not available.</string>
+ <!-- Error message shown when the face hardware timer has expired and the user needs to restart the operation. [CHAR LIMIT=50] -->
+ <string name="face_error_timeout">Face time out reached. Try again.</string>
+ <!-- Error message shown when the face hardware has run out of room for storing faces. [CHAR LIMIT=50] -->
+ <string name="face_error_no_space">Face can\u2019t be stored.</string>
+ <!-- Generic error message shown when the face operation (e.g. enrollment or authentication) is canceled. Generally not shown to the user. [CHAR LIMIT=50] -->
+ <string name="face_error_canceled">Face operation canceled.</string>
+ <!-- Generic error message shown when the face operation fails because too many attempts have been made. [CHAR LIMIT=50] -->
+ <string name="face_error_lockout">Too many attempts. Try again later.</string>
+ <!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=50] -->
+ <string name="face_error_lockout_permanent">Too many attempts. Facial authentication disabled.</string>
+ <!-- Generic error message shown when the face hardware can't recognize the face. [CHAR LIMIT=50] -->
+ <string name="face_error_unable_to_process">Try again.</string>
+ <!-- Generic error message shown when the user has no enrolled face. [CHAR LIMIT=50] -->
+ <string name="face_error_not_enrolled">No face enrolled.</string>
+ <!-- Generic error message shown when the app requests face authentication on a device without a sensor. [CHAR LIMIT=60] -->
+ <string name="face_error_hw_not_present">This device does not have a face authentication sensor</string>
+
+ <!-- Template to be used to name enrolled faces by default. [CHAR LIMIT=10] -->
+ <string name="face_name_template">Face <xliff:g id="faceId" example="1">%d</xliff:g></string>
+
+ <!-- Array containing custom error messages from vendor. Vendor is expected to add and translate these strings -->
+ <string-array name="face_error_vendor">
+ </string-array>
+
+ <!-- Content description which should be used for the face icon. [CHAR LIMIT=10] -->
+ <string name="face_icon_content_description">Face icon</string>
+
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_readSyncSettings">read sync settings</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -3173,6 +3237,21 @@
<!-- A notification is shown when the user connects to a Wi-Fi network and the system detects that that network has no Internet access. This is the notification's message. -->
<string name="wifi_no_internet_detailed">Tap for options</string>
+ <!-- A notification is shown when the user's softap config has been changed due to underlying
+ hardware restrictions. This is the notifications's title.
+ [CHAR_LIMIT=NONE] -->
+ <string name="wifi_softap_config_change">Changes to your hotspot settings</string>
+
+ <!-- A notification is shown when the user's softap config has been changed due to underlying
+ hardware restrictions. This is the notification's summary message.
+ [CHAR_LIMIT=NONE] -->
+ <string name="wifi_softap_config_change_summary">Your hotspot band has changed.</string>
+
+ <!-- A notification is shown when the user's softap config has been changed due to underlying
+ hardware restrictions. This is the notification's full message.
+ [CHAR_LIMIT=NONE] -->
+ <string name="wifi_softap_config_change_detailed">This device doesn\u2019t support your preference for 5GHz only. Instead, this device will use the 5GHz band when available.</string>
+
<!-- A notification might be shown if the device switches to another network type (e.g., mobile data) because it detects that the network it was using (e.g., Wi-Fi) has lost Internet connectivity. This is the notification's title. %1$s is the network type that the device switched to, e.g., cellular data. It is one of the strings in the network_switch_type_name array. -->
<string name="network_switch_metered">Switched to <xliff:g id="network_type">%1$s</xliff:g></string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 17fb575..99d0dba 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1061,6 +1061,9 @@
<java-symbol type="string" name="network_switch_type_name_unknown" />
<java-symbol type="string" name="wifi_no_internet" />
<java-symbol type="string" name="wifi_no_internet_detailed" />
+ <java-symbol type="string" name="wifi_softap_config_change" />
+ <java-symbol type="string" name="wifi_softap_config_change_summary" />
+ <java-symbol type="string" name="wifi_softap_config_change_detailed" />
<java-symbol type="string" name="wifi_connect_alert_title" />
<java-symbol type="string" name="wifi_connect_alert_message" />
<java-symbol type="string" name="wifi_connect_default_application" />
@@ -1773,9 +1776,6 @@
<java-symbol type="string" name="global_action_silent_mode_off_status" />
<java-symbol type="string" name="global_action_silent_mode_on_status" />
<java-symbol type="string" name="global_action_toggle_silent_mode" />
- <java-symbol type="string" name="global_action_battery_saver_off_status" />
- <java-symbol type="string" name="global_action_battery_saver_on_status" />
- <java-symbol type="string" name="global_action_toggle_battery_saver" />
<java-symbol type="string" name="global_action_lockdown" />
<java-symbol type="string" name="global_action_voice_assist" />
<java-symbol type="string" name="global_action_assist" />
@@ -1828,6 +1828,7 @@
<java-symbol type="array" name="config_tether_bluetooth_regexs" />
<java-symbol type="array" name="config_tether_dhcp_range" />
<java-symbol type="array" name="config_tether_upstream_types" />
+ <java-symbol type="bool" name="config_tether_upstream_automatic" />
<java-symbol type="array" name="config_tether_apndata" />
<java-symbol type="array" name="config_tether_usb_regexs" />
<java-symbol type="array" name="config_tether_wifi_regexs" />
@@ -2199,6 +2200,7 @@
<java-symbol type="string" name="ext_media_move_failure_message" />
<java-symbol type="style" name="Animation.RecentApplications" />
<java-symbol type="integer" name="dock_enter_exit_duration" />
+ <java-symbol type="bool" name="config_battery_percentage_setting_available" />
<!-- ImfTest -->
<java-symbol type="layout" name="auto_complete_list" />
@@ -2418,6 +2420,34 @@
<java-symbol type="integer" name="config_fingerprintMaxTemplatesPerUser"/>
<java-symbol type="bool" name="config_fingerprintSupportsGestures"/>
+ <!-- Face authentication messages -->
+ <java-symbol type="string" name="face_error_unable_to_process" />
+ <java-symbol type="string" name="face_error_hw_not_available" />
+ <java-symbol type="string" name="face_error_no_space" />
+ <java-symbol type="string" name="face_error_timeout" />
+ <java-symbol type="array" name="face_error_vendor" />
+ <java-symbol type="string" name="face_error_canceled" />
+ <java-symbol type="string" name="face_error_lockout" />
+ <java-symbol type="string" name="face_error_lockout_permanent" />
+ <java-symbol type="string" name="face_error_not_enrolled" />
+ <java-symbol type="string" name="face_error_hw_not_present" />
+ <java-symbol type="string" name="face_acquired_insufficient" />
+ <java-symbol type="string" name="face_acquired_too_bright" />
+ <java-symbol type="string" name="face_acquired_too_dark" />
+ <java-symbol type="string" name="face_acquired_too_close" />
+ <java-symbol type="string" name="face_acquired_too_far" />
+ <java-symbol type="string" name="face_acquired_too_high" />
+ <java-symbol type="string" name="face_acquired_too_low" />
+ <java-symbol type="string" name="face_acquired_too_right" />
+ <java-symbol type="string" name="face_acquired_too_left" />
+ <java-symbol type="string" name="face_acquired_poor_gaze" />
+ <java-symbol type="string" name="face_acquired_not_detected" />
+ <java-symbol type="array" name="face_acquired_vendor" />
+ <java-symbol type="string" name="face_name_template" />
+
+ <!-- Face config -->
+ <java-symbol type="integer" name="config_face_MaxTemplatesPerUser" />
+
<!-- From various Material changes -->
<java-symbol type="attr" name="titleTextAppearance" />
<java-symbol type="attr" name="subtitleTextAppearance" />
diff --git a/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java b/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java
new file mode 100644
index 0000000..c8bc35c
--- /dev/null
+++ b/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.system.Os;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.util.Arrays;
+
+@RunWith(AndroidJUnit4.class)
+public class RedactingFileDescriptorTest {
+ private Context mContext;
+ private File mFile;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getContext();
+ mFile = File.createTempFile("redacting", "dat");
+ try (FileOutputStream out = new FileOutputStream(mFile)) {
+ final byte[] buf = new byte[1_000_000];
+ Arrays.fill(buf, (byte) 64);
+ out.write(buf);
+ }
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mFile.delete();
+ }
+
+ @Test
+ public void testSingleByte() throws Exception {
+ final FileDescriptor fd = RedactingFileDescriptor
+ .open(mContext, mFile, new long[] { 10, 11 }).getFileDescriptor();
+
+ final byte[] buf = new byte[1_000];
+ assertEquals(buf.length, Os.read(fd, buf, 0, buf.length));
+ for (int i = 0; i < buf.length; i++) {
+ if (i == 10) {
+ assertEquals(0, buf[i]);
+ } else {
+ assertEquals(64, buf[i]);
+ }
+ }
+ }
+
+ @Test
+ public void testRanges() throws Exception {
+ final FileDescriptor fd = RedactingFileDescriptor
+ .open(mContext, mFile, new long[] { 100, 200, 300, 400 }).getFileDescriptor();
+
+ final byte[] buf = new byte[10];
+ assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 90));
+ assertArrayEquals(new byte[] { 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 }, buf);
+
+ assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 95));
+ assertArrayEquals(new byte[] { 64, 64, 64, 64, 64, 0, 0, 0, 0, 0 }, buf);
+
+ assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 100));
+ assertArrayEquals(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, buf);
+
+ assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 195));
+ assertArrayEquals(new byte[] { 0, 0, 0, 0, 0, 64, 64, 64, 64, 64 }, buf);
+
+ assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 395));
+ assertArrayEquals(new byte[] { 0, 0, 0, 0, 0, 64, 64, 64, 64, 64 }, buf);
+ }
+
+ @Test
+ public void testEntireFile() throws Exception {
+ final FileDescriptor fd = RedactingFileDescriptor
+ .open(mContext, mFile, new long[] { 0, 5_000_000 }).getFileDescriptor();
+
+ try (FileInputStream in = new FileInputStream(fd)) {
+ int val;
+ while ((val = in.read()) != -1) {
+ assertEquals(0, val);
+ }
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 8c16d83..7d48987 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -272,6 +272,7 @@
Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
Settings.Global.LOCATION_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS,
Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST,
+ Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS,
Settings.Global.LOCATION_GLOBAL_KILL_SWITCH,
Settings.Global.LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED,
Settings.Global.LOCK_SOUND,
@@ -459,6 +460,8 @@
Settings.Global.WIFI_BOUNCE_DELAY_OVERRIDE_MS,
Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED,
Settings.Global.WIFI_COUNTRY_CODE,
+ Settings.Global.WIFI_DATA_STALL_MIN_TX_BAD,
+ Settings.Global.WIFI_DATA_STALL_MIN_TX_SUCCESS_WITHOUT_RX,
Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN,
Settings.Global.WIFI_DISPLAY_CERTIFICATION_ON,
Settings.Global.WIFI_DISPLAY_ON,
@@ -468,6 +471,8 @@
Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS,
Settings.Global.WIFI_FREQUENCY_BAND,
Settings.Global.WIFI_IDLE_MS,
+ Settings.Global.WIFI_IS_UNUSABLE_EVENT_METRICS_ENABLED,
+ Settings.Global.WIFI_LINK_SPEED_METRICS_ENABLED,
Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT,
Settings.Global.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS,
Settings.Global.WIFI_NETWORK_SHOW_RSSI,
diff --git a/core/tests/coretests/src/android/util/TimestampedValueTest.java b/core/tests/coretests/src/android/util/TimestampedValueTest.java
index 7117c1b..03b4abd 100644
--- a/core/tests/coretests/src/android/util/TimestampedValueTest.java
+++ b/core/tests/coretests/src/android/util/TimestampedValueTest.java
@@ -116,4 +116,14 @@
parcel.recycle();
}
}
+
+ @Test
+ public void testReferenceTimeDifference() {
+ TimestampedValue<Long> value1 = new TimestampedValue<>(1000, 123L);
+ assertEquals(0, TimestampedValue.referenceTimeDifference(value1, value1));
+
+ TimestampedValue<Long> value2 = new TimestampedValue<>(1, 321L);
+ assertEquals(999, TimestampedValue.referenceTimeDifference(value1, value2));
+ assertEquals(-999, TimestampedValue.referenceTimeDifference(value2, value1));
+ }
}
diff --git a/core/tests/coretests/src/android/view/ViewGroupTransientViewTest.java b/core/tests/coretests/src/android/view/ViewGroupTransientViewTest.java
new file mode 100644
index 0000000..93ad41f0
--- /dev/null
+++ b/core/tests/coretests/src/android/view/ViewGroupTransientViewTest.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2018 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.view;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.fail;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.widget.FrameLayout;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ViewGroupTransientViewTest {
+
+ @Rule
+ public ActivityTestRule<Activity> mActivityRule = new ActivityTestRule<>(Activity.class);
+
+ private FrameLayout mBasePanel;
+ private ViewGroup mTestViewGroup;
+ private TestView mTestView;
+
+ @Before
+ public void setUp() {
+ final Activity activity = mActivityRule.getActivity();
+ mBasePanel = new FrameLayout(activity);
+ mTestViewGroup = new FrameLayout(activity);
+ mTestView = new TestView(activity);
+ activity.runOnUiThread(() -> activity.setContentView(mBasePanel));
+ }
+
+ @UiThreadTest
+ @Test
+ public void addAndRemove_inNonAttachedViewGroup_shouldNotAttachAndDetach() {
+ mTestViewGroup.addTransientView(mTestView, 0);
+ assertEquals(0, mTestView.mAttachedCount);
+
+ mTestViewGroup.removeTransientView(mTestView);
+ assertEquals(0, mTestView.mDetachedCount);
+ }
+
+ @UiThreadTest
+ @Test
+ public void addAndRemove_inAttachedViewGroup_shouldAttachAndDetachOnce() {
+ mBasePanel.addView(mTestViewGroup);
+ mTestViewGroup.addTransientView(mTestView, 0);
+ assertEquals(mTestView, mTestViewGroup.getTransientView(0));
+ assertEquals(1, mTestViewGroup.getTransientViewCount());
+ assertEquals(1, mTestView.mAttachedCount);
+
+ mBasePanel.removeView(mTestViewGroup);
+ mTestViewGroup.removeTransientView(mTestView);
+ assertEquals(null, mTestViewGroup.getTransientView(0));
+ assertEquals(0, mTestViewGroup.getTransientViewCount());
+ assertEquals(1, mTestView.mDetachedCount);
+ }
+
+ @UiThreadTest
+ @Test
+ public void addRemoveAdd_noException() {
+ mBasePanel.addView(mTestViewGroup);
+ mTestViewGroup.addTransientView(mTestView, 1);
+ mTestViewGroup.removeTransientView(mTestView);
+ mTestViewGroup.addTransientView(mTestView, 2);
+ }
+
+ @UiThreadTest
+ @Test
+ public void reAddBeforeRemove_shouldThrowException() {
+ mTestViewGroup.addView(mTestView);
+
+ try {
+ mTestViewGroup.addTransientView(mTestView, 0);
+ fail("Not allow to add as transient view before removing it");
+ } catch (IllegalStateException e) {
+ // Expected
+ }
+
+ mTestViewGroup.removeView(mTestView);
+ mTestViewGroup.addTransientView(mTestView, 0);
+ try {
+ mTestViewGroup.addTransientView(mTestView, 1);
+ fail("Not allow to add the same transient view again");
+ } catch (IllegalStateException e) {
+ // Expected
+ }
+ }
+
+ @Test
+ public void drawTransientView() throws Exception {
+ // For view can be drawn if keyguard is active.
+ mActivityRule.getActivity().setShowWhenLocked(true);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ mTestView.mOnDraw = () -> latch.countDown();
+
+ mActivityRule.getActivity().runOnUiThread(() -> {
+ mBasePanel.addView(mTestViewGroup);
+ mTestViewGroup.addTransientView(mTestView, 0);
+ });
+
+ if (!latch.await(3, TimeUnit.SECONDS)) {
+ fail("Transient view does not draw");
+ }
+ }
+
+ private static class TestView extends View {
+ int mAttachedCount;
+ int mDetachedCount;
+ Runnable mOnDraw;
+
+ TestView(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mAttachedCount++;
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mDetachedCount++;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (mOnDraw != null) {
+ mOnDraw.run();
+ mOnDraw = null;
+ }
+ }
+ }
+}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index 2b5a37b..4c007cb 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -811,7 +811,7 @@
}
int errorCode = mKeyStore.importWrappedKey(
- Credentials.USER_SECRET_KEY + alias,
+ Credentials.USER_PRIVATE_KEY + alias,
entry.getWrappedKeyBytes(),
Credentials.USER_PRIVATE_KEY + entry.getWrappingKeyAlias(),
maskingKey,
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index 1b816fe..c195a8e 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -142,7 +142,7 @@
LOG_ALWAYS_FATAL_IF(!mProjectedDisplayList->mProjectedOutline);
const bool shouldClip = mProjectedDisplayList->mProjectedOutline->getPath();
SkAutoCanvasRestore acr2(canvas, shouldClip);
- canvas->setMatrix(mProjectedDisplayList->mProjectedReceiverParentMatrix);
+ canvas->setMatrix(mProjectedDisplayList->mParentMatrix);
if (shouldClip) {
clipOutline(*mProjectedDisplayList->mProjectedOutline, canvas, nullptr);
}
@@ -200,9 +200,7 @@
setViewProperties(properties, canvas, &alphaMultiplier);
}
SkiaDisplayList* displayList = (SkiaDisplayList*)mRenderNode->getDisplayList();
- if (displayList->containsProjectionReceiver()) {
- displayList->mProjectedReceiverParentMatrix = canvas->getTotalMatrix();
- }
+ displayList->mParentMatrix = canvas->getTotalMatrix();
// TODO should we let the bound of the drawable do this for us?
const SkRect bounds = SkRect::MakeWH(properties.getWidth(), properties.getHeight());
diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
index 6292a6c..dba97fe 100644
--- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
+++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
@@ -55,6 +55,11 @@
if (casterZ >= -NON_ZERO_EPSILON) { // draw only children with negative Z
return;
}
+ SkAutoCanvasRestore acr(canvas, true);
+ // Since we're drawing out of recording order, the child's matrix needs to be applied to the
+ // canvas. In in-order drawing, the canvas already has the child's matrix applied.
+ canvas->setMatrix(mDisplayList->mParentMatrix);
+ canvas->concat(childNode->getRecordedMatrix());
childNode->forceDraw(canvas);
drawIndex++;
}
@@ -102,6 +107,11 @@
RenderNodeDrawable* childNode = zChildren[drawIndex];
SkASSERT(childNode);
+ SkAutoCanvasRestore acr(canvas, true);
+ // Since we're drawing out of recording order, the child's matrix needs to be applied to the
+ // canvas. In in-order drawing, the canvas already has the child's matrix applied.
+ canvas->setMatrix(mStartBarrier->mDisplayList->mParentMatrix);
+ canvas->concat(childNode->getRecordedMatrix());
childNode->forceDraw(canvas);
drawIndex++;
@@ -153,10 +163,15 @@
}
SkAutoCanvasRestore acr(canvas, true);
+ // Since we're drawing out of recording order, the child's matrix needs to be applied to the
+ // canvas. In in-order drawing, the canvas already has the child's matrix applied.
+ canvas->setMatrix(mStartBarrier->mDisplayList->mParentMatrix);
SkMatrix shadowMatrix;
- mat4 hwuiMatrix;
+ mat4 hwuiMatrix(caster->getRecordedMatrix());
// TODO we don't pass the optional boolean to treat it as a 4x4 matrix
+ // applyViewPropertyTransforms gets the same matrix, which render nodes apply with
+ // RenderNodeDrawable::setViewProperties as a part if their draw.
caster->getRenderNode()->applyViewPropertyTransforms(hwuiMatrix);
hwuiMatrix.copyTo(shadowMatrix);
canvas->concat(shadowMatrix);
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h
index 58b9242..6eff589 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.h
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h
@@ -173,12 +173,12 @@
// node is drawn.
const Outline* mProjectedOutline = nullptr;
- // mProjectedReceiverParentMatrix is valid when render node tree is traversed during the draw
- // pass. Render nodes that have a child receiver node, will store their matrix in
- // mProjectedReceiverParentMatrix. Child receiver node will set the matrix and then clip with
- // the
- // outline of their parent.
- SkMatrix mProjectedReceiverParentMatrix;
+ // mParentMatrix is set and valid when render node tree is traversed during the draw
+ // pass. Render nodes, which draw in a order different than recording order (e.g. nodes with a
+ // child receiver node or Z elevation), can use mParentMatrix to calculate the final transform
+ // without replaying the matrix transform OPs from the display list.
+ // Child receiver node will set the matrix and then clip with the outline of their parent.
+ SkMatrix mParentMatrix;
};
}; // namespace skiapipeline
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
index 208910a..f2f5056 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
@@ -26,6 +26,7 @@
#include "DeviceInfo.h"
#include "Matrix.h"
#include "Properties.h"
+#include "utils/MathUtils.h"
using namespace android::uirenderer::renderthread;
@@ -115,9 +116,9 @@
paint.setBlendMode(SkBlendMode::kSrc);
// Apply a filter, which is matching OpenGL pipeline readback behaviour. Filter usage
// is codified by tests using golden images like DecodeAccuracyTest.
- if (skiaSrcRect.width() != bitmap->width() ||
- skiaSrcRect.height() != bitmap->height()) {
- // TODO: apply filter always, but check if tests will be fine
+ bool disableFilter = MathUtils::areEqual(skiaSrcRect.width(), skiaDestRect.width())
+ && MathUtils::areEqual(skiaSrcRect.height(), skiaDestRect.height());
+ if (!disableFilter) {
paint.setFilterQuality(kLow_SkFilterQuality);
}
scaledSurface->getCanvas()->concat(textureMatrix);
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 62f820a..10edf73 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -31,44 +31,242 @@
namespace uirenderer {
namespace renderthread {
-#define GET_PROC(F) m##F = (PFN_vk##F)vkGetInstanceProcAddr(instance, "vk" #F)
-#define GET_DEV_PROC(F) m##F = (PFN_vk##F)vkGetDeviceProcAddr(device, "vk" #F)
+#define GET_PROC(F) m##F = (PFN_vk##F)vkGetInstanceProcAddr(VK_NULL_HANDLE, "vk" #F)
+#define GET_INST_PROC(F) m##F = (PFN_vk##F)vkGetInstanceProcAddr(mInstance, "vk" #F)
+#define GET_DEV_PROC(F) m##F = (PFN_vk##F)vkGetDeviceProcAddr(mDevice, "vk" #F)
VulkanManager::VulkanManager(RenderThread& thread) : mRenderThread(thread) {}
void VulkanManager::destroy() {
- if (!hasVkContext()) return;
-
mRenderThread.renderState().onVkContextDestroyed();
mRenderThread.setGrContext(nullptr);
if (VK_NULL_HANDLE != mCommandPool) {
- mDestroyCommandPool(mBackendContext->fDevice, mCommandPool, nullptr);
+ mDestroyCommandPool(mDevice, mCommandPool, nullptr);
mCommandPool = VK_NULL_HANDLE;
}
- mBackendContext.reset();
-}
-void VulkanManager::initialize() {
- if (hasVkContext()) {
- return;
+ if (mDevice != VK_NULL_HANDLE) {
+ mDeviceWaitIdle(mDevice);
+ mDestroyDevice(mDevice, nullptr);
}
- auto canPresent = [](VkInstance, VkPhysicalDevice, uint32_t) { return true; };
+ if (mInstance != VK_NULL_HANDLE) {
+ mDestroyInstance(mInstance, nullptr);
+ }
- mBackendContext.reset(GrVkBackendContext::Create(vkGetInstanceProcAddr, vkGetDeviceProcAddr,
- &mPresentQueueIndex, canPresent));
- LOG_ALWAYS_FATAL_IF(!mBackendContext.get());
+ mGraphicsQueue = VK_NULL_HANDLE;
+ mPresentQueue = VK_NULL_HANDLE;
+ mDevice = VK_NULL_HANDLE;
+ mPhysicalDevice = VK_NULL_HANDLE;
+ mInstance = VK_NULL_HANDLE;
+}
- // Get all the addresses of needed vulkan functions
- VkInstance instance = mBackendContext->fInstance;
- VkDevice device = mBackendContext->fDevice;
- GET_PROC(CreateAndroidSurfaceKHR);
- GET_PROC(DestroySurfaceKHR);
- GET_PROC(GetPhysicalDeviceSurfaceSupportKHR);
- GET_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR);
- GET_PROC(GetPhysicalDeviceSurfaceFormatsKHR);
- GET_PROC(GetPhysicalDeviceSurfacePresentModesKHR);
+bool VulkanManager::setupDevice(VkPhysicalDeviceFeatures& deviceFeatures) {
+ VkResult err;
+
+ constexpr VkApplicationInfo app_info = {
+ VK_STRUCTURE_TYPE_APPLICATION_INFO, // sType
+ nullptr, // pNext
+ "android framework", // pApplicationName
+ 0, // applicationVersion
+ "android framework", // pEngineName
+ 0, // engineVerison
+ VK_MAKE_VERSION(1, 0, 0), // apiVersion
+ };
+
+ std::vector<const char*> instanceExtensions;
+ {
+ GET_PROC(EnumerateInstanceExtensionProperties);
+
+ uint32_t extensionCount = 0;
+ err = mEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
+ if (VK_SUCCESS != err) {
+ return false;
+ }
+ std::unique_ptr<VkExtensionProperties[]> extensions(
+ new VkExtensionProperties[extensionCount]);
+ err = mEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.get());
+ if (VK_SUCCESS != err) {
+ return false;
+ }
+ bool hasKHRSurfaceExtension = false;
+ bool hasKHRAndroidSurfaceExtension = false;
+ for (uint32_t i = 0; i < extensionCount; ++i) {
+ instanceExtensions.push_back(extensions[i].extensionName);
+ if (!strcmp(extensions[i].extensionName, VK_KHR_SURFACE_EXTENSION_NAME)) {
+ hasKHRSurfaceExtension = true;
+ }
+ if (!strcmp(extensions[i].extensionName,VK_KHR_ANDROID_SURFACE_EXTENSION_NAME)) {
+ hasKHRAndroidSurfaceExtension = true;
+ }
+ }
+ if (!hasKHRSurfaceExtension || !hasKHRAndroidSurfaceExtension) {
+ this->destroy();
+ return false;
+ }
+ }
+
+ const VkInstanceCreateInfo instance_create = {
+ VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, // sType
+ nullptr, // pNext
+ 0, // flags
+ &app_info, // pApplicationInfo
+ 0, // enabledLayerNameCount
+ nullptr, // ppEnabledLayerNames
+ (uint32_t) instanceExtensions.size(), // enabledExtensionNameCount
+ instanceExtensions.data(), // ppEnabledExtensionNames
+ };
+
+ GET_PROC(CreateInstance);
+ err = mCreateInstance(&instance_create, nullptr, &mInstance);
+ if (err < 0) {
+ this->destroy();
+ return false;
+ }
+
+ GET_INST_PROC(DestroyInstance);
+ GET_INST_PROC(EnumeratePhysicalDevices);
+ GET_INST_PROC(GetPhysicalDeviceQueueFamilyProperties);
+ GET_INST_PROC(GetPhysicalDeviceFeatures);
+ GET_INST_PROC(CreateDevice);
+ GET_INST_PROC(EnumerateDeviceExtensionProperties);
+ GET_INST_PROC(CreateAndroidSurfaceKHR);
+ GET_INST_PROC(DestroySurfaceKHR);
+ GET_INST_PROC(GetPhysicalDeviceSurfaceSupportKHR);
+ GET_INST_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR);
+ GET_INST_PROC(GetPhysicalDeviceSurfaceFormatsKHR);
+ GET_INST_PROC(GetPhysicalDeviceSurfacePresentModesKHR);
+
+ uint32_t gpuCount;
+ err = mEnumeratePhysicalDevices(mInstance, &gpuCount, nullptr);
+ if (err) {
+ this->destroy();
+ return false;
+ }
+ if (!gpuCount) {
+ this->destroy();
+ return false;
+ }
+ // Just returning the first physical device instead of getting the whole array. Since there
+ // should only be one device on android.
+ gpuCount = 1;
+ err = mEnumeratePhysicalDevices(mInstance, &gpuCount, &mPhysicalDevice);
+ // VK_INCOMPLETE is returned when the count we provide is less than the total device count.
+ if (err && VK_INCOMPLETE != err) {
+ this->destroy();
+ return false;
+ }
+
+ // query to get the initial queue props size
+ uint32_t queueCount;
+ mGetPhysicalDeviceQueueFamilyProperties(mPhysicalDevice, &queueCount, nullptr);
+ if (!queueCount) {
+ this->destroy();
+ return false;
+ }
+
+ // now get the actual queue props
+ std::unique_ptr<VkQueueFamilyProperties[]> queueProps(new VkQueueFamilyProperties[queueCount]);
+ mGetPhysicalDeviceQueueFamilyProperties(mPhysicalDevice, &queueCount, queueProps.get());
+
+ // iterate to find the graphics queue
+ mGraphicsQueueIndex = queueCount;
+ for (uint32_t i = 0; i < queueCount; i++) {
+ if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
+ mGraphicsQueueIndex = i;
+ break;
+ }
+ }
+ if (mGraphicsQueueIndex == queueCount) {
+ this->destroy();
+ return false;
+ }
+
+ // All physical devices and queue families on Android must be capable of
+ // presentation with any native window. So just use the first one.
+ mPresentQueueIndex = 0;
+
+ std::vector<const char*> deviceExtensions;
+ {
+ uint32_t extensionCount = 0;
+ err = mEnumerateDeviceExtensionProperties(mPhysicalDevice, nullptr, &extensionCount,
+ nullptr);
+ if (VK_SUCCESS != err) {
+ this->destroy();
+ return false;
+ }
+ std::unique_ptr<VkExtensionProperties[]> extensions(
+ new VkExtensionProperties[extensionCount]);
+ err = mEnumerateDeviceExtensionProperties(mPhysicalDevice, nullptr, &extensionCount,
+ extensions.get());
+ if (VK_SUCCESS != err) {
+ this->destroy();
+ return false;
+ }
+ bool hasKHRSwapchainExtension = false;
+ for (uint32_t i = 0; i < extensionCount; ++i) {
+ deviceExtensions.push_back(extensions[i].extensionName);
+ if (!strcmp(extensions[i].extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
+ hasKHRSwapchainExtension = true;
+ }
+ }
+ if (!hasKHRSwapchainExtension) {
+ this->destroy();
+ return false;
+ }
+ }
+
+ // query to get the physical device properties
+ mGetPhysicalDeviceFeatures(mPhysicalDevice, &deviceFeatures);
+ // this looks like it would slow things down,
+ // and we can't depend on it on all platforms
+ deviceFeatures.robustBufferAccess = VK_FALSE;
+
+ float queuePriorities[1] = { 0.0 };
+
+ const VkDeviceQueueCreateInfo queueInfo[2] = {
+ {
+ VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
+ nullptr, // pNext
+ 0, // VkDeviceQueueCreateFlags
+ mGraphicsQueueIndex, // queueFamilyIndex
+ 1, // queueCount
+ queuePriorities, // pQueuePriorities
+ },
+ {
+ VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
+ nullptr, // pNext
+ 0, // VkDeviceQueueCreateFlags
+ mPresentQueueIndex, // queueFamilyIndex
+ 1, // queueCount
+ queuePriorities, // pQueuePriorities
+ }
+ };
+ uint32_t queueInfoCount = (mPresentQueueIndex != mGraphicsQueueIndex) ? 2 : 1;
+
+ const VkDeviceCreateInfo deviceInfo = {
+ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType
+ nullptr, // pNext
+ 0, // VkDeviceCreateFlags
+ queueInfoCount, // queueCreateInfoCount
+ queueInfo, // pQueueCreateInfos
+ 0, // layerCount
+ nullptr, // ppEnabledLayerNames
+ (uint32_t) deviceExtensions.size(), // extensionCount
+ deviceExtensions.data(), // ppEnabledExtensionNames
+ &deviceFeatures // ppEnabledFeatures
+ };
+
+ err = mCreateDevice(mPhysicalDevice, &deviceInfo, nullptr, &mDevice);
+ if (err) {
+ this->destroy();
+ return false;
+ }
+
+ GET_DEV_PROC(GetDeviceQueue);
+ GET_DEV_PROC(DeviceWaitIdle);
+ GET_DEV_PROC(DestroyDevice);
GET_DEV_PROC(CreateSwapchainKHR);
GET_DEV_PROC(DestroySwapchainKHR);
GET_DEV_PROC(GetSwapchainImagesKHR);
@@ -93,25 +291,76 @@
GET_DEV_PROC(WaitForFences);
GET_DEV_PROC(ResetFences);
+ return true;
+}
+
+void VulkanManager::initialize() {
+ if (mDevice != VK_NULL_HANDLE) {
+ return;
+ }
+
+ std::vector<const char*> instanceExtensions;
+ std::vector<const char*> deviceExtensions;
+ VkPhysicalDeviceFeatures deviceFeatures;
+ LOG_ALWAYS_FATAL_IF(!this->setupDevice(deviceFeatures));
+
+ mGetDeviceQueue(mDevice, mGraphicsQueueIndex, 0, &mGraphicsQueue);
+
+ uint32_t extensionFlags = kKHR_surface_GrVkExtensionFlag |
+ kKHR_android_surface_GrVkExtensionFlag |
+ kKHR_swapchain_GrVkExtensionFlag;
+
+ uint32_t featureFlags = 0;
+ if (deviceFeatures.geometryShader) {
+ featureFlags |= kGeometryShader_GrVkFeatureFlag;
+ }
+ if (deviceFeatures.dualSrcBlend) {
+ featureFlags |= kDualSrcBlend_GrVkFeatureFlag;
+ }
+ if (deviceFeatures.sampleRateShading) {
+ featureFlags |= kSampleRateShading_GrVkFeatureFlag;
+ }
+
+ auto getProc = [] (const char* proc_name, VkInstance instance, VkDevice device) {
+ if (device != VK_NULL_HANDLE) {
+ return vkGetDeviceProcAddr(device, proc_name);
+ }
+ return vkGetInstanceProcAddr(instance, proc_name);
+ };
+ auto interface =
+ sk_make_sp<GrVkInterface>(getProc, mInstance, mDevice, extensionFlags);
+
+ GrVkBackendContext backendContext;
+ backendContext.fInstance = mInstance;
+ backendContext.fPhysicalDevice = mPhysicalDevice;
+ backendContext.fDevice = mDevice;
+ backendContext.fQueue = mGraphicsQueue;
+ backendContext.fGraphicsQueueIndex = mGraphicsQueueIndex;
+ backendContext.fMinAPIVersion = VK_MAKE_VERSION(1, 0, 0);
+ backendContext.fExtensions = extensionFlags;
+ backendContext.fFeatures = featureFlags;
+ backendContext.fInterface = std::move(interface);
+ backendContext.fOwnsInstanceAndDevice = false;
+
// create the command pool for the command buffers
if (VK_NULL_HANDLE == mCommandPool) {
VkCommandPoolCreateInfo commandPoolInfo;
memset(&commandPoolInfo, 0, sizeof(VkCommandPoolCreateInfo));
commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
// this needs to be on the render queue
- commandPoolInfo.queueFamilyIndex = mBackendContext->fGraphicsQueueIndex;
+ commandPoolInfo.queueFamilyIndex = mGraphicsQueueIndex;
commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
- SkDEBUGCODE(VkResult res =) mCreateCommandPool(mBackendContext->fDevice, &commandPoolInfo,
- nullptr, &mCommandPool);
+ SkDEBUGCODE(VkResult res =) mCreateCommandPool(mDevice, &commandPoolInfo, nullptr,
+ &mCommandPool);
SkASSERT(VK_SUCCESS == res);
}
- mGetDeviceQueue(mBackendContext->fDevice, mPresentQueueIndex, 0, &mPresentQueue);
+ mGetDeviceQueue(mDevice, mPresentQueueIndex, 0, &mPresentQueue);
GrContextOptions options;
options.fDisableDistanceFieldPaths = true;
mRenderThread.cacheManager().configureContext(&options);
- sk_sp<GrContext> grContext(GrContext::MakeVulkan(mBackendContext, options));
+ sk_sp<GrContext> grContext(GrContext::MakeVulkan(backendContext, options));
LOG_ALWAYS_FATAL_IF(!grContext.get());
mRenderThread.setGrContext(grContext);
DeviceInfo::initialize(mRenderThread.getGrContext()->maxRenderTargetSize());
@@ -138,8 +387,7 @@
// Before we reuse a backbuffer, make sure its fences have all signaled so that we can safely
// reuse its commands buffers.
- VkResult res =
- mWaitForFences(mBackendContext->fDevice, 2, backbuffer->mUsageFences, true, UINT64_MAX);
+ VkResult res = mWaitForFences(mDevice, 2, backbuffer->mUsageFences, true, UINT64_MAX);
if (res != VK_SUCCESS) {
return nullptr;
}
@@ -153,12 +401,12 @@
VkResult res;
- res = mResetFences(mBackendContext->fDevice, 2, backbuffer->mUsageFences);
+ res = mResetFences(mDevice, 2, backbuffer->mUsageFences);
SkASSERT(VK_SUCCESS == res);
// The acquire will signal the attached mAcquireSemaphore. We use this to know the image has
// finished presenting and that it is safe to begin sending new commands to the returned image.
- res = mAcquireNextImageKHR(mBackendContext->fDevice, surface->mSwapchain, UINT64_MAX,
+ res = mAcquireNextImageKHR(mDevice, surface->mSwapchain, UINT64_MAX,
backbuffer->mAcquireSemaphore, VK_NULL_HANDLE,
&backbuffer->mImageIndex);
@@ -173,11 +421,11 @@
return nullptr;
}
backbuffer = getAvailableBackbuffer(surface);
- res = mResetFences(mBackendContext->fDevice, 2, backbuffer->mUsageFences);
+ res = mResetFences(mDevice, 2, backbuffer->mUsageFences);
SkASSERT(VK_SUCCESS == res);
// acquire the image
- res = mAcquireNextImageKHR(mBackendContext->fDevice, surface->mSwapchain, UINT64_MAX,
+ res = mAcquireNextImageKHR(mDevice, surface->mSwapchain, UINT64_MAX,
backbuffer->mAcquireSemaphore, VK_NULL_HANDLE,
&backbuffer->mImageIndex);
@@ -205,7 +453,7 @@
layout, // oldLayout
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout
mPresentQueueIndex, // srcQueueFamilyIndex
- mBackendContext->fGraphicsQueueIndex, // dstQueueFamilyIndex
+ mGraphicsQueueIndex, // dstQueueFamilyIndex
surface->mImages[backbuffer->mImageIndex], // image
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1} // subresourceRange
};
@@ -236,7 +484,7 @@
submitInfo.signalSemaphoreCount = 0;
// Attach first fence to submission here so we can track when the command buffer finishes.
- mQueueSubmit(mBackendContext->fQueue, 1, &submitInfo, backbuffer->mUsageFences[0]);
+ mQueueSubmit(mGraphicsQueue, 1, &submitInfo, backbuffer->mUsageFences[0]);
// We need to notify Skia that we changed the layout of the wrapped VkImage
sk_sp<SkSurface> skSurface = surface->mImageInfos[backbuffer->mImageIndex].mSurface;
@@ -255,17 +503,14 @@
void VulkanManager::destroyBuffers(VulkanSurface* surface) {
if (surface->mBackbuffers) {
for (uint32_t i = 0; i < surface->mImageCount + 1; ++i) {
- mWaitForFences(mBackendContext->fDevice, 2, surface->mBackbuffers[i].mUsageFences, true,
- UINT64_MAX);
+ mWaitForFences(mDevice, 2, surface->mBackbuffers[i].mUsageFences, true, UINT64_MAX);
surface->mBackbuffers[i].mImageIndex = -1;
- mDestroySemaphore(mBackendContext->fDevice, surface->mBackbuffers[i].mAcquireSemaphore,
- nullptr);
- mDestroySemaphore(mBackendContext->fDevice, surface->mBackbuffers[i].mRenderSemaphore,
- nullptr);
- mFreeCommandBuffers(mBackendContext->fDevice, mCommandPool, 2,
- surface->mBackbuffers[i].mTransitionCmdBuffers);
- mDestroyFence(mBackendContext->fDevice, surface->mBackbuffers[i].mUsageFences[0], 0);
- mDestroyFence(mBackendContext->fDevice, surface->mBackbuffers[i].mUsageFences[1], 0);
+ mDestroySemaphore(mDevice, surface->mBackbuffers[i].mAcquireSemaphore, nullptr);
+ mDestroySemaphore(mDevice, surface->mBackbuffers[i].mRenderSemaphore, nullptr);
+ mFreeCommandBuffers(mDevice, mCommandPool, 2,
+ surface->mBackbuffers[i].mTransitionCmdBuffers);
+ mDestroyFence(mDevice, surface->mBackbuffers[i].mUsageFences[0], 0);
+ mDestroyFence(mDevice, surface->mBackbuffers[i].mUsageFences[1], 0);
}
}
@@ -282,29 +527,27 @@
if (VK_NULL_HANDLE != mPresentQueue) {
mQueueWaitIdle(mPresentQueue);
}
- mDeviceWaitIdle(mBackendContext->fDevice);
+ mDeviceWaitIdle(mDevice);
destroyBuffers(surface);
if (VK_NULL_HANDLE != surface->mSwapchain) {
- mDestroySwapchainKHR(mBackendContext->fDevice, surface->mSwapchain, nullptr);
+ mDestroySwapchainKHR(mDevice, surface->mSwapchain, nullptr);
surface->mSwapchain = VK_NULL_HANDLE;
}
if (VK_NULL_HANDLE != surface->mVkSurface) {
- mDestroySurfaceKHR(mBackendContext->fInstance, surface->mVkSurface, nullptr);
+ mDestroySurfaceKHR(mInstance, surface->mVkSurface, nullptr);
surface->mVkSurface = VK_NULL_HANDLE;
}
delete surface;
}
void VulkanManager::createBuffers(VulkanSurface* surface, VkFormat format, VkExtent2D extent) {
- mGetSwapchainImagesKHR(mBackendContext->fDevice, surface->mSwapchain, &surface->mImageCount,
- nullptr);
+ mGetSwapchainImagesKHR(mDevice, surface->mSwapchain, &surface->mImageCount, nullptr);
SkASSERT(surface->mImageCount);
surface->mImages = new VkImage[surface->mImageCount];
- mGetSwapchainImagesKHR(mBackendContext->fDevice, surface->mSwapchain, &surface->mImageCount,
- surface->mImages);
+ mGetSwapchainImagesKHR(mDevice, surface->mSwapchain, &surface->mImageCount, surface->mImages);
SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
@@ -354,15 +597,15 @@
for (uint32_t i = 0; i < surface->mImageCount + 1; ++i) {
SkDEBUGCODE(VkResult res);
surface->mBackbuffers[i].mImageIndex = -1;
- SkDEBUGCODE(res =) mCreateSemaphore(mBackendContext->fDevice, &semaphoreInfo, nullptr,
+ SkDEBUGCODE(res =) mCreateSemaphore(mDevice, &semaphoreInfo, nullptr,
&surface->mBackbuffers[i].mAcquireSemaphore);
- SkDEBUGCODE(res =) mCreateSemaphore(mBackendContext->fDevice, &semaphoreInfo, nullptr,
+ SkDEBUGCODE(res =) mCreateSemaphore(mDevice, &semaphoreInfo, nullptr,
&surface->mBackbuffers[i].mRenderSemaphore);
- SkDEBUGCODE(res =) mAllocateCommandBuffers(mBackendContext->fDevice, &commandBuffersInfo,
+ SkDEBUGCODE(res =) mAllocateCommandBuffers(mDevice, &commandBuffersInfo,
surface->mBackbuffers[i].mTransitionCmdBuffers);
- SkDEBUGCODE(res =) mCreateFence(mBackendContext->fDevice, &fenceInfo, nullptr,
+ SkDEBUGCODE(res =) mCreateFence(mDevice, &fenceInfo, nullptr,
&surface->mBackbuffers[i].mUsageFences[0]);
- SkDEBUGCODE(res =) mCreateFence(mBackendContext->fDevice, &fenceInfo, nullptr,
+ SkDEBUGCODE(res =) mCreateFence(mDevice, &fenceInfo, nullptr,
&surface->mBackbuffers[i].mUsageFences[1]);
SkASSERT(VK_SUCCESS == res);
}
@@ -372,35 +615,35 @@
bool VulkanManager::createSwapchain(VulkanSurface* surface) {
// check for capabilities
VkSurfaceCapabilitiesKHR caps;
- VkResult res = mGetPhysicalDeviceSurfaceCapabilitiesKHR(mBackendContext->fPhysicalDevice,
+ VkResult res = mGetPhysicalDeviceSurfaceCapabilitiesKHR(mPhysicalDevice,
surface->mVkSurface, &caps);
if (VK_SUCCESS != res) {
return false;
}
uint32_t surfaceFormatCount;
- res = mGetPhysicalDeviceSurfaceFormatsKHR(mBackendContext->fPhysicalDevice, surface->mVkSurface,
+ res = mGetPhysicalDeviceSurfaceFormatsKHR(mPhysicalDevice, surface->mVkSurface,
&surfaceFormatCount, nullptr);
if (VK_SUCCESS != res) {
return false;
}
FatVector<VkSurfaceFormatKHR, 4> surfaceFormats(surfaceFormatCount);
- res = mGetPhysicalDeviceSurfaceFormatsKHR(mBackendContext->fPhysicalDevice, surface->mVkSurface,
+ res = mGetPhysicalDeviceSurfaceFormatsKHR(mPhysicalDevice, surface->mVkSurface,
&surfaceFormatCount, surfaceFormats.data());
if (VK_SUCCESS != res) {
return false;
}
uint32_t presentModeCount;
- res = mGetPhysicalDeviceSurfacePresentModesKHR(mBackendContext->fPhysicalDevice,
+ res = mGetPhysicalDeviceSurfacePresentModesKHR(mPhysicalDevice,
surface->mVkSurface, &presentModeCount, nullptr);
if (VK_SUCCESS != res) {
return false;
}
FatVector<VkPresentModeKHR, VK_PRESENT_MODE_RANGE_SIZE_KHR> presentModes(presentModeCount);
- res = mGetPhysicalDeviceSurfacePresentModesKHR(mBackendContext->fPhysicalDevice,
+ res = mGetPhysicalDeviceSurfacePresentModesKHR(mPhysicalDevice,
surface->mVkSurface, &presentModeCount,
presentModes.data());
if (VK_SUCCESS != res) {
@@ -482,8 +725,8 @@
swapchainCreateInfo.imageArrayLayers = 1;
swapchainCreateInfo.imageUsage = usageFlags;
- uint32_t queueFamilies[] = {mBackendContext->fGraphicsQueueIndex, mPresentQueueIndex};
- if (mBackendContext->fGraphicsQueueIndex != mPresentQueueIndex) {
+ uint32_t queueFamilies[] = {mGraphicsQueueIndex, mPresentQueueIndex};
+ if (mGraphicsQueueIndex != mPresentQueueIndex) {
swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
swapchainCreateInfo.queueFamilyIndexCount = 2;
swapchainCreateInfo.pQueueFamilyIndices = queueFamilies;
@@ -499,19 +742,18 @@
swapchainCreateInfo.clipped = true;
swapchainCreateInfo.oldSwapchain = surface->mSwapchain;
- res = mCreateSwapchainKHR(mBackendContext->fDevice, &swapchainCreateInfo, nullptr,
- &surface->mSwapchain);
+ res = mCreateSwapchainKHR(mDevice, &swapchainCreateInfo, nullptr, &surface->mSwapchain);
if (VK_SUCCESS != res) {
return false;
}
// destroy the old swapchain
if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) {
- mDeviceWaitIdle(mBackendContext->fDevice);
+ mDeviceWaitIdle(mDevice);
destroyBuffers(surface);
- mDestroySwapchainKHR(mBackendContext->fDevice, swapchainCreateInfo.oldSwapchain, nullptr);
+ mDestroySwapchainKHR(mDevice, swapchainCreateInfo.oldSwapchain, nullptr);
}
createBuffers(surface, surfaceFormat, extent);
@@ -535,20 +777,18 @@
surfaceCreateInfo.flags = 0;
surfaceCreateInfo.window = window;
- VkResult res = mCreateAndroidSurfaceKHR(mBackendContext->fInstance, &surfaceCreateInfo, nullptr,
- &surface->mVkSurface);
+ VkResult res = mCreateAndroidSurfaceKHR(mInstance, &surfaceCreateInfo, nullptr,
+ &surface->mVkSurface);
if (VK_SUCCESS != res) {
delete surface;
return nullptr;
}
SkDEBUGCODE(VkBool32 supported; res = mGetPhysicalDeviceSurfaceSupportKHR(
- mBackendContext->fPhysicalDevice, mPresentQueueIndex,
- surface->mVkSurface, &supported);
- // All physical devices and queue families on Android must be capable of
- // presentation with any
- // native window.
- SkASSERT(VK_SUCCESS == res && supported););
+ mPhysicalDevice, mPresentQueueIndex, surface->mVkSurface, &supported);
+ // All physical devices and queue families on Android must be capable of
+ // presentation with any native window.
+ SkASSERT(VK_SUCCESS == res && supported););
if (!createSwapchain(surface)) {
destroySurface(surface);
@@ -605,7 +845,7 @@
void VulkanManager::swapBuffers(VulkanSurface* surface) {
if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
ATRACE_NAME("Finishing GPU work");
- mDeviceWaitIdle(mBackendContext->fDevice);
+ mDeviceWaitIdle(mDevice);
}
SkASSERT(surface->mBackbuffers);
@@ -638,7 +878,7 @@
dstAccessMask, // inputMask
layout, // oldLayout
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // newLayout
- mBackendContext->fGraphicsQueueIndex, // srcQueueFamilyIndex
+ mGraphicsQueueIndex, // srcQueueFamilyIndex
mPresentQueueIndex, // dstQueueFamilyIndex
surface->mImages[backbuffer->mImageIndex], // image
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1} // subresourceRange
@@ -670,7 +910,7 @@
submitInfo.pSignalSemaphores = &backbuffer->mRenderSemaphore;
// Attach second fence to submission here so we can track when the command buffer finishes.
- mQueueSubmit(mBackendContext->fQueue, 1, &submitInfo, backbuffer->mUsageFences[1]);
+ mQueueSubmit(mGraphicsQueue, 1, &submitInfo, backbuffer->mUsageFences[1]);
// Submit present operation to present queue. We use a semaphore here to make sure all rendering
// to the image is complete and that the layout has been change to present on the graphics
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index c319c9e..9a72706 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -79,7 +79,7 @@
void initialize();
// Quick check to see if the VulkanManager has been initialized.
- bool hasVkContext() { return mBackendContext.get() != nullptr; }
+ bool hasVkContext() { return mDevice != VK_NULL_HANDLE; }
// Given a window this creates a new VkSurfaceKHR and VkSwapchain and stores them inside a new
// VulkanSurface object which is returned.
@@ -111,6 +111,10 @@
explicit VulkanManager(RenderThread& thread);
~VulkanManager() { destroy(); }
+ // Sets up the VkInstance and VkDevice objects. Also fills out the passed in
+ // VkPhysicalDeviceFeatures struct.
+ bool setupDevice(VkPhysicalDeviceFeatures& deviceFeatures);
+
void destroyBuffers(VulkanSurface* surface);
bool createSwapchain(VulkanSurface* surface);
@@ -148,7 +152,21 @@
VkPtr<PFN_vkQueuePresentKHR> mQueuePresentKHR;
VkPtr<PFN_vkCreateSharedSwapchainsKHR> mCreateSharedSwapchainsKHR;
- // Additional vulkan functions
+ // Instance Functions
+ VkPtr<PFN_vkEnumerateInstanceExtensionProperties> mEnumerateInstanceExtensionProperties;
+ VkPtr<PFN_vkCreateInstance> mCreateInstance;
+
+ VkPtr<PFN_vkDestroyInstance> mDestroyInstance;
+ VkPtr<PFN_vkEnumeratePhysicalDevices> mEnumeratePhysicalDevices;
+ VkPtr<PFN_vkGetPhysicalDeviceQueueFamilyProperties> mGetPhysicalDeviceQueueFamilyProperties;
+ VkPtr<PFN_vkGetPhysicalDeviceFeatures> mGetPhysicalDeviceFeatures;
+ VkPtr<PFN_vkCreateDevice> mCreateDevice;
+ VkPtr<PFN_vkEnumerateDeviceExtensionProperties> mEnumerateDeviceExtensionProperties;
+
+ // Device Functions
+ VkPtr<PFN_vkGetDeviceQueue> mGetDeviceQueue;
+ VkPtr<PFN_vkDeviceWaitIdle> mDeviceWaitIdle;
+ VkPtr<PFN_vkDestroyDevice> mDestroyDevice;
VkPtr<PFN_vkCreateCommandPool> mCreateCommandPool;
VkPtr<PFN_vkDestroyCommandPool> mDestroyCommandPool;
VkPtr<PFN_vkAllocateCommandBuffers> mAllocateCommandBuffers;
@@ -158,10 +176,8 @@
VkPtr<PFN_vkEndCommandBuffer> mEndCommandBuffer;
VkPtr<PFN_vkCmdPipelineBarrier> mCmdPipelineBarrier;
- VkPtr<PFN_vkGetDeviceQueue> mGetDeviceQueue;
VkPtr<PFN_vkQueueSubmit> mQueueSubmit;
VkPtr<PFN_vkQueueWaitIdle> mQueueWaitIdle;
- VkPtr<PFN_vkDeviceWaitIdle> mDeviceWaitIdle;
VkPtr<PFN_vkCreateSemaphore> mCreateSemaphore;
VkPtr<PFN_vkDestroySemaphore> mDestroySemaphore;
@@ -172,7 +188,12 @@
RenderThread& mRenderThread;
- sk_sp<const GrVkBackendContext> mBackendContext;
+ VkInstance mInstance = VK_NULL_HANDLE;
+ VkPhysicalDevice mPhysicalDevice = VK_NULL_HANDLE;
+ VkDevice mDevice = VK_NULL_HANDLE;
+
+ uint32_t mGraphicsQueueIndex;
+ VkQueue mGraphicsQueue = VK_NULL_HANDLE;
uint32_t mPresentQueueIndex;
VkQueue mPresentQueue = VK_NULL_HANDLE;
VkCommandPool mCommandPool = VK_NULL_HANDLE;
diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp
index 7f8cb2d..3d50d2d 100644
--- a/libs/hwui/service/GraphicsStatsService.cpp
+++ b/libs/hwui/service/GraphicsStatsService.cpp
@@ -127,7 +127,7 @@
return false;
}
void* addr = mmap(nullptr, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
- if (!addr) {
+ if (addr == MAP_FAILED) {
int err = errno;
// The file not existing is normal for addToDump(), so only log if
// we get an unexpected error
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index 15c0ab1..eb67e6c 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -1094,7 +1094,7 @@
class ShadowTestCanvas : public SkCanvas {
public:
ShadowTestCanvas(int width, int height) : SkCanvas(width, height) {}
- int getIndex() { return mDrawCounter; }
+ int getDrawCounter() { return mDrawCounter; }
virtual void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override {
// expect to draw 2 RenderNodeDrawable, 1 StartReorderBarrierDrawable,
@@ -1109,17 +1109,36 @@
EXPECT_EQ(dy, TRANSLATE_Y);
}
- virtual void didConcat(const SkMatrix& matrix) override {
- // This function is invoked by EndReorderBarrierDrawable::drawShadow to apply shadow
- // matrix.
+ virtual void didSetMatrix(const SkMatrix& matrix) override {
mDrawCounter++;
- EXPECT_EQ(SkMatrix::MakeTrans(CASTER_X, CASTER_Y), matrix);
- EXPECT_EQ(SkMatrix::MakeTrans(CASTER_X + TRANSLATE_X, CASTER_Y + TRANSLATE_Y),
- getTotalMatrix());
+ // First invocation is EndReorderBarrierDrawable::drawShadow to apply shadow matrix.
+ // Second invocation is preparing the matrix for an elevated RenderNodeDrawable.
+ EXPECT_TRUE(matrix.isIdentity());
+ EXPECT_TRUE(getTotalMatrix().isIdentity());
+ }
+
+ virtual void didConcat(const SkMatrix& matrix) override {
+ mDrawCounter++;
+ if (mFirstDidConcat) {
+ // First invocation is EndReorderBarrierDrawable::drawShadow to apply shadow matrix.
+ mFirstDidConcat = false;
+ EXPECT_EQ(SkMatrix::MakeTrans(CASTER_X + TRANSLATE_X, CASTER_Y + TRANSLATE_Y),
+ matrix);
+ EXPECT_EQ(SkMatrix::MakeTrans(CASTER_X + TRANSLATE_X, CASTER_Y + TRANSLATE_Y),
+ getTotalMatrix());
+ } else {
+ // Second invocation is preparing the matrix for an elevated RenderNodeDrawable.
+ EXPECT_EQ(SkMatrix::MakeTrans(TRANSLATE_X, TRANSLATE_Y),
+ matrix);
+ EXPECT_EQ(SkMatrix::MakeTrans(TRANSLATE_X, TRANSLATE_Y),
+ getTotalMatrix());
+ }
}
protected:
int mDrawCounter = 0;
+ private:
+ bool mFirstDidConcat = true;
};
auto parent = TestUtils::createSkiaNode(
@@ -1143,7 +1162,7 @@
ShadowTestCanvas canvas(CANVAS_WIDTH, CANVAS_HEIGHT);
RenderNodeDrawable drawable(parent.get(), &canvas, false);
canvas.drawDrawable(&drawable);
- EXPECT_EQ(6, canvas.getIndex());
+ EXPECT_EQ(9, canvas.getDrawCounter());
}
// Draw a vector drawable twice but with different bounds and verify correct bounds are used.
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 196b886..1a282b2 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -794,6 +794,11 @@
* <p>
* This method should only be used by applications that replace the platform-wide
* management of audio settings or the main telephony application.
+ * <p>This method has no effect if the device implements a fixed volume policy
+ * as indicated by {@link #isVolumeFixed()}.
+ * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
+ * unless the app has been granted Do Not Disturb Access.
+ * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
*
* @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
* {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC},
@@ -804,6 +809,8 @@
* @param flags One or more flags.
* @see #adjustVolume(int, int)
* @see #setStreamVolume(int, int, int)
+ * @throws SecurityException if the adjustment triggers a Do Not Disturb change
+ * and the caller is not granted notification policy access.
*/
public void adjustStreamVolume(int streamType, int direction, int flags) {
final IAudioService service = getService();
@@ -1121,6 +1128,8 @@
* @see #getStreamMaxVolume(int)
* @see #getStreamVolume(int)
* @see #isVolumeFixed()
+ * @throws SecurityException if the volume change triggers a Do Not Disturb change
+ * and the caller is not granted notification policy access.
*/
public void setStreamVolume(int streamType, int index, int flags) {
final IAudioService service = getService();
diff --git a/media/java/android/media/MediaHTTPConnection.java b/media/java/android/media/MediaHTTPConnection.java
index aae1f51..6bf52bd 100644
--- a/media/java/android/media/MediaHTTPConnection.java
+++ b/media/java/android/media/MediaHTTPConnection.java
@@ -323,8 +323,10 @@
StrictMode.setThreadPolicy(policy);
try {
- if (offset != mCurrentOffset) {
- seekTo(offset);
+ synchronized(this) {
+ if (offset != mCurrentOffset) {
+ seekTo(offset);
+ }
}
int n = mInputStream.read(data, 0, size);
@@ -366,7 +368,7 @@
}
@Override
- public long getSize() {
+ public synchronized long getSize() {
if (mConnection == null) {
try {
seekTo(0);
@@ -379,7 +381,7 @@
}
@Override
- public String getMIMEType() {
+ public synchronized String getMIMEType() {
if (mConnection == null) {
try {
seekTo(0);
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index dcc872c..70ef81f 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -116,9 +116,9 @@
* these circumstances. Sometimes, due to programming errors, invoking a playback
* control operation in an invalid state may also occur. Under all these
* error conditions, the internal player engine invokes a user supplied
- * MediaPlayer2EventCallback.onError() method if an MediaPlayer2EventCallback has been
+ * EventCallback.onError() method if an EventCallback has been
* registered beforehand via
- * {@link #setMediaPlayer2EventCallback(Executor, MediaPlayer2EventCallback)}.
+ * {@link #setEventCallback(Executor, EventCallback)}.
* <ul>
* <li>It is important to note that once an error occurs, the
* MediaPlayer2 object enters the <em>Error</em> state (except as noted
@@ -159,9 +159,9 @@
* player engine continues working on the rest of preparation work
* until the preparation work completes. When the preparation completes,
* the internal player engine then calls a user supplied callback method,
- * onInfo() of the MediaPlayer2EventCallback interface with {@link #MEDIA_INFO_PREPARED},
- * if an MediaPlayer2EventCallback is registered beforehand via
- * {@link #setMediaPlayer2EventCallback(Executor, MediaPlayer2EventCallback)}.</li>
+ * onInfo() of the EventCallback interface with {@link #MEDIA_INFO_PREPARED},
+ * if an EventCallback is registered beforehand via
+ * {@link #setEventCallback(Executor, EventCallback)}.</li>
* <li>It is important to note that
* the <em>Preparing</em> state is a transient state, and the behavior
* of calling any method with side effect while a MediaPlayer2 object is
@@ -180,10 +180,10 @@
* whether the MediaPlayer2 object is in the <em>Started</em> state.
* <ul>
* <li>While in the <em>Started</em> state, the internal player engine calls
- * a user supplied callback method MediaPlayer2EventCallback.onInfo() with
- * {@link #MEDIA_INFO_BUFFERING_UPDATE} if an MediaPlayer2EventCallback has been
+ * a user supplied callback method EventCallback.onInfo() with
+ * {@link #MEDIA_INFO_BUFFERING_UPDATE} if an EventCallback has been
* registered beforehand via
- * {@link #setMediaPlayer2EventCallback(Executor, MediaPlayer2EventCallback)}.
+ * {@link #setEventCallback(Executor, EventCallback)}.
* This callback allows applications to keep track of the buffering status
* while streaming audio/video.</li>
* <li>Calling {@link #play()} has not effect
@@ -215,10 +215,10 @@
* call returns right away, the actual seek operation may take a while to
* finish, especially for audio/video being streamed. When the actual
* seek operation completes, the internal player engine calls a user
- * supplied MediaPlayer2EventCallback.onCallCompleted() with
+ * supplied EventCallback.onCallCompleted() with
* {@link #CALL_COMPLETED_SEEK_TO}
- * if an MediaPlayer2EventCallback has been registered beforehand via
- * {@link #setMediaPlayer2EventCallback(Executor, MediaPlayer2EventCallback)}.</li>
+ * if an EventCallback has been registered beforehand via
+ * {@link #setEventCallback(Executor, EventCallback)}.</li>
* <li>Please
* note that {@link #seekTo(long, int)} can also be called in the other states,
* such as <em>Prepared</em>, <em>Paused</em> and <em>PlaybackCompleted
@@ -238,9 +238,9 @@
* the MediaPlayer2 object shall remain in the <em>Started</em> state.</li>
* <li>If the looping mode was set to <var>false
* </var>, the player engine calls a user supplied callback method,
- * MediaPlayer2EventCallback.onCompletion(), if an MediaPlayer2EventCallback is
+ * EventCallback.onCompletion(), if an EventCallback is
* registered beforehand via
- * {@link #setMediaPlayer2EventCallback(Executor, MediaPlayer2EventCallback)}.
+ * {@link #setEventCallback(Executor, EventCallback)}.
* The invoke of the callback signals that the object is now in the <em>
* PlaybackCompleted</em> state.</li>
* <li>While in the <em>PlaybackCompleted</em>
@@ -387,7 +387,7 @@
* <td>{} </p></td>
* <td>This method can be called in any state and calling it does not change
* the object state. </p></td></tr>
- * <tr><td>setMediaPlayer2EventCallback </p></td>
+ * <tr><td>setEventCallback </p></td>
* <td>any </p></td>
* <td>{} </p></td>
* <td>This method can be called in any state and calling it does not change
@@ -445,7 +445,7 @@
* possible runtime errors during playback or streaming. Registration for
* these events is done by properly setting the appropriate listeners (via calls
* to
- * {@link #setMediaPlayer2EventCallback(Executor, MediaPlayer2EventCallback)},
+ * {@link #setEventCallback(Executor, EventCallback)},
* {@link #setDrmEventCallback(Executor, DrmEventCallback)}).
* In order to receive the respective callback
* associated with these listeners, applications are required to create
@@ -453,8 +453,8 @@
* thread by default has a Looper running).
*
*/
-public abstract class MediaPlayer2 extends MediaPlayerBase
- implements SubtitleController.Listener
+public abstract class MediaPlayer2 implements SubtitleController.Listener
+ , AutoCloseable
, AudioRouting {
/**
* Create a MediaPlayer2 object.
@@ -514,6 +514,12 @@
public MediaPlayer2() { }
/**
+ * Returns a {@link MediaPlayerBase} implementation which runs based on
+ * this MediaPlayer2 instance.
+ */
+ public abstract MediaPlayerBase getMediaPlayerBase();
+
+ /**
* Releases the resources held by this {@code MediaPlayer2} object.
*
* It is considered good practice to call this method when you're
@@ -549,7 +555,6 @@
*
*/
// This is an asynchronous call.
- @Override
public abstract void play();
/**
@@ -560,21 +565,18 @@
*
*/
// This is an asynchronous call.
- @Override
public abstract void prepare();
/**
* Pauses playback. Call play() to resume.
*/
// This is an asynchronous call.
- @Override
public abstract void pause();
/**
* Tries to play next data source if applicable.
*/
// This is an asynchronous call.
- @Override
public abstract void skipToNext();
/**
@@ -584,7 +586,6 @@
* @param msec the offset in milliseconds from the start to seek to
*/
// This is an asynchronous call.
- @Override
public void seekTo(long msec) {
seekTo(msec, SEEK_PREVIOUS_SYNC /* mode */);
}
@@ -594,7 +595,6 @@
*
* @return the current position in milliseconds
*/
- @Override
public abstract long getCurrentPosition();
/**
@@ -603,7 +603,6 @@
* @return the duration in milliseconds, if no duration is available
* (for example, if streaming live content), -1 is returned.
*/
- @Override
public abstract long getDuration();
/**
@@ -615,25 +614,60 @@
*
* @return the current buffered media source position in milliseconds
*/
- @Override
public abstract long getBufferedPosition();
/**
+ * MediaPlayer2 has not been prepared or just has been reset.
+ * In this state, MediaPlayer2 doesn't fetch data.
+ * @hide
+ */
+ public static final int PLAYER_STATE_IDLE = 1001;
+
+ /**
+ * MediaPlayer2 has been just prepared.
+ * In this state, MediaPlayer2 just fetches data from media source,
+ * but doesn't actively render data.
+ * @hide
+ */
+ public static final int PLAYER_STATE_PREPARED = 1002;
+
+ /**
+ * MediaPlayer2 is paused.
+ * In this state, MediaPlayer2 doesn't actively render data.
+ * @hide
+ */
+ public static final int PLAYER_STATE_PAUSED = 1003;
+
+ /**
+ * MediaPlayer2 is actively playing back data.
+ * @hide
+ */
+ public static final int PLAYER_STATE_PLAYING = 1004;
+
+ /**
+ * MediaPlayer2 has hit some fatal error and cannot continue playback.
+ * @hide
+ */
+ public static final int PLAYER_STATE_ERROR = 1005;
+
+ /**
+ * @hide
+ */
+ @IntDef(flag = false, prefix = "MEDIAPLAYER2_STATE", value = {
+ PLAYER_STATE_IDLE,
+ PLAYER_STATE_PREPARED,
+ PLAYER_STATE_PAUSED,
+ PLAYER_STATE_PLAYING,
+ PLAYER_STATE_ERROR })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface MediaPlayer2State {}
+
+ /**
* Gets the current player state.
*
* @return the current player state.
*/
- @Override
- public abstract @PlayerState int getPlayerState();
-
- /**
- * Gets the current buffering state of the player.
- * During buffering, see {@link #getBufferedPosition()} for the quantifying the amount already
- * buffered.
- * @return the buffering state, one of the following:
- */
- @Override
- public abstract @BuffState int getBufferingState();
+ public abstract @MediaPlayer2State int getState();
/**
* Sets the audio attributes for this MediaPlayer2.
@@ -643,14 +677,12 @@
* @param attributes a non-null set of audio attributes
*/
// This is an asynchronous call.
- @Override
public abstract void setAudioAttributes(@NonNull AudioAttributes attributes);
/**
* Gets the audio attributes for this MediaPlayer2.
* @return attributes a set of audio attributes
*/
- @Override
public abstract @Nullable AudioAttributes getAudioAttributes();
/**
@@ -659,7 +691,6 @@
* @param dsd the descriptor of data source you want to play
*/
// This is an asynchronous call.
- @Override
public abstract void setDataSource(@NonNull DataSourceDesc dsd);
/**
@@ -669,7 +700,6 @@
* @param dsd the descriptor of data source you want to play after current one
*/
// This is an asynchronous call.
- @Override
public abstract void setNextDataSource(@NonNull DataSourceDesc dsd);
/**
@@ -678,7 +708,6 @@
* @param dsds the list of data sources you want to play after current one
*/
// This is an asynchronous call.
- @Override
public abstract void setNextDataSources(@NonNull List<DataSourceDesc> dsds);
/**
@@ -686,7 +715,6 @@
*
* @return the current DataSourceDesc
*/
- @Override
public abstract @NonNull DataSourceDesc getCurrentDataSource();
/**
@@ -694,44 +722,9 @@
* @param loop true if the current data source is meant to loop.
*/
// This is an asynchronous call.
- @Override
public abstract void loopCurrent(boolean loop);
/**
- * Sets the playback speed.
- * A value of 1.0f is the default playback value.
- * A negative value indicates reverse playback, check {@link #isReversePlaybackSupported()}
- * before using negative values.<br>
- * After changing the playback speed, it is recommended to query the actual speed supported
- * by the player, see {@link #getPlaybackSpeed()}.
- * @param speed the desired playback speed
- */
- // This is an asynchronous call.
- @Override
- public abstract void setPlaybackSpeed(float speed);
-
- /**
- * Returns the actual playback speed to be used by the player when playing.
- * Note that it may differ from the speed set in {@link #setPlaybackSpeed(float)}.
- * @return the actual playback speed
- */
- @Override
- public float getPlaybackSpeed() {
- return 1.0f;
- }
-
- /**
- * Indicates whether reverse playback is supported.
- * Reverse playback is indicated by negative playback speeds, see
- * {@link #setPlaybackSpeed(float)}.
- * @return true if reverse playback is supported.
- */
- @Override
- public boolean isReversePlaybackSupported() {
- return false;
- }
-
- /**
* Sets the volume of the audio of the media to play, expressed as a linear multiplier
* on the audio samples.
* Note that this volume is specific to the player, and is separate from stream volume
@@ -741,7 +734,6 @@
* @param volume a value between 0.0f and {@link #getMaxPlayerVolume()}.
*/
// This is an asynchronous call.
- @Override
public abstract void setPlayerVolume(float volume);
/**
@@ -749,36 +741,16 @@
* Note that it does not take into account the associated stream volume.
* @return the player volume.
*/
- @Override
public abstract float getPlayerVolume();
/**
* @return the maximum volume that can be used in {@link #setPlayerVolume(float)}.
*/
- @Override
public float getMaxPlayerVolume() {
return 1.0f;
}
/**
- * Adds a callback to be notified of events for this player.
- * @param e the {@link Executor} to be used for the events.
- * @param cb the callback to receive the events.
- */
- // This is a synchronous call.
- @Override
- public abstract void registerPlayerEventCallback(@NonNull Executor e,
- @NonNull PlayerEventCallback cb);
-
- /**
- * Removes a previously registered callback for player events
- * @param cb the callback to remove
- */
- // This is a synchronous call.
- @Override
- public abstract void unregisterPlayerEventCallback(@NonNull PlayerEventCallback cb);
-
- /**
* Create a request parcel which can be routed to the native media
* player using {@link #invoke(Parcel, Parcel)}. The Parcel
* returned has the proper InterfaceToken set. The caller should
@@ -812,10 +784,10 @@
/**
* Insert a task in the command queue to help the client to identify whether a batch
* of commands has been finished. When this command is processed, a notification
- * {@code MediaPlayer2EventCallback.onCommandLabelReached} will be fired with the
+ * {@code EventCallback.onCommandLabelReached} will be fired with the
* given {@code label}.
*
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCommandLabelReached
+ * @see android.media.MediaPlayer2.EventCallback#onCommandLabelReached
*
* @param label An application specific Object used to help to identify the completeness
* of a batch of commands.
@@ -973,7 +945,8 @@
*/
// This is a synchronous call.
@Override
- public abstract void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener);
+ public abstract void removeOnRoutingChangedListener(
+ AudioRouting.OnRoutingChangedListener listener);
/**
* Set the low-level power management behavior for this MediaPlayer2.
@@ -1010,9 +983,9 @@
*
* @return the width of the video, or 0 if there is no video,
* no display surface was set, or the width has not been determined
- * yet. The {@code MediaPlayer2EventCallback} can be registered via
- * {@link #setMediaPlayer2EventCallback(Executor, MediaPlayer2EventCallback)} to provide a
- * notification {@code MediaPlayer2EventCallback.onVideoSizeChanged} when the width
+ * yet. The {@code EventCallback} can be registered via
+ * {@link #setEventCallback(Executor, EventCallback)} to provide a
+ * notification {@code EventCallback.onVideoSizeChanged} when the width
* is available.
*/
public abstract int getVideoWidth();
@@ -1022,9 +995,10 @@
*
* @return the height of the video, or 0 if there is no video,
* no display surface was set, or the height has not been determined
- * yet. The {@code MediaPlayer2EventCallback} can be registered via
- * {@link #setMediaPlayer2EventCallback(Executor, MediaPlayer2EventCallback)} to provide a
- * notification {@code MediaPlayer2EventCallback.onVideoSizeChanged} when the height is available.
+ * yet. The {@code EventCallback} can be registered via
+ * {@link #setEventCallback(Executor, EventCallback)} to provide a
+ * notification {@code EventCallback.onVideoSizeChanged} when the height is
+ * available.
*/
public abstract int getVideoHeight();
@@ -1051,60 +1025,6 @@
public abstract boolean isPlaying();
/**
- * MediaPlayer2 has not been prepared or just has been reset.
- * In this state, MediaPlayer2 doesn't fetch data.
- * @hide
- */
- public static final int MEDIAPLAYER2_STATE_IDLE = 1;
-
- /**
- * MediaPlayer2 has been just prepared.
- * In this state, MediaPlayer2 just fetches data from media source,
- * but doesn't actively render data.
- * @hide
- */
- public static final int MEDIAPLAYER2_STATE_PREPARED = 2;
-
- /**
- * MediaPlayer2 is paused.
- * In this state, MediaPlayer2 doesn't actively render data.
- * @hide
- */
- public static final int MEDIAPLAYER2_STATE_PAUSED = 3;
-
- /**
- * MediaPlayer2 is actively playing back data.
- * @hide
- */
- public static final int MEDIAPLAYER2_STATE_PLAYING = 4;
-
- /**
- * MediaPlayer2 has hit some fatal error and cannot continue playback.
- * @hide
- */
- public static final int MEDIAPLAYER2_STATE_ERROR = 5;
-
- /**
- * @hide
- */
- @IntDef(flag = false, prefix = "MEDIAPLAYER2_STATE", value = {
- MEDIAPLAYER2_STATE_IDLE,
- MEDIAPLAYER2_STATE_PREPARED,
- MEDIAPLAYER2_STATE_PAUSED,
- MEDIAPLAYER2_STATE_PLAYING,
- MEDIAPLAYER2_STATE_ERROR })
- @Retention(RetentionPolicy.SOURCE)
- public @interface MediaPlayer2State {}
-
- /**
- * Gets the current MediaPlayer2 state.
- *
- * @return the current MediaPlayer2 state.
- * @hide
- */
- public abstract @MediaPlayer2State int getMediaPlayer2State();
-
- /**
* Gets the current buffering management params used by the source component.
* Calling it only after {@code setDataSource} has been called.
* Each type of data source might have different set of default params.
@@ -1383,7 +1303,6 @@
* data source and calling prepare().
*/
// This is a synchronous call.
- @Override
public abstract void reset();
/**
@@ -1706,7 +1625,7 @@
* Interface definition for callbacks to be invoked when the player has the corresponding
* events.
*/
- public abstract static class MediaPlayer2EventCallback {
+ public abstract static class EventCallback {
/**
* Called to indicate the video size
*
@@ -1718,7 +1637,8 @@
* @param width the width of the video
* @param height the height of the video
*/
- public void onVideoSizeChanged(MediaPlayer2 mp, DataSourceDesc dsd, int width, int height) { }
+ public void onVideoSizeChanged(
+ MediaPlayer2 mp, DataSourceDesc dsd, int width, int height) { }
/**
* Called to indicate an avaliable timed text
@@ -1814,14 +1734,14 @@
* @param executor the executor through which the callback should be invoked
*/
// This is a synchronous call.
- public abstract void setMediaPlayer2EventCallback(@NonNull @CallbackExecutor Executor executor,
- @NonNull MediaPlayer2EventCallback eventCallback);
+ public abstract void setEventCallback(@NonNull @CallbackExecutor Executor executor,
+ @NonNull EventCallback eventCallback);
/**
- * Clears the {@link MediaPlayer2EventCallback}.
+ * Clears the {@link EventCallback}.
*/
// This is a synchronous call.
- public abstract void clearMediaPlayer2EventCallback();
+ public abstract void clearEventCallback();
/**
* Interface definition of a callback to be invoked when a
@@ -1849,14 +1769,14 @@
* in include/media/mediaplayer2.h!
*/
/** Unspecified media player error.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onError
+ * @see android.media.MediaPlayer2.EventCallback#onError
*/
public static final int MEDIA_ERROR_UNKNOWN = 1;
/** The video is streamed and its container is not valid for progressive
* playback i.e the video's index (e.g moov atom) is not at the start of the
* file.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onError
+ * @see android.media.MediaPlayer2.EventCallback#onError
*/
public static final int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200;
@@ -1872,7 +1792,7 @@
/** Unspecified low-level system error. This value originated from UNKNOWN_ERROR in
* system/core/include/utils/Errors.h
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onError
+ * @see android.media.MediaPlayer2.EventCallback#onError
* @hide
*/
public static final int MEDIA_ERROR_SYSTEM = -2147483648;
@@ -1896,62 +1816,62 @@
* in include/media/mediaplayer2.h!
*/
/** Unspecified media player info.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
+ * @see android.media.MediaPlayer2.EventCallback#onInfo
*/
public static final int MEDIA_INFO_UNKNOWN = 1;
/** The player switched to this datas source because it is the
* next-to-be-played in the playlist.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
+ * @see android.media.MediaPlayer2.EventCallback#onInfo
*/
public static final int MEDIA_INFO_STARTED_AS_NEXT = 2;
/** The player just pushed the very first video frame for rendering.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
+ * @see android.media.MediaPlayer2.EventCallback#onInfo
*/
public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3;
/** The player just rendered the very first audio sample.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
+ * @see android.media.MediaPlayer2.EventCallback#onInfo
*/
public static final int MEDIA_INFO_AUDIO_RENDERING_START = 4;
/** The player just completed the playback of this data source.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
+ * @see android.media.MediaPlayer2.EventCallback#onInfo
*/
public static final int MEDIA_INFO_PLAYBACK_COMPLETE = 5;
/** The player just completed the playback of the full playlist.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
+ * @see android.media.MediaPlayer2.EventCallback#onInfo
*/
public static final int MEDIA_INFO_PLAYLIST_END = 6;
/** The player just prepared a data source.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
+ * @see android.media.MediaPlayer2.EventCallback#onInfo
*/
public static final int MEDIA_INFO_PREPARED = 100;
/** The video is too complex for the decoder: it can't decode frames fast
* enough. Possibly only the audio plays fine at this stage.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
+ * @see android.media.MediaPlayer2.EventCallback#onInfo
*/
public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700;
/** MediaPlayer2 is temporarily pausing playback internally in order to
* buffer more data.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
+ * @see android.media.MediaPlayer2.EventCallback#onInfo
*/
public static final int MEDIA_INFO_BUFFERING_START = 701;
/** MediaPlayer2 is resuming playback after filling buffers.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
+ * @see android.media.MediaPlayer2.EventCallback#onInfo
*/
public static final int MEDIA_INFO_BUFFERING_END = 702;
/** Estimated network bandwidth information (kbps) is available; currently this event fires
* simultaneously as {@link #MEDIA_INFO_BUFFERING_START} and {@link #MEDIA_INFO_BUFFERING_END}
* when playing network files.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
+ * @see android.media.MediaPlayer2.EventCallback#onInfo
* @hide
*/
public static final int MEDIA_INFO_NETWORK_BANDWIDTH = 703;
@@ -1963,26 +1883,26 @@
* has already been played indicates that the next 30 percent of the
* content to play has been buffered.
*
- * The {@code extra} parameter in {@code MediaPlayer2EventCallback.onInfo} is the
+ * The {@code extra} parameter in {@code EventCallback.onInfo} is the
* percentage (0-100) of the content that has been buffered or played thus far.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
+ * @see android.media.MediaPlayer2.EventCallback#onInfo
*/
public static final int MEDIA_INFO_BUFFERING_UPDATE = 704;
/** Bad interleaving means that a media has been improperly interleaved or
* not interleaved at all, e.g has all the video samples first then all the
* audio ones. Video is playing but a lot of disk seeks may be happening.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
+ * @see android.media.MediaPlayer2.EventCallback#onInfo
*/
public static final int MEDIA_INFO_BAD_INTERLEAVING = 800;
/** The media cannot be seeked (e.g live stream)
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
+ * @see android.media.MediaPlayer2.EventCallback#onInfo
*/
public static final int MEDIA_INFO_NOT_SEEKABLE = 801;
/** A new set of metadata is available.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
+ * @see android.media.MediaPlayer2.EventCallback#onInfo
*/
public static final int MEDIA_INFO_METADATA_UPDATE = 802;
@@ -1994,30 +1914,30 @@
/** Informs that audio is not playing. Note that playback of the video
* is not interrupted.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
+ * @see android.media.MediaPlayer2.EventCallback#onInfo
*/
public static final int MEDIA_INFO_AUDIO_NOT_PLAYING = 804;
/** Informs that video is not playing. Note that playback of the audio
* is not interrupted.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
+ * @see android.media.MediaPlayer2.EventCallback#onInfo
*/
public static final int MEDIA_INFO_VIDEO_NOT_PLAYING = 805;
/** Failed to handle timed text track properly.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
+ * @see android.media.MediaPlayer2.EventCallback#onInfo
*
* {@hide}
*/
public static final int MEDIA_INFO_TIMED_TEXT_ERROR = 900;
/** Subtitle track was not supported by the media framework.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
+ * @see android.media.MediaPlayer2.EventCallback#onInfo
*/
public static final int MEDIA_INFO_UNSUPPORTED_SUBTITLE = 901;
/** Reading the subtitle track takes too long.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
+ * @see android.media.MediaPlayer2.EventCallback#onInfo
*/
public static final int MEDIA_INFO_SUBTITLE_TIMED_OUT = 902;
@@ -2052,129 +1972,129 @@
//--------------------------------------------------------------------------
/** The player just completed a call {@link #attachAuxEffect}.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_COMPLETED_ATTACH_AUX_EFFECT = 1;
/** The player just completed a call {@link #deselectTrack}.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_COMPLETED_DESELECT_TRACK = 2;
/** The player just completed a call {@link #loopCurrent}.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_COMPLETED_LOOP_CURRENT = 3;
/** The player just completed a call {@link #pause}.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_COMPLETED_PAUSE = 4;
/** The player just completed a call {@link #play}.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_COMPLETED_PLAY = 5;
/** The player just completed a call {@link #prepare}.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_COMPLETED_PREPARE = 6;
/** The player just completed a call {@link #releaseDrm}.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_COMPLETED_RELEASE_DRM = 12;
/** The player just completed a call {@link #restoreDrmKeys}.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_COMPLETED_RESTORE_DRM_KEYS = 13;
/** The player just completed a call {@link #seekTo}.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_COMPLETED_SEEK_TO = 14;
/** The player just completed a call {@link #selectTrack}.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_COMPLETED_SELECT_TRACK = 15;
/** The player just completed a call {@link #setAudioAttributes}.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_COMPLETED_SET_AUDIO_ATTRIBUTES = 16;
/** The player just completed a call {@link #setAudioSessionId}.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_COMPLETED_SET_AUDIO_SESSION_ID = 17;
/** The player just completed a call {@link #setAuxEffectSendLevel}.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_COMPLETED_SET_AUX_EFFECT_SEND_LEVEL = 18;
/** The player just completed a call {@link #setDataSource}.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_COMPLETED_SET_DATA_SOURCE = 19;
/** The player just completed a call {@link #setNextDataSource}.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_COMPLETED_SET_NEXT_DATA_SOURCE = 22;
/** The player just completed a call {@link #setNextDataSources}.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_COMPLETED_SET_NEXT_DATA_SOURCES = 23;
/** The player just completed a call {@link #setPlaybackParams}.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_COMPLETED_SET_PLAYBACK_PARAMS = 24;
/** The player just completed a call {@link #setPlaybackSpeed}.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_COMPLETED_SET_PLAYBACK_SPEED = 25;
/** The player just completed a call {@link #setPlayerVolume}.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_COMPLETED_SET_PLAYER_VOLUME = 26;
/** The player just completed a call {@link #setSurface}.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_COMPLETED_SET_SURFACE = 27;
/** The player just completed a call {@link #setSyncParams}.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_COMPLETED_SET_SYNC_PARAMS = 28;
/** The player just completed a call {@link #skipToNext}.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_COMPLETED_SKIP_TO_NEXT = 29;
/** The player just completed a call {@link #setBufferingParams}.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
* @hide
*/
public static final int CALL_COMPLETED_SET_BUFFERING_PARAMS = 1001;
/** The player just completed a call {@code setVideoScalingMode}.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
* @hide
*/
public static final int CALL_COMPLETED_SET_VIDEO_SCALING_MODE = 1002;
/** The player just completed a call {@code notifyWhenCommandLabelReached}.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCommandLabelReached
+ * @see android.media.MediaPlayer2.EventCallback#onCommandLabelReached
* @hide
*/
public static final int CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED = 1003;
@@ -2200,7 +2120,6 @@
CALL_COMPLETED_SET_NEXT_DATA_SOURCE,
CALL_COMPLETED_SET_NEXT_DATA_SOURCES,
CALL_COMPLETED_SET_PLAYBACK_PARAMS,
- CALL_COMPLETED_SET_PLAYBACK_SPEED,
CALL_COMPLETED_SET_PLAYER_VOLUME,
CALL_COMPLETED_SET_SURFACE,
CALL_COMPLETED_SET_SYNC_PARAMS,
@@ -2213,38 +2132,38 @@
public @interface CallCompleted {}
/** Status code represents that call is completed without an error.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_STATUS_NO_ERROR = 0;
/** Status code represents that call is ended with an unknown error.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_STATUS_ERROR_UNKNOWN = Integer.MIN_VALUE;
/** Status code represents that the player is not in valid state for the operation.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_STATUS_INVALID_OPERATION = 1;
/** Status code represents that the argument is illegal.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_STATUS_BAD_VALUE = 2;
/** Status code represents that the operation is not allowed.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_STATUS_PERMISSION_DENIED = 3;
/** Status code represents a file or network related operation error.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_STATUS_ERROR_IO = 4;
/** Status code represents that DRM operation is called before preparing a DRM scheme through
* {@link #prepareDrm}.
- * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+ * @see android.media.MediaPlayer2.EventCallback#onCallCompleted
*/
public static final int CALL_STATUS_NO_DRM_SCHEME = 5;
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 56423fd..2b61b2e 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -173,6 +173,11 @@
native_setup(new WeakReference<MediaPlayer2Impl>(this));
}
+ @Override
+ public MediaPlayerBase getMediaPlayerBase() {
+ return null;
+ }
+
/**
* Releases the resources held by this {@code MediaPlayer2} object.
*
@@ -313,39 +318,11 @@
}
@Override
- public @PlayerState int getPlayerState() {
- int mediaplayer2State = getMediaPlayer2State();
- int playerState;
- switch (mediaplayer2State) {
- case MEDIAPLAYER2_STATE_IDLE:
- playerState = PLAYER_STATE_IDLE;
- break;
- case MEDIAPLAYER2_STATE_PREPARED:
- case MEDIAPLAYER2_STATE_PAUSED:
- playerState = PLAYER_STATE_PAUSED;
- break;
- case MEDIAPLAYER2_STATE_PLAYING:
- playerState = PLAYER_STATE_PLAYING;
- break;
- case MEDIAPLAYER2_STATE_ERROR:
- default:
- playerState = PLAYER_STATE_ERROR;
- break;
- }
-
- return playerState;
+ public @MediaPlayer2State int getState() {
+ return native_getState();
}
- /**
- * Gets the current buffering state of the player.
- * During buffering, see {@link #getBufferedPosition()} for the quantifying the amount already
- * buffered.
- */
- @Override
- public @BuffState int getBufferingState() {
- // TODO: use cached state or call native function.
- return BUFFERING_STATE_UNKNOWN;
- }
+ private native int native_getState();
/**
* Sets the audio attributes for this MediaPlayer2.
@@ -427,8 +404,8 @@
mNextSourceState = NEXT_SOURCE_STATE_INIT;
mNextSourcePlayPending = false;
}
- int state = getMediaPlayer2State();
- if (state != MEDIAPLAYER2_STATE_IDLE) {
+ int state = getState();
+ if (state != PLAYER_STATE_IDLE) {
synchronized (mSrcLock) {
prepareNextDataSource_l();
}
@@ -465,8 +442,8 @@
mNextSourceState = NEXT_SOURCE_STATE_INIT;
mNextSourcePlayPending = false;
}
- int state = getMediaPlayer2State();
- if (state != MEDIAPLAYER2_STATE_IDLE) {
+ int state = getState();
+ if (state != PLAYER_STATE_IDLE) {
synchronized (mSrcLock) {
prepareNextDataSource_l();
}
@@ -500,46 +477,6 @@
private native void setLooping(boolean looping);
/**
- * Sets the playback speed.
- * A value of 1.0f is the default playback value.
- * A negative value indicates reverse playback, check {@link #isReversePlaybackSupported()}
- * before using negative values.<br>
- * After changing the playback speed, it is recommended to query the actual speed supported
- * by the player, see {@link #getPlaybackSpeed()}.
- * @param speed the desired playback speed
- */
- @Override
- public void setPlaybackSpeed(float speed) {
- addTask(new Task(CALL_COMPLETED_SET_PLAYBACK_SPEED, false) {
- @Override
- void process() {
- _setPlaybackParams(getPlaybackParams().setSpeed(speed));
- }
- });
- }
-
- /**
- * Returns the actual playback speed to be used by the player when playing.
- * Note that it may differ from the speed set in {@link #setPlaybackSpeed(float)}.
- * @return the actual playback speed
- */
- @Override
- public float getPlaybackSpeed() {
- return getPlaybackParams().getSpeed();
- }
-
- /**
- * Indicates whether reverse playback is supported.
- * Reverse playback is indicated by negative playback speeds, see
- * {@link #setPlaybackSpeed(float)}.
- * @return true if reverse playback is supported.
- */
- @Override
- public boolean isReversePlaybackSupported() {
- return false;
- }
-
- /**
* Sets the volume of the audio of the media to play, expressed as a linear multiplier
* on the audio samples.
* Note that this volume is specific to the player, and is separate from stream volume
@@ -579,25 +516,6 @@
return 1.0f;
}
- /**
- * Adds a callback to be notified of events for this player.
- * @param e the {@link Executor} to be used for the events.
- * @param cb the callback to receive the events.
- */
- @Override
- public void registerPlayerEventCallback(@NonNull Executor e,
- @NonNull PlayerEventCallback cb) {
- }
-
- /**
- * Removes a previously registered callback for player events
- * @param cb the callback to remove
- */
- @Override
- public void unregisterPlayerEventCallback(@NonNull PlayerEventCallback cb) {
- }
-
-
private static final int NEXT_SOURCE_STATE_ERROR = -1;
private static final int NEXT_SOURCE_STATE_INIT = 0;
private static final int NEXT_SOURCE_STATE_PREPARING = 1;
@@ -666,7 +584,7 @@
@Override
void process() {
synchronized (mEventCbLock) {
- for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
+ for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
cb.first.execute(() -> cb.second.onCommandLabelReached(
MediaPlayer2Impl.this, label));
}
@@ -1305,9 +1223,9 @@
*
* @return the width of the video, or 0 if there is no video,
* no display surface was set, or the width has not been determined
- * yet. The {@code MediaPlayer2EventCallback} can be registered via
- * {@link #setMediaPlayer2EventCallback(Executor, MediaPlayer2EventCallback)} to provide a
- * notification {@code MediaPlayer2EventCallback.onVideoSizeChanged} when the width
+ * yet. The {@code EventCallback} can be registered via
+ * {@link #setEventCallback(Executor, EventCallback)} to provide a
+ * notification {@code EventCallback.onVideoSizeChanged} when the width
* is available.
*/
@Override
@@ -1318,9 +1236,9 @@
*
* @return the height of the video, or 0 if there is no video,
* no display surface was set, or the height has not been determined
- * yet. The {@code MediaPlayer2EventCallback} can be registered via
- * {@link #setMediaPlayer2EventCallback(Executor, MediaPlayer2EventCallback)} to provide a
- * notification {@code MediaPlayer2EventCallback.onVideoSizeChanged} when the height
+ * yet. The {@code EventCallback} can be registered via
+ * {@link #setEventCallback(Executor, EventCallback)} to provide a
+ * notification {@code EventCallback.onVideoSizeChanged} when the height
* is available.
*/
@Override
@@ -1355,13 +1273,6 @@
@Override
public native boolean isPlaying();
- @Override
- public @MediaPlayer2State int getMediaPlayer2State() {
- return native_getMediaPlayer2State();
- }
-
- private native int native_getMediaPlayer2State();
-
/**
* Gets the current buffering management params used by the source component.
* Calling it only after {@code setDataSource} has been called.
@@ -2820,7 +2731,7 @@
if (dsd != null) {
synchronized (mEventCbLock) {
- for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
+ for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
cb.first.execute(() -> cb.second.onInfo(
mMediaPlayer, dsd, MEDIA_INFO_PREPARED, 0));
}
@@ -2882,7 +2793,7 @@
}
synchronized (mEventCbLock) {
- for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
+ for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
cb.first.execute(() -> cb.second.onInfo(
mMediaPlayer, dsd, MEDIA_INFO_PLAYBACK_COMPLETE, 0));
}
@@ -2916,7 +2827,7 @@
synchronized (mEventCbLock) {
if (srcId == mCurrentSrcId) {
mBufferedPercentageCurrent.set(percent);
- for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
+ for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
cb.first.execute(() -> cb.second.onInfo(
mMediaPlayer, mCurrentDSD, MEDIA_INFO_BUFFERING_UPDATE,
percent));
@@ -2924,7 +2835,7 @@
} else if (srcId == mNextSrcId && !mNextDSDs.isEmpty()) {
mBufferedPercentageNext.set(percent);
DataSourceDesc nextDSD = mNextDSDs.get(0);
- for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
+ for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
cb.first.execute(() -> cb.second.onInfo(
mMediaPlayer, nextDSD, MEDIA_INFO_BUFFERING_UPDATE,
percent));
@@ -2962,7 +2873,7 @@
final int width = msg.arg1;
final int height = msg.arg2;
synchronized (mEventCbLock) {
- for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
+ for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
cb.first.execute(() -> cb.second.onVideoSizeChanged(
mMediaPlayer, mCurrentDSD, width, height));
}
@@ -2974,7 +2885,7 @@
{
Log.e(TAG, "Error (" + msg.arg1 + "," + msg.arg2 + ")");
synchronized (mEventCbLock) {
- for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
+ for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
cb.first.execute(() -> cb.second.onError(
mMediaPlayer, mCurrentDSD, what, extra));
cb.first.execute(() -> cb.second.onInfo(
@@ -3027,7 +2938,7 @@
}
synchronized (mEventCbLock) {
- for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
+ for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
cb.first.execute(() -> cb.second.onInfo(
mMediaPlayer, mCurrentDSD, what, extra));
}
@@ -3057,7 +2968,7 @@
}
synchronized (mEventCbLock) {
- for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
+ for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
cb.first.execute(() -> cb.second.onTimedText(mMediaPlayer, mCurrentDSD, text));
}
}
@@ -3091,7 +3002,7 @@
}
synchronized (mEventCbLock) {
- for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
+ for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
cb.first.execute(() -> cb.second.onTimedMetaDataAvailable(
mMediaPlayer, mCurrentDSD, data));
}
@@ -3196,8 +3107,8 @@
}
private final Object mEventCbLock = new Object();
- private ArrayList<Pair<Executor, MediaPlayer2EventCallback> > mEventCallbackRecords
- = new ArrayList<Pair<Executor, MediaPlayer2EventCallback> >();
+ private ArrayList<Pair<Executor, EventCallback> > mEventCallbackRecords
+ = new ArrayList<Pair<Executor, EventCallback> >();
/**
* Register a callback to be invoked when the media source is ready
@@ -3207,14 +3118,14 @@
* @param executor the executor through which the callback should be invoked
*/
@Override
- public void setMediaPlayer2EventCallback(@NonNull @CallbackExecutor Executor executor,
- @NonNull MediaPlayer2EventCallback eventCallback) {
+ public void setEventCallback(@NonNull @CallbackExecutor Executor executor,
+ @NonNull EventCallback eventCallback) {
if (eventCallback == null) {
- throw new IllegalArgumentException("Illegal null MediaPlayer2EventCallback");
+ throw new IllegalArgumentException("Illegal null EventCallback");
}
if (executor == null) {
throw new IllegalArgumentException(
- "Illegal null Executor for the MediaPlayer2EventCallback");
+ "Illegal null Executor for the EventCallback");
}
synchronized (mEventCbLock) {
mEventCallbackRecords.add(new Pair(executor, eventCallback));
@@ -3222,10 +3133,10 @@
}
/**
- * Clears the {@link MediaPlayer2EventCallback}.
+ * Clears the {@link EventCallback}.
*/
@Override
- public void clearMediaPlayer2EventCallback() {
+ public void clearEventCallback() {
synchronized (mEventCbLock) {
mEventCallbackRecords.clear();
}
@@ -3281,11 +3192,11 @@
public void setDrmEventCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull DrmEventCallback eventCallback) {
if (eventCallback == null) {
- throw new IllegalArgumentException("Illegal null MediaPlayer2EventCallback");
+ throw new IllegalArgumentException("Illegal null EventCallback");
}
if (executor == null) {
throw new IllegalArgumentException(
- "Illegal null Executor for the MediaPlayer2EventCallback");
+ "Illegal null Executor for the EventCallback");
}
synchronized (mDrmEventCbLock) {
mDrmEventCallbackRecords.add(new Pair(executor, eventCallback));
@@ -4786,7 +4697,7 @@
return;
}
synchronized (mEventCbLock) {
- for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
+ for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
cb.first.execute(() -> cb.second.onCallCompleted(
MediaPlayer2Impl.this, mDSD, mMediaCallType, status));
}
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index c36858a..a45aa90 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -612,8 +612,12 @@
Image_setBufferItem(env, image, buffer);
env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp,
static_cast<jlong>(buffer->mTimestamp));
+ auto transform = buffer->mTransform;
+ if (buffer->mTransformToDisplayInverse) {
+ transform |= NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
+ }
env->SetIntField(image, gSurfaceImageClassInfo.mTransform,
- static_cast<jint>(buffer->mTransform));
+ static_cast<jint>(transform));
env->SetIntField(image, gSurfaceImageClassInfo.mScalingMode,
static_cast<jint>(buffer->mScalingMode));
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index 6546cf0..d166cc3 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -786,13 +786,13 @@
}
static jint
-android_media_MediaPlayer2_getMediaPlayer2State(JNIEnv *env, jobject thiz)
+android_media_MediaPlayer2_getState(JNIEnv *env, jobject thiz)
{
sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
if (mp == NULL) {
return MEDIAPLAYER2_STATE_IDLE;
}
- return (jint)mp->getMediaPlayer2State();
+ return (jint)mp->getState();
}
static jint
@@ -1502,7 +1502,7 @@
{"_prepare", "()V", (void *)android_media_MediaPlayer2_prepare},
{"_start", "()V", (void *)android_media_MediaPlayer2_start},
{"_stop", "()V", (void *)android_media_MediaPlayer2_stop},
- {"native_getMediaPlayer2State", "()I", (void *)android_media_MediaPlayer2_getMediaPlayer2State},
+ {"native_getState", "()I", (void *)android_media_MediaPlayer2_getState},
{"getVideoWidth", "()I", (void *)android_media_MediaPlayer2_getVideoWidth},
{"getVideoHeight", "()I", (void *)android_media_MediaPlayer2_getVideoHeight},
{"native_getMetrics", "()Landroid/os/PersistableBundle;", (void *)android_media_MediaPlayer2_native_getMetrics},
diff --git a/media/native/midi/include/midi.h b/media/native/midi/include/midi.h
index 780d8a7..755d09f 100644
--- a/media/native/midi/include/midi.h
+++ b/media/native/midi/include/midi.h
@@ -71,7 +71,7 @@
* @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN} - an unknown error occurred.
*/
media_status_t AMIDI_API AMidiDevice_fromJava(
- JNIEnv *env, jobject midiDeviceObj, AMidiDevice **outDevicePtrPtr);
+ JNIEnv *env, jobject midiDeviceObj, AMidiDevice **outDevicePtrPtr) __INTRODUCED_IN(29);
/**
* Disconnects the native Midi Device Object from the associated Java MidiDevice object.
@@ -88,7 +88,7 @@
* - the JNI interface initialization to the associated java MidiDevice failed.
* @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN} - couldn't retrieve the device info.
*/
-media_status_t AMIDI_API AMidiDevice_release(const AMidiDevice *midiDevice);
+media_status_t AMIDI_API AMidiDevice_release(const AMidiDevice *midiDevice) __INTRODUCED_IN(29);
/**
* Gets the MIDI device type.
@@ -104,7 +104,7 @@
* parameter is NULL.
* @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN} - Unknown error.
*/
-int32_t AMIDI_API AMidiDevice_getType(const AMidiDevice *device);
+int32_t AMIDI_API AMidiDevice_getType(const AMidiDevice *device) __INTRODUCED_IN(29);
/**
* Gets the number of input (sending) ports available on the specified MIDI device.
@@ -117,7 +117,7 @@
* parameter is NULL.
* @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN} - couldn't retrieve the device info.
*/
-ssize_t AMIDI_API AMidiDevice_getNumInputPorts(const AMidiDevice *device);
+ssize_t AMIDI_API AMidiDevice_getNumInputPorts(const AMidiDevice *device) __INTRODUCED_IN(29);
/**
* Gets the number of output (receiving) ports available on the specified MIDI device.
@@ -130,7 +130,7 @@
* parameter is NULL.
* @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN}- couldn't retrieve the device info.
*/
-ssize_t AMIDI_API AMidiDevice_getNumOutputPorts(const AMidiDevice *device);
+ssize_t AMIDI_API AMidiDevice_getNumOutputPorts(const AMidiDevice *device) __INTRODUCED_IN(29);
/*
* API for receiving data from the Output port of a device.
@@ -149,14 +149,14 @@
* @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN} - Unknown Error.
*/
media_status_t AMIDI_API AMidiOutputPort_open(const AMidiDevice *device, int32_t portNumber,
- AMidiOutputPort **outOutputPortPtr);
+ AMidiOutputPort **outOutputPortPtr) __INTRODUCED_IN(29);
/**
* Closes the output port.
*
* @param outputPort The native API port identifier of the port.
*/
-void AMIDI_API AMidiOutputPort_close(const AMidiOutputPort *outputPort);
+void AMIDI_API AMidiOutputPort_close(const AMidiOutputPort *outputPort) __INTRODUCED_IN(29);
/**
* Receives the next pending MIDI message. To retrieve all pending messages, the client should
@@ -177,7 +177,7 @@
* @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN} - Unknown Error.
*/
ssize_t AMIDI_API AMidiOutputPort_receive(const AMidiOutputPort *outputPort, int32_t *opcodePtr,
- uint8_t *buffer, size_t maxBytes, size_t* numBytesReceivedPtr, int64_t *outTimestampPtr);
+ uint8_t *buffer, size_t maxBytes, size_t* numBytesReceivedPtr, int64_t *outTimestampPtr) __INTRODUCED_IN(29);
/*
* API for sending data to the Input port of a device.
@@ -196,7 +196,7 @@
* @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN} - Unknown Error.
*/
media_status_t AMIDI_API AMidiInputPort_open(const AMidiDevice *device, int32_t portNumber,
- AMidiInputPort **outInputPortPtr);
+ AMidiInputPort **outInputPortPtr) __INTRODUCED_IN(29);
/**
* Sends data to the specified input port.
@@ -210,7 +210,7 @@
* was NULL, the specified buffer was NULL.
*/
ssize_t AMIDI_API AMidiInputPort_send(const AMidiInputPort *inputPort, const uint8_t *buffer,
- size_t numBytes);
+ size_t numBytes) __INTRODUCED_IN(29);
/**
* Sends data to the specified input port with a timestamp.
@@ -225,7 +225,7 @@
* was NULL, the specified buffer was NULL.
*/
ssize_t AMIDI_API AMidiInputPort_sendWithTimestamp(const AMidiInputPort *inputPort,
- const uint8_t *buffer, size_t numBytes, int64_t timestamp);
+ const uint8_t *buffer, size_t numBytes, int64_t timestamp) __INTRODUCED_IN(29);
/**
* Sends a message with a 'MIDI flush command code' to the specified port. This should cause
@@ -239,14 +239,14 @@
* @see AMEDIA_ERROR_UNSUPPORTED {@link AMEDIA_ERROR_UNSUPPORTED} The FLUSH command couldn't
* be sent.
*/
-media_status_t AMIDI_API AMidiInputPort_sendFlush(const AMidiInputPort *inputPort);
+media_status_t AMIDI_API AMidiInputPort_sendFlush(const AMidiInputPort *inputPort) __INTRODUCED_IN(29);
/**
* Closes the input port.
*
* @param inputPort Identifies the input (sending) port to close.
*/
-void AMIDI_API AMidiInputPort_close(const AMidiInputPort *inputPort);
+void AMIDI_API AMidiInputPort_close(const AMidiInputPort *inputPort) __INTRODUCED_IN(29);
#ifdef __cplusplus
}
diff --git a/packages/CarrierDefaultApp/res/values-el/strings.xml b/packages/CarrierDefaultApp/res/values-el/strings.xml
index a13f634..016e68f 100644
--- a/packages/CarrierDefaultApp/res/values-el/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-el/strings.xml
@@ -6,7 +6,7 @@
<string name="portal_notification_id" msgid="5155057562457079297">"Τα δεδομένα κινητής τηλεφωνίας εξαντλήθηκαν"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Τα δεδομένα κινητής τηλεφωνίας έχουν απενεργοποιηθεί"</string>
<string name="portal_notification_detail" msgid="2295729385924660881">"Πατήστε για να επισκεφτείτε τον ιστότοπο %s"</string>
- <string name="no_data_notification_detail" msgid="3112125343857014825">"Επικοινωνήστε με τον παροχέα υπηρεσιών σας %s"</string>
+ <string name="no_data_notification_detail" msgid="3112125343857014825">"Επικοινωνήστε με τον πάροχο υπηρεσιών σας %s"</string>
<string name="no_mobile_data_connection_title" msgid="7449525772416200578">"Δεν υπάρχει σύνδεση δεδομένων κινητής τηλεφωνίας"</string>
<string name="no_mobile_data_connection" msgid="544980465184147010">"Προσθήκη δεδομένων ή προγράμματος περιαγωγής μέσω του %s"</string>
<string name="mobile_data_status_notification_channel_name" msgid="833999690121305708">"Κατάσταση δεδομένων κινητής τηλεφωνίας"</string>
diff --git a/packages/EasterEgg/Android.bp b/packages/EasterEgg/Android.bp
new file mode 100644
index 0000000..43ed810
--- /dev/null
+++ b/packages/EasterEgg/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2018 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.
+//
+
+android_app {
+ // the build system in pi-dev can't quite handle R.java in kt
+ // so we will have a mix of java and kotlin files
+ srcs: ["src/**/*.java", "src/**/*.kt"],
+
+ resource_dirs: ["res"],
+
+ name: "EasterEgg",
+
+ certificate: "platform",
+
+ sdk_version: "current",
+
+ optimize: {
+ enabled: false,
+ }
+}
diff --git a/packages/EasterEgg/Android.mk b/packages/EasterEgg/Android.mk
deleted file mode 100644
index 8fa4d6a..0000000
--- a/packages/EasterEgg/Android.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- jsr305
-
-LOCAL_STATIC_ANDROID_LIBRARIES := \
- androidx.legacy_legacy-support-v4 \
- androidx.legacy_legacy-support-v13 \
- androidx.dynamicanimation_dynamicanimation \
- androidx.recyclerview_recyclerview \
- androidx.preference_preference \
- androidx.appcompat_appcompat \
- androidx.legacy_legacy-preference-v14
-
-LOCAL_USE_AAPT2 := true
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-
-LOCAL_PACKAGE_NAME := EasterEgg
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_CERTIFICATE := platform
-
-include $(BUILD_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/EasterEgg/AndroidManifest.xml b/packages/EasterEgg/AndroidManifest.xml
index e8ea32b..c7dd40d 100644
--- a/packages/EasterEgg/AndroidManifest.xml
+++ b/packages/EasterEgg/AndroidManifest.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-Copyright (C) 2016 The Android Open Source Project
+ Copyright (C) 2018 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -15,85 +15,28 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.egg"
- android:versionCode="1"
- android:versionName="1.0">
+ package="com.android.egg"
+ android:versionCode="1"
+ android:versionName="1.0">
- <uses-sdk android:minSdkVersion="26" />
+ <uses-sdk android:minSdkVersion="28" />
- <uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <application
+ android:icon="@drawable/icon"
+ android:label="@string/app_name">
- <application android:label="@string/app_name" android:icon="@drawable/icon">
-
- <activity android:name=".octo.Ocquarium"
- android:theme="@android:style/Theme.DeviceDefault.NoActionBar.Fullscreen"
- android:label="@string/app_name">
+ <activity
+ android:name=".paint.PaintActivity"
+ android:configChanges="orientation|keyboardHidden|screenSize|uiMode"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
+ <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
+ <!--<category android:name="android.intent.category.LAUNCHER" />-->
<category android:name="com.android.internal.category.PLATLOGO" />
</intent-filter>
</activity>
-
- <!-- Android N lives on inside Android O... -->
-
- <!-- Long press the QS tile to get here -->
- <activity android:name=".neko.NekoLand"
- android:theme="@android:style/Theme.Material.NoActionBar"
- android:label="@string/app_name">
- <intent-filter>
- <action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" />
- <action android:name="android.intent.action.MAIN" />
- </intent-filter>
- </activity>
-
- <!-- This is where the magic happens -->
- <service
- android:name=".neko.NekoService"
- android:enabled="true"
- android:permission="android.permission.BIND_JOB_SERVICE"
- android:exported="true" >
- </service>
-
- <!-- Used to show over lock screen -->
- <activity android:name=".neko.NekoLockedActivity"
- android:excludeFromRecents="true"
- android:theme="@android:style/Theme.Material.Light.Dialog.NoActionBar"
- android:showOnLockScreen="true" />
-
- <!-- Used to enable easter egg -->
- <activity android:name=".neko.NekoActivationActivity"
- android:excludeFromRecents="true"
- android:theme="@android:style/Theme.NoDisplay"
- >
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- </activity>
-
- <!-- The quick settings tile, disabled by default -->
- <service
- android:name=".neko.NekoTile"
- android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
- android:icon="@drawable/stat_icon"
- android:enabled="false"
- android:label="@string/default_tile_name">
- <intent-filter>
- <action android:name="android.service.quicksettings.action.QS_TILE" />
- </intent-filter>
- </service>
-
- <!-- FileProvider for sending pictures -->
- <provider
- android:name="androidx.core.content.FileProvider"
- android:authorities="com.android.egg.fileprovider"
- android:grantUriPermissions="true"
- android:exported="false">
- <meta-data
- android:name="android.support.FILE_PROVIDER_PATHS"
- android:resource="@xml/filepaths" />
- </provider>
</application>
+
</manifest>
diff --git a/packages/EasterEgg/res/values/dimens.xml b/packages/EasterEgg/res/color-night/toolbar_icon_color.xml
similarity index 63%
copy from packages/EasterEgg/res/values/dimens.xml
copy to packages/EasterEgg/res/color-night/toolbar_icon_color.xml
index e9dcebd..c0a8152 100644
--- a/packages/EasterEgg/res/values/dimens.xml
+++ b/packages/EasterEgg/res/color-night/toolbar_icon_color.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-Copyright (C) 2016 The Android Open Source Project
+ Copyright (C) 2018 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -14,6 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <dimen name="neko_display_size">64dp</dimen>
-</resources>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="#FFFF3333" android:state_selected="true" />
+ <item android:color="#FFFFFFFF" />
+</selector>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/values/dimens.xml b/packages/EasterEgg/res/color/toolbar_icon_color.xml
similarity index 71%
rename from packages/EasterEgg/res/values/dimens.xml
rename to packages/EasterEgg/res/color/toolbar_icon_color.xml
index e9dcebd..d3247e4 100644
--- a/packages/EasterEgg/res/values/dimens.xml
+++ b/packages/EasterEgg/res/color/toolbar_icon_color.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-Copyright (C) 2016 The Android Open Source Project
+Copyright (C) 2018 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.
@@ -14,6 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <dimen name="neko_display_size">64dp</dimen>
-</resources>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="#FFCC0000" android:state_selected="true" />
+ <item android:color="#FF000000" />
+</selector>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/drawable/back.xml b/packages/EasterEgg/res/drawable/back.xml
deleted file mode 100644
index b55d65c..0000000
--- a/packages/EasterEgg/res/drawable/back.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path android:name="back" android:fillColor="#FF000000" android:pathData="M37.1,22c-1.1,0 -1.9,0.8 -1.9,1.9v5.6c0,1.1 0.8,1.9 1.9,1.9H39v-1.9v-5.6V22H37.1z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/belly.xml b/packages/EasterEgg/res/drawable/belly.xml
deleted file mode 100644
index 8b0e9af..0000000
--- a/packages/EasterEgg/res/drawable/belly.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path android:name="belly" android:fillColor="#FF000000" android:pathData="M20.5,25c-3.6,0 -6.5,2.9 -6.5,6.5V38h13v-6.5C27,27.9 24.1,25 20.5,25z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/body.xml b/packages/EasterEgg/res/drawable/body.xml
deleted file mode 100644
index 8608720..0000000
--- a/packages/EasterEgg/res/drawable/body.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path android:name="body" android:fillColor="#FF000000" android:pathData="M9,20h30v18h-30z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/bowtie.xml b/packages/EasterEgg/res/drawable/bowtie.xml
deleted file mode 100644
index 33fa921..0000000
--- a/packages/EasterEgg/res/drawable/bowtie.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path android:name="bowtie" android:fillColor="#FF000000" android:pathData="M29,16.8l-10,5l0,-5l10,5z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/cap.xml b/packages/EasterEgg/res/drawable/cap.xml
deleted file mode 100644
index d8b4cc5..0000000
--- a/packages/EasterEgg/res/drawable/cap.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path android:name="cap" android:fillColor="#FF000000" android:pathData="M27.2,3.8c-1,-0.2 -2.1,-0.3 -3.2,-0.3s-2.1,0.1 -3.2,0.3c0.2,1.3 1.5,2.2 3.2,2.2C25.6,6.1 26.9,5.1 27.2,3.8z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/collar.xml b/packages/EasterEgg/res/drawable/collar.xml
deleted file mode 100644
index 5e4d0fd..0000000
--- a/packages/EasterEgg/res/drawable/collar.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path android:name="collar" android:fillColor="#FF000000" android:pathData="M9,18.4h30v1.7h-30z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/face_spot.xml b/packages/EasterEgg/res/drawable/face_spot.xml
deleted file mode 100644
index a89fb4f..0000000
--- a/packages/EasterEgg/res/drawable/face_spot.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path android:name="face_spot" android:fillColor="#FF000000" android:pathData="M19.5,15.2a4.5,3.2 0,1 0,9 0a4.5,3.2 0,1 0,-9 0z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/food_bits.xml b/packages/EasterEgg/res/drawable/food_bits.xml
deleted file mode 100644
index 1b2bb6f..0000000
--- a/packages/EasterEgg/res/drawable/food_bits.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<!--
-Copyright (C) 2015 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path
- android:fillColor="#FF000000"
- android:pathData="M19.1,34l-3.5,1.3c-1,0.4,-2.2,-0.1,-2.6,-1.1l-1.2,-3c-0.4,-1,0.1,-2.2,1.1,-2.6l3.5,-1.3c1,-0.4,2.2,0.1,2.6,1.1l1.2,3 C20.6,32.4,20.1,33.6,19.1,34z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M25.2,28.1L22.9,28c-0.8,0,-1.5,-0.7,-1.4,-1.6l0.1,-2c0,-0.8,0.7,-1.5,1.6,-1.4l2.4,0.1c0.8,0,1.5,0.7,1.4,1.6l-0.1,2 C26.8,27.5,26.1,28.1,25.2,28.1z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M18.7,23.1L16.5,23c-0.5,0,-0.9,-0.4,-0.8,-0.9l0.1,-2.2c0,-0.5,0.4,-0.9,0.9,-0.8l2.2,0.1c0.5,0,0.9,0.4,0.8,0.9 l-0.1,2.2C19.6,22.8,19.2,23.1,18.7,23.1z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M32.2,35.3l-3.6,-1.8c-1,-0.5,-1.4,-1.7,-0.9,-2.7l1.6,-3.1c0.5,-1,1.7,-1.4,2.7,-0.9l3.6,1.8c1,0.5,1.4,1.7,0.9,2.7 l-1.6,3.1C34.4,35.4,33.2,35.7,32.2,35.3z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/food_chicken.xml b/packages/EasterEgg/res/drawable/food_chicken.xml
deleted file mode 100644
index 95b2fb5..0000000
--- a/packages/EasterEgg/res/drawable/food_chicken.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<!--
-Copyright (C) 2015 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path
- android:fillColor="#FF000000"
- android:pathData="M9,12v14h10V11H9z M11.7,16.3c-0.7,0,-1.3,-0.6,-1.3,-1.3s0.6,-1.3,1.3,-1.3S13,14.3,13,15S12.4,16.3,11.7,16.3z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M5.7,20.1l1.6,-3.0l-1.6,-3.0l4.4,3.0z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M19.0,6.0l-2.3,2.3l-2.7,-2.6l-2.7,2.6l-2.3,-2.3l0.0,4.0l10.0,0.0z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M9,25c0,8.3,6.7,15,15,15s15,-6.7,15,-15H9z M29.9,31.5h-11v-1h12L29.9,31.5z M31.9,29.5h-13v-1h14L31.9,29.5z M33.9,27.5 h-15v-1h16L33.9,27.5z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M27.0,38.6h2.0v6.0h-2.0z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M17.4,44.6l-2.1999998,0.0l4.4000006,-6.0l2.1999989,0.0z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/food_cookie.xml b/packages/EasterEgg/res/drawable/food_cookie.xml
deleted file mode 100644
index 74dd134..0000000
--- a/packages/EasterEgg/res/drawable/food_cookie.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <group>
- <path
- android:fillColor="#55FFFFFF"
- android:fillType="evenOdd"
- android:pathData="M5.71 18.29A8.99 8.99 0 0 0 22 13c0-3-1.46-5.65-3.71-7.29A8.99 8.99 0 0 0 2 11c0 3 1.46 5.65 3.71 7.29z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:fillType="evenOdd"
- android:pathData="M7.25 19.18A8.5 8.5 0 0 0 19.19 7.24 9 9 0 0 1 7.24 19.19z"/>
- <path
- android:fillColor="#55FFFFFF"
- android:pathData="M10.5 3a0.5 0.5 0 1 1 1 0v2.05a0.5 0.5 0 1 1-1 0V3zm3.1 0.42a0.5 0.5 0 0 1 0.93 0.39l-0.8 1.88A0.5 0.5 0 1 1 12.8 5.3l0.8-1.88zm2.7 1.57a0.5 0.5 0 1 1 0.71 0.7l-1.45 1.46a0.5 0.5 0 0 1-0.7-0.71l1.44-1.45zm1.9 2.5a0.5 0.5 0 0 1 0.38 0.92l-1.9 0.77a0.5 0.5 0 0 1-0.37-0.93l1.9-0.77zM19 10.5a0.5 0.5 0 1 1 0 1h-2.05a0.5 0.5 0 0 1 0-1H19zm-0.42 3.1a0.5 0.5 0 0 1-0.39 0.93l-1.88-0.8a0.5 0.5 0 1 1 0.39-0.92l1.88 0.8zm-1.57 2.7a0.5 0.5 0 1 1-0.7 0.71l-1.46-1.45a0.5 0.5 0 0 1 0.71-0.7l1.45 1.44zm-2.5 1.9a0.5 0.5 0 1 1-0.92 0.38l-0.77-1.9a0.5 0.5 0 0 1 0.93-0.37l0.77 1.9zM11.5 19a0.5 0.5 0 1 1-1 0v-2.05a0.5 0.5 0 0 1 1 0V19zm-3.1-0.42a0.5 0.5 0 0 1-0.93-0.39l0.8-1.88A0.5 0.5 0 0 1 9.2 16.7l-0.8 1.88zm-2.7-1.57a0.5 0.5 0 1 1-0.71-0.7l1.45-1.46a0.5 0.5 0 0 1 0.7 0.71L5.7 17.01zm-1.9-2.48a0.5 0.5 0 0 1-0.38-0.92l1.88-0.8a0.5 0.5 0 0 1 0.4 0.92l-1.9 0.8zM3 11.5a0.5 0.5 0 1 1 0-1h2.05a0.5 0.5 0 1 1 0 1H3zm0.42-3.1A0.5 0.5 0 0 1 3.8 7.46l1.88 0.8A0.5 0.5 0 1 1 5.3 9.2L3.42 8.4zm1.57-2.7a0.5 0.5 0 1 1 0.7-0.71l1.46 1.45a0.5 0.5 0 0 1-0.71 0.7L4.99 5.7zm2.5-1.9A0.5 0.5 0 0 1 8.4 3.41l0.77 1.9a0.5 0.5 0 0 1-0.93 0.37L7.48 3.8z"/>
- </group>
-</vector>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/drawable/food_dish.xml b/packages/EasterEgg/res/drawable/food_dish.xml
deleted file mode 100644
index 3fff6a9..0000000
--- a/packages/EasterEgg/res/drawable/food_dish.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2015 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path
- android:fillColor="#FF000000"
- android:pathData="M24,13.8C11.3,13.8,1,18.3,1,24c0,5.7,10.3,10.2,23,10.2S47,29.7,47,24C47,18.3,36.7,13.8,24,13.8z M33.7,26.6 c1.1,-0.6,1.8,-1.3,1.8,-2c0,-2.1,-5.2,-3.8,-11.7,-3.8s-11.7,1.7,-11.7,3.8c0,0.6,0.4,1.2,1.2,1.7c-1.7,-0.8,-2.8,-1.7,-2.8,-2.8 c0,-2.5,6,-4.5,13.4,-4.5s13.4,2,13.4,4.5C37.4,24.7,36,25.8,33.7,26.6z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/food_donut.xml b/packages/EasterEgg/res/drawable/food_donut.xml
deleted file mode 100644
index eaf831e..0000000
--- a/packages/EasterEgg/res/drawable/food_donut.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2015 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path
- android:fillColor="#FF000000"
- android:pathData="M24,4.5c-10.5,0,-19,8.5,-19,19s8.5,19,19,19s19,-8.5,19,-19S34.5,4.5,24,4.5z M35.2,15.5l1.6,-1.1 c0.3,-0.2,0.6,-0.1,0.8,0.1l0.1,0.1c0.2,0.3,0.1,0.6,-0.1,0.8l-1.6,1.1c-0.3,0.2,-0.6,0.1,-0.8,-0.1l-0.1,-0.1 C34.9,16.1,35,15.7,35.2,15.5z M32.7,10.7c0,-0.3,0.3,-0.5,0.6,-0.5l0.1,0c0.3,0,0.5,0.3,0.5,0.6l-0.2,2c0,0.3,-0.3,0.5,-0.6,0.5l-0.1,0 c-0.3,0,-0.5,-0.3,-0.5,-0.6L32.7,10.7z M31.7,15.1l1.5,-0.2c0.2,0,0.5,0.1,0.5,0.4l0,0.1c0,0.2,-0.1,0.5,-0.4,0.5l-1.5,0.2 c-0.2,0,-0.5,-0.1,-0.5,-0.4l0,-0.1C31.3,15.4,31.5,15.2,31.7,15.1z M28.8,10.6l1.6,-1.1c0.3,-0.2,0.6,-0.1,0.8,0.1l0.1,0.1 c0.2,0.3,0.1,0.6,-0.1,0.8l-1.6,1.1c-0.3,0.2,-0.6,0.1,-0.8,-0.1l-0.1,-0.1C28.4,11.1,28.5,10.8,28.8,10.6z M25.8,6 c0,-0.3,0.3,-0.5,0.6,-0.5l0.1,0c0.3,0,0.5,0.3,0.5,0.6l-0.2,2c0,0.3,-0.3,0.5,-0.6,0.5l-0.1,0c-0.3,0,-0.5,-0.3,-0.5,-0.6L25.8,6z M20.7,6.5l1.9,-0.7c0.3,-0.1,0.6,0,0.7,0.3l0,0.1c0.1,0.3,0,0.6,-0.3,0.7l-1.9,0.7c-0.3,0.1,-0.6,0,-0.7,-0.3l0,-0.1 C20.3,6.9,20.4,6.6,20.7,6.5z M19.9,10.9l1.5,-0.2c0.2,0,0.5,0.1,0.5,0.4l0,0.1c0,0.2,-0.1,0.5,-0.4,0.5l-1.5,0.2 c-0.2,0,-0.5,-0.1,-0.5,-0.4l0,-0.1C19.5,11.1,19.7,10.9,19.9,10.9z M16,10.9L16,10.9c0.2,-0.3,0.4,-0.4,0.6,-0.3l1.3,0.7 c0.2,0.1,0.3,0.4,0.2,0.6L18,12c-0.1,0.2,-0.4,0.3,-0.6,0.2l-1.3,-0.7C15.9,11.4,15.8,11.1,16,10.9z M15.8,18.5c0.2,0,0.4,0.1,0.5,0.4 l0,0.1c0,0.2,-0.1,0.4,-0.4,0.5l-1.5,0.2c-0.2,0,-0.4,-0.1,-0.5,-0.4l0,-0.1c0,-0.2,0.1,-0.4,0.4,-0.5L15.8,18.5z M14,21.8l-1.6,1.1 c-0.3,0.2,-0.6,0.1,-0.8,-0.1l-0.1,-0.1c-0.2,-0.3,-0.1,-0.6,0.1,-0.8l1.6,-1.1c0.3,-0.2,0.6,-0.1,0.8,0.1l0.1,0.1 C14.3,21.3,14.3,21.6,14,21.8z M12.4,12L12.4,12c0.3,-0.2,0.5,-0.2,0.7,-0.1l1,1.1c0.2,0.2,0.2,0.4,0,0.6L14,13.7 c-0.2,0.2,-0.4,0.2,-0.6,0l-1,-1.1C12.2,12.4,12.2,12.1,12.4,12z M8.3,24.5c0,0.3,-0.3,0.5,-0.6,0.5l-0.1,0c-0.3,0,-0.5,-0.3,-0.5,-0.6 l0.2,-2c0,-0.3,0.3,-0.5,0.6,-0.5l0.1,0c0.3,0,0.5,0.3,0.5,0.6L8.3,24.5z M8.5,16.2v-0.1c0,-0.3,0.2,-0.6,0.6,-0.6h2 c0.3,0,0.6,0.2,0.6,0.6v0.1c0,0.3,-0.2,0.6,-0.6,0.6H9C8.7,16.7,8.5,16.5,8.5,16.2z M10.3,20.7c-0.3,0.2,-0.6,0.1,-0.8,-0.1l-0.1,-0.1 c-0.2,-0.3,-0.1,-0.6,0.1,-0.8l1.6,-1.1c0.3,-0.2,0.6,-0.1,0.8,0.1l0.1,0.1c0.2,0.3,0.1,0.6,-0.1,0.8L10.3,20.7z M11.3,28.3l0,-0.1 c-0.1,-0.3,0,-0.6,0.3,-0.7l1.9,-0.7c0.3,-0.1,0.6,0,0.7,0.3l0,0.1c0.1,0.3,0,0.6,-0.3,0.7L12,28.6C11.7,28.7,11.4,28.6,11.3,28.3z M14.4,33c0,0.2,-0.2,0.4,-0.4,0.4h-1.5c-0.2,0,-0.4,-0.2,-0.4,-0.4v-0.1c0,-0.2,0.2,-0.4,0.4,-0.4H14c0.2,0,0.4,0.2,0.4,0.4V33z M17.9,35.2 l-1.6,1.1c-0.3,0.2,-0.6,0.1,-0.8,-0.1l-0.1,-0.1c-0.2,-0.3,-0.1,-0.6,0.1,-0.8l1.6,-1.1c0.3,-0.2,0.6,-0.1,0.8,0.1l0.1,0.1 C18.2,34.7,18.2,35.1,17.9,35.2z M20.7,33.8l-0.1,0.1c-0.1,0.3,-0.5,0.4,-0.8,0.2l-1.7,-1c-0.3,-0.1,-0.4,-0.5,-0.2,-0.8l0.1,-0.1 c0.1,-0.3,0.5,-0.4,0.8,-0.2l1.7,1C20.7,33.2,20.8,33.5,20.7,33.8z M17.5,23.5c0,-3.6,2.9,-6.5,6.5,-6.5s6.5,2.9,6.5,6.5 c0,3.6,-2.9,6.5,-6.5,6.5S17.5,27.1,17.5,23.5z M27.4,35.7l-1.9,0.7c-0.3,0.1,-0.6,0,-0.7,-0.3l0,-0.1c-0.1,-0.3,0,-0.6,0.3,-0.7l1.9,-0.7 c0.3,-0.1,0.6,0,0.7,0.3l0,0.1C27.9,35.3,27.7,35.6,27.4,35.7z M29.7,32.7l-1.4,0.5c-0.2,0.1,-0.5,0,-0.5,-0.3l0,-0.1 c-0.1,-0.2,0,-0.5,0.3,-0.5l1.4,-0.5c0.2,-0.1,0.5,0,0.5,0.3l0,0.1C30,32.3,29.9,32.6,29.7,32.7z M32.8,35.5l-0.1,0.1 c-0.1,0.3,-0.5,0.4,-0.8,0.2l-1.7,-1c-0.3,-0.1,-0.4,-0.5,-0.2,-0.8l0.1,-0.1c0.1,-0.3,0.5,-0.4,0.8,-0.2l1.7,1C32.8,34.9,32.9,35.2,32.8,35.5z M33.7,30.9c0,0.2,-0.2,0.4,-0.5,0.4l-0.1,0c-0.2,0,-0.4,-0.2,-0.4,-0.5l0.1,-1.5c0,-0.2,0.2,-0.4,0.5,-0.4l0.1,0c0.2,0,0.4,0.2,0.4,0.5 L33.7,30.9z M34.5,26.5l-1.3,0.9c-0.2,0.1,-0.5,0.1,-0.6,-0.1l-0.1,-0.1c-0.1,-0.2,-0.1,-0.5,0.1,-0.6l1.3,-0.9c0.2,-0.1,0.5,-0.1,0.6,0.1 l0.1,0.1C34.8,26.1,34.7,26.3,34.5,26.5z M35.6,20.6l-1.7,-1c-0.3,-0.1,-0.4,-0.5,-0.2,-0.8l0.1,-0.1c0.1,-0.3,0.5,-0.4,0.8,-0.2l1.7,1 c0.3,0.1,0.4,0.5,0.2,0.8l-0.1,0.1C36.2,20.6,35.8,20.7,35.6,20.6z M38.6,27.1l-1.6,1.1c-0.3,0.2,-0.6,0.1,-0.8,-0.1L36.1,28 c-0.2,-0.3,-0.1,-0.6,0.1,-0.8l1.6,-1.1c0.3,-0.2,0.6,-0.1,0.8,0.1l0.1,0.1C38.9,26.6,38.8,27,38.6,27.1z M39,19.4l-1.5,0.2 c-0.2,0,-0.5,-0.1,-0.5,-0.4l0,-0.1c0,-0.2,0.1,-0.5,0.4,-0.5l1.5,-0.2c0.2,0,0.5,0.1,0.5,0.4l0,0.1C39.4,19.1,39.2,19.3,39,19.4z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/food_sysuituna.xml b/packages/EasterEgg/res/drawable/food_sysuituna.xml
deleted file mode 100644
index 28cf4a2..0000000
--- a/packages/EasterEgg/res/drawable/food_sysuituna.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2015 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path
- android:fillColor="#FF000000"
- android:pathData="M46,18.4l-5.8,4.6c-3.9,-3.2,-8.9,-5.6,-14.6,-6.3l1.2,-6l-7.3,5.9C12.5,17.2,6.4,20,2,24.3l7.2,1.4L2,27 c4.3,4.2,10.4,7.1,17.3,7.6l3.1,2.5L22,34.8c7.1,0,13.5,-2.5,18.2,-6.5l5.8,4.6l-1.4,-7.2L46,18.4z M14.3,24.8l-0.6,0.6l-1.1,-1.1 l-1.1,1.1l-0.6,-0.6l1.1,-1.1l-1.1,-1.1l0.6,-0.6l1.1,1.1l1.1,-1.1l0.6,0.6l-1.1,1.1L14.3,24.8z M18.8,29.1c0.7,-0.8,1.1,-2.2,1.1,-3.8 c0,-1.6,-0.4,-3,-1.1,-3.8c1.1,0.5,1.9,2,1.9,3.8S19.9,28.5,18.8,29.1z M20.7,29.1c0.7,-0.8,1.1,-2.2,1.1,-3.8c0,-1.6,-0.4,-3,-1.1,-3.8 c1.1,0.5,1.9,2,1.9,3.8S21.8,28.5,20.7,29.1z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/foot1.xml b/packages/EasterEgg/res/drawable/foot1.xml
deleted file mode 100644
index 0d90859..0000000
--- a/packages/EasterEgg/res/drawable/foot1.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path android:name="foot1" android:fillColor="#FF000000" android:pathData="M11.5,43m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/foot2.xml b/packages/EasterEgg/res/drawable/foot2.xml
deleted file mode 100644
index 364ba0c..0000000
--- a/packages/EasterEgg/res/drawable/foot2.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path android:name="foot2" android:fillColor="#FF000000" android:pathData="M18.5,43m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/foot3.xml b/packages/EasterEgg/res/drawable/foot3.xml
deleted file mode 100644
index e3a512a..0000000
--- a/packages/EasterEgg/res/drawable/foot3.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path android:name="foot3" android:fillColor="#FF000000" android:pathData="M29.5,43m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/foot4.xml b/packages/EasterEgg/res/drawable/foot4.xml
deleted file mode 100644
index 66b78fa..0000000
--- a/packages/EasterEgg/res/drawable/foot4.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path android:name="foot4" android:fillColor="#FF000000" android:pathData="M36.5,43m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/head.xml b/packages/EasterEgg/res/drawable/head.xml
deleted file mode 100644
index df600a8..0000000
--- a/packages/EasterEgg/res/drawable/head.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path android:name="head" android:fillColor="#FF000000" android:pathData="M9,18.5c0,-8.3 6.8,-15 15,-15s15,6.7 15,15H9z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/ic_clear.xml b/packages/EasterEgg/res/drawable/ic_clear.xml
new file mode 100644
index 0000000..489dcd2
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/ic_clear.xml
@@ -0,0 +1,27 @@
+<!--
+Copyright (C) 2018 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M19,6.41l-1.41,-1.41l-5.59,5.59l-5.59,-5.59l-1.41,1.41l5.59,5.59l-5.59,5.59l1.41,1.41l5.59,-5.59l5.59,5.59l1.41,-1.41l-5.59,-5.59z"
+ android:strokeWidth="1"
+ android:fillColor="#000000"
+ android:fillType="nonZero"
+ android:strokeColor="#00000000"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/ic_close.xml b/packages/EasterEgg/res/drawable/ic_close.xml
deleted file mode 100644
index 60ea36b..0000000
--- a/packages/EasterEgg/res/drawable/ic_close.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
- Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M19.0,6.41L17.59,5.0 12.0,10.59 6.41,5.0 5.0,6.41 10.59,12.0 5.0,17.59 6.41,19.0 12.0,13.41 17.59,19.0 19.0,17.59 13.41,12.0z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/ic_dropper.xml b/packages/EasterEgg/res/drawable/ic_dropper.xml
new file mode 100644
index 0000000..2307309
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/ic_dropper.xml
@@ -0,0 +1,39 @@
+<!--
+Copyright (C) 2018 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M13.6789,5.6997L3,16.3784L3,20L4,21L7.6216,21L18.3004,10.3212L13.6789,5.6997ZM7,19L5,19L5,17L13.788,8.344L15.6561,10.212L7,19Z"
+ android:strokeWidth="1"
+ android:fillColor="#000000"
+ android:fillType="nonZero"
+ android:strokeColor="#00000000"/>
+ <path
+ android:pathData="M20.9983,2.4982L21.5018,3.0017C22.0876,3.5875 22.0876,4.5373 21.5018,5.1231L18.1231,8.5018C17.5373,9.0876 16.5875,9.0876 16.0017,8.5018L15.4982,7.9983C14.9124,7.4125 14.9124,6.4627 15.4982,5.8769L18.8769,2.4982C19.4627,1.9124 20.4125,1.9124 20.9983,2.4982Z"
+ android:strokeWidth="1"
+ android:fillColor="#000000"
+ android:fillType="evenOdd"
+ android:strokeColor="#00000000"/>
+ <path
+ android:pathData="M13.8284,3l7.0711,7.0711l-2.8284,2.8284l-7.0711,-7.0711z"
+ android:strokeWidth="1"
+ android:fillColor="#000000"
+ android:fillType="evenOdd"
+ android:strokeColor="#00000000"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/ic_hourglass.xml b/packages/EasterEgg/res/drawable/ic_hourglass.xml
new file mode 100644
index 0000000..fe4b9c4
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/ic_hourglass.xml
@@ -0,0 +1,27 @@
+<!--
+ Copyright (C) 2018 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M12.5,11L16,7.5L16,4L8,4L8,7.5L11.5,11L11.5,13L8,16.5L8,20L16,20L16,16.5L12.5,13L12.5,11ZM6,2L18,2L18,8L17.99,8L18,8.01L14,12L18,16L17.99,16.01L18,16.01L18,22L6,22L6,16.01L6.01,16.01L6,16L10,12L6,8.01L6.01,8L6,8L6,2Z"
+ android:strokeWidth="1"
+ android:fillColor="#000000"
+ android:fillType="nonZero"
+ android:strokeColor="#00000000"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/ic_share.xml b/packages/EasterEgg/res/drawable/ic_share.xml
deleted file mode 100644
index 8cebc7e..0000000
--- a/packages/EasterEgg/res/drawable/ic_share.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
- Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M18.0,16.08c-0.76,0.0 -1.4,0.3 -1.9,0.77L8.91,12.7c0.05,-0.2 0.09,-0.4 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.5,0.5 1.2,0.81 2.0,0.81 1.66,0.0 3.0,-1.34 3.0,-3.0s-1.34,-3.0 -3.0,-3.0 -3.0,1.34 -3.0,3.0c0.0,0.2 0.0,0.4 0.0,0.7L8.04,9.81C7.5,9.31 6.79,9.0 6.0,9.0c-1.66,0.0 -3.0,1.34 -3.0,3.0s1.34,3.0 3.0,3.0c0.79,0.0 1.5,-0.31 2.04,-0.81l7.12,4.16c0.0,0.21 0.0,0.43 0.0,0.65 0.0,1.61 1.31,2.92 2.92,2.92 1.61,0.0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/icon.xml b/packages/EasterEgg/res/drawable/icon.xml
index 5ce9e51..2306b7b 100644
--- a/packages/EasterEgg/res/drawable/icon.xml
+++ b/packages/EasterEgg/res/drawable/icon.xml
@@ -1,7 +1,7 @@
<!--
-Copyright (C) 2017 The Android Open Source Project
+ Copyright (C) 2018 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -13,28 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path
- android:pathData="M25.0,25.0m-20.5,0.0a20.5,20.5,0,1,1,41.0,0.0a20.5,20.5,0,1,1,-41.0,0.0"
- android:fillAlpha="0.066"
- android:fillColor="#000000"/>
- <path
- android:pathData="M24.0,24.0m-20.0,0.0a20.0,20.0,0,1,1,40.0,0.0a20.0,20.0,0,1,1,-40.0,0.0"
- android:fillColor="#283593"/>
- <path
- android:pathData="M44,24.2010101 L33.9004889,14.101499 L14.101499,33.9004889 L24.2010101,44 C29.2525804,43.9497929 34.2887564,41.9975027 38.1431296,38.1431296 C41.9975027,34.2887564 43.9497929,29.2525804 44,24.2010101 Z"
- android:fillColor="#1a237e"/>
- <path
- android:pathData="M24.0,24.0m-14.0,0.0a14.0,14.0,0,1,1,28.0,0.0a14.0,14.0,0,1,1,-28.0,0.0"
- android:fillColor="#5c6bc0"/>
- <path
- android:pathData="M37.7829445,26.469236 L29.6578482,18.3441397 L18.3441397,29.6578482 L26.469236,37.7829445 C29.1911841,37.2979273 31.7972024,36.0037754 33.9004889,33.9004889 C36.0037754,31.7972024 37.2979273,29.1911841 37.7829445,26.469236 Z"
- android:fillColor="#3f51b5"/>
- <path
- android:pathData="M24.0,24.0m-8.0,0.0a8.0,8.0,0,1,1,16.0,0.0a8.0,8.0,0,1,1,-16.0,0.0"
- android:fillColor="#FFFFFF"/>
-</vector>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/icon_bg"/>
+ <foreground android:drawable="@drawable/p"/>
+</adaptive-icon>
diff --git a/packages/EasterEgg/res/xml/filepaths.xml b/packages/EasterEgg/res/drawable/icon_bg.xml
similarity index 70%
rename from packages/EasterEgg/res/xml/filepaths.xml
rename to packages/EasterEgg/res/drawable/icon_bg.xml
index 2130025..c1553ce 100644
--- a/packages/EasterEgg/res/xml/filepaths.xml
+++ b/packages/EasterEgg/res/drawable/icon_bg.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-Copyright (C) 2017 The Android Open Source Project
+ Copyright (C) 2018 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -14,6 +14,5 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<paths>
- <external-path name="cats" path="Pictures/Cats" />
-</paths>
\ No newline at end of file
+<color xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="#C5E1A5" />
\ No newline at end of file
diff --git a/packages/EasterEgg/res/drawable/left_ear.xml b/packages/EasterEgg/res/drawable/left_ear.xml
deleted file mode 100644
index 2b98736..0000000
--- a/packages/EasterEgg/res/drawable/left_ear.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path android:name="left_ear" android:fillColor="#FF000000" android:pathData="M15.4,1l5.1000004,5.3l-6.3,2.8000002z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/left_ear_inside.xml b/packages/EasterEgg/res/drawable/left_ear_inside.xml
deleted file mode 100644
index 1d947ed..0000000
--- a/packages/EasterEgg/res/drawable/left_ear_inside.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path android:name="left_ear_inside" android:fillColor="#FF000000" android:pathData="M15.4,1l3.5,6.2l-4.7,1.9z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/left_eye.xml b/packages/EasterEgg/res/drawable/left_eye.xml
deleted file mode 100644
index 4dde1b6..0000000
--- a/packages/EasterEgg/res/drawable/left_eye.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path android:name="left_eye" android:fillColor="#FF000000" android:pathData="M20.5,11c0,1.7 -3,1.7 -3,0C17.5,9.3 20.5,9.3 20.5,11z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/leg1.xml b/packages/EasterEgg/res/drawable/leg1.xml
deleted file mode 100644
index d72c746..0000000
--- a/packages/EasterEgg/res/drawable/leg1.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path android:name="leg1" android:fillColor="#FF000000" android:pathData="M9,37h5v6h-5z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/leg2.xml b/packages/EasterEgg/res/drawable/leg2.xml
deleted file mode 100644
index a772a87..0000000
--- a/packages/EasterEgg/res/drawable/leg2.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path android:name="leg2" android:fillColor="#FF000000" android:pathData="M16,37h5v6h-5z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/leg2_shadow.xml b/packages/EasterEgg/res/drawable/leg2_shadow.xml
deleted file mode 100644
index b01bd69..0000000
--- a/packages/EasterEgg/res/drawable/leg2_shadow.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path android:name="leg2_shadow" android:fillColor="#FF000000" android:pathData="M16,37h5v3h-5z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/leg3.xml b/packages/EasterEgg/res/drawable/leg3.xml
deleted file mode 100644
index d471236..0000000
--- a/packages/EasterEgg/res/drawable/leg3.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path android:name="leg3" android:fillColor="#FF000000" android:pathData="M27,37h5v6h-5z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/leg4.xml b/packages/EasterEgg/res/drawable/leg4.xml
deleted file mode 100644
index e5868eb..0000000
--- a/packages/EasterEgg/res/drawable/leg4.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path android:name="leg4" android:fillColor="#FF000000" android:pathData="M34,37h5v6h-5z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/mouth.xml b/packages/EasterEgg/res/drawable/mouth.xml
deleted file mode 100644
index ddcf2e8..0000000
--- a/packages/EasterEgg/res/drawable/mouth.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path android:name="mouth"
- android:strokeColor="#FF000000"
- android:strokeWidth="1.2"
- android:strokeLineCap="round"
- android:pathData="M29,14.3c-0.4,0.8 -1.3,1.4 -2.3,1.4c-1.4,0 -2.7,-1.3 -2.7,-2.7
- M24,13c0,1.5 -1.2,2.7 -2.7,2.7c-1,0 -1.9,-0.5 -2.3,-1.4"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/nose.xml b/packages/EasterEgg/res/drawable/nose.xml
deleted file mode 100644
index d403cd1..0000000
--- a/packages/EasterEgg/res/drawable/nose.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path android:name="nose" android:fillColor="#FF000000" android:pathData="M25.2,13c0,1.3 -2.3,1.3 -2.3,0S25.2,11.7 25.2,13z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/octo_bg.xml b/packages/EasterEgg/res/drawable/octo_bg.xml
deleted file mode 100644
index 1e46cf4..0000000
--- a/packages/EasterEgg/res/drawable/octo_bg.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <gradient android:angle="-90"
- android:startColor="#FF205090"
- android:endColor="#FF001040"
- android:type="linear"
- />
-</shape>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/drawable/p.xml b/packages/EasterEgg/res/drawable/p.xml
new file mode 100644
index 0000000..596b782
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/p.xml
@@ -0,0 +1,33 @@
+<!--
+Copyright (C) 2018 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:pathData="M49,65L54,65C60.075,65 65,60.075 65,54C65,47.925 60.075,43 54,43C47.925,43 43,47.925 43,54L43,108"
+ android:strokeWidth="16"
+ android:fillColor="#00000000"
+ android:strokeColor="#7CB342"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M51,65L54,65C60.075,65 65,60.075 65,54C65,47.925 60.075,43 54,43C47.925,43 43,47.925 43,54L43,108"
+ android:strokeWidth="8"
+ android:fillColor="#00000000"
+ android:strokeColor="#FFFFFF"
+ android:fillType="evenOdd"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/right_ear.xml b/packages/EasterEgg/res/drawable/right_ear.xml
deleted file mode 100644
index b9fb4d1..0000000
--- a/packages/EasterEgg/res/drawable/right_ear.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path android:name="right_ear" android:fillColor="#FF000000" android:pathData="M32.6,1l-5.0999985,5.3l6.299999,2.8000002z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/right_ear_inside.xml b/packages/EasterEgg/res/drawable/right_ear_inside.xml
deleted file mode 100644
index 86b6e34..0000000
--- a/packages/EasterEgg/res/drawable/right_ear_inside.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
-
- <path android:name="right_ear_inside" android:fillColor="#FF000000" android:pathData="M33.8,9.1l-4.7,-1.9l3.5,-6.2z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/right_eye.xml b/packages/EasterEgg/res/drawable/right_eye.xml
deleted file mode 100644
index a1871a6..0000000
--- a/packages/EasterEgg/res/drawable/right_eye.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path android:name="right_eye" android:fillColor="#FF000000" android:pathData="M30.5,11c0,1.7 -3,1.7 -3,0C27.5,9.3 30.5,9.3 30.5,11z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/stat_icon.xml b/packages/EasterEgg/res/drawable/stat_icon.xml
deleted file mode 100644
index 608cb20..0000000
--- a/packages/EasterEgg/res/drawable/stat_icon.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<!--
-Copyright (C) 2015 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FF000000"
- android:pathData="M12,2C6.5,2 2,6.5 2,12c0,5.5 4.5,10 10,10s10,-4.5 10,-10C22,6.5 17.5,2 12,2zM5.5,11c0,-1.6 3,-1.6 3,0C8.5,12.7 5.5,12.7 5.5,11zM17.5,14.6c-0.6,1 -1.7,1.7 -2.9,1.7c-1.1,0 -2,-0.6 -2.6,-1.4c-0.6,0.9 -1.6,1.4 -2.7,1.4c-1.3,0 -2.3,-0.7 -2.9,-1.8c-0.2,-0.3 0,-0.7 0.3,-0.8c0.3,-0.2 0.7,0 0.8,0.3c0.3,0.7 1,1.1 1.8,1.1c0.9,0 1.6,-0.5 1.9,-1.3c-0.2,-0.2 -0.4,-0.4 -0.4,-0.7c0,-1.3 2.3,-1.3 2.3,0c0,0.3 -0.2,0.6 -0.4,0.7c0.3,0.8 1.1,1.3 1.9,1.3c0.8,0 1.5,-0.6 1.8,-1.1c0.2,-0.3 0.6,-0.4 0.9,-0.2C17.6,13.9 17.7,14.3 17.5,14.6zM15.5,11c0,-1.6 3,-1.6 3,0C18.5,12.7 15.5,12.7 15.5,11z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M5.2,1.0l4.1000004,4.2l-5.0,2.1000004z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M18.8,1.0l-4.0999994,4.2l5.000001,2.1000004z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/tail.xml b/packages/EasterEgg/res/drawable/tail.xml
deleted file mode 100644
index 0cca23c..0000000
--- a/packages/EasterEgg/res/drawable/tail.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path android:name="tail"
- android:strokeColor="#FF000000"
- android:strokeWidth="5"
- android:strokeLineCap="round"
- android:pathData="M35,35.5h5.9c2.1,0 3.8,-1.7 3.8,-3.8v-6.2"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/tail_cap.xml b/packages/EasterEgg/res/drawable/tail_cap.xml
deleted file mode 100644
index b82f6f9..0000000
--- a/packages/EasterEgg/res/drawable/tail_cap.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path android:name="tail_cap" android:fillColor="#FF000000" android:pathData="M42.2,25.5c0,-1.4 1.1,-2.5 2.5,-2.5s2.5,1.1 2.5,2.5H42.2z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/tail_shadow.xml b/packages/EasterEgg/res/drawable/tail_shadow.xml
deleted file mode 100644
index bb1ff12..0000000
--- a/packages/EasterEgg/res/drawable/tail_shadow.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path android:name="tail_shadow" android:fillColor="#FF000000" android:pathData="M40,38l0,-5l-1,0l0,5z"/>
-</vector>
diff --git a/packages/EasterEgg/res/values/dimens.xml b/packages/EasterEgg/res/drawable/toolbar_bg.xml
similarity index 65%
copy from packages/EasterEgg/res/values/dimens.xml
copy to packages/EasterEgg/res/drawable/toolbar_bg.xml
index e9dcebd..0f0e702 100644
--- a/packages/EasterEgg/res/values/dimens.xml
+++ b/packages/EasterEgg/res/drawable/toolbar_bg.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-Copyright (C) 2016 The Android Open Source Project
+ Copyright (C) 2018 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -14,6 +14,6 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <dimen name="neko_display_size">64dp</dimen>
-</resources>
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
+ <solid android:color="@color/toolbar_bg_color" />
+</shape>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/drawable/toolbar_button_bg.xml b/packages/EasterEgg/res/drawable/toolbar_button_bg.xml
new file mode 100644
index 0000000..1b6a53e
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/toolbar_button_bg.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 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.
+-->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:attr/colorControlHighlight">
+ <item android:id="@android:id/mask">
+ <shape android:shape="rectangle">
+ <solid android:color="@android:color/black" />
+ <corners android:radius="4dp" />
+ </shape>
+ </item>
+</ripple>
diff --git a/packages/EasterEgg/res/layout/activity_paint.xml b/packages/EasterEgg/res/layout/activity_paint.xml
new file mode 100644
index 0000000..a4c17af
--- /dev/null
+++ b/packages/EasterEgg/res/layout/activity_paint.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 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.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ xmlns:app="http://schemas.android.com/apk/res/com.android.egg"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="#666"
+ tools:context=".paint.PaintActivity"
+ android:id="@+id/contentView" >
+
+ <include layout="@layout/toolbar"
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="50dp"
+ android:layout_gravity="top"
+ />
+ <include layout="@layout/colors"
+ android:id="@+id/colors"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:layout_gravity="top"
+ android:visibility="gone"
+ />
+ <include layout="@layout/brushes"
+ android:id="@+id/brushes"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:layout_gravity="top"
+ android:visibility="gone"
+ />
+
+
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/layout/brushes.xml b/packages/EasterEgg/res/layout/brushes.xml
new file mode 100644
index 0000000..0c4b849
--- /dev/null
+++ b/packages/EasterEgg/res/layout/brushes.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="left"
+ android:background="@drawable/toolbar_bg"
+ android:elevation="10dp"
+ >
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/layout/cat_view.xml b/packages/EasterEgg/res/layout/cat_view.xml
deleted file mode 100644
index 85b494d..0000000
--- a/packages/EasterEgg/res/layout/cat_view.xml
+++ /dev/null
@@ -1,82 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2016 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.
- -->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="?android:attr/listPreferredItemHeightSmall"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:background="?android:attr/selectableItemBackgroundBorderless"
- android:gravity="center_horizontal"
- android:clipToPadding="false">
-
- <FrameLayout
- android:layout_width="96dp"
- android:layout_height="wrap_content">
-
- <ImageView
- android:id="@android:id/icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:padding="10dp"
- android:layout_gravity="center"
- android:scaleType="fitCenter" />
-
- <LinearLayout
- android:id="@+id/contextGroup"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:visibility="invisible"
- android:layout_gravity="bottom">
-
- <ImageView
- android:id="@android:id/shareText"
- android:layout_width="40dp"
- android:layout_height="40dp"
- android:padding="8dp"
- android:src="@drawable/ic_share"
- android:scaleType="fitCenter"
- android:background="#40000000"/>
-
- <Space
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1" />
-
- <ImageView
- android:id="@android:id/closeButton"
- android:layout_width="40dp"
- android:layout_height="40dp"
- android:padding="4dp"
- android:src="@drawable/ic_close"
- android:scaleType="fitCenter"
- android:background="#40000000"/>
-
- </LinearLayout>
-
- </FrameLayout>
-
- <TextView
- android:id="@android:id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceListItem"
- android:gravity="center"/>
-</LinearLayout>
-
diff --git a/packages/EasterEgg/res/layout/colors.xml b/packages/EasterEgg/res/layout/colors.xml
new file mode 100644
index 0000000..b90f4d7
--- /dev/null
+++ b/packages/EasterEgg/res/layout/colors.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="left"
+ android:background="@drawable/toolbar_bg"
+ android:elevation="10dp"
+ >
+
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/layout/edit_text.xml b/packages/EasterEgg/res/layout/edit_text.xml
deleted file mode 100644
index 9f7ac802..0000000
--- a/packages/EasterEgg/res/layout/edit_text.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2016 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.
- -->
-
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingStart="20dp"
- android:paddingEnd="20dp">
-
- <EditText
- android:id="@android:id/edit"
- android:maxLines="1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
-
-</FrameLayout>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/layout/food_layout.xml b/packages/EasterEgg/res/layout/food_layout.xml
deleted file mode 100644
index d0ca0c8..0000000
--- a/packages/EasterEgg/res/layout/food_layout.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2016 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.
- -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="?android:attr/selectableItemBackgroundBorderless"
- android:paddingLeft="4dp" android:paddingRight="4dp"
- android:paddingBottom="6dp" android:paddingTop="6dp">
- <ImageView
- android:layout_width="64dp"
- android:layout_height="64dp"
- android:id="@+id/icon"
- android:tint="?android:attr/colorControlNormal"/>
- <TextView android:layout_width="64dp" android:layout_height="wrap_content"
- android:gravity="top|center_horizontal"
- android:id="@+id/text" />
-</LinearLayout>
diff --git a/packages/EasterEgg/res/layout/neko_activity.xml b/packages/EasterEgg/res/layout/neko_activity.xml
deleted file mode 100644
index c258137..0000000
--- a/packages/EasterEgg/res/layout/neko_activity.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2016 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.
--->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <androidx.recyclerview.widget.RecyclerView
- android:id="@+id/holder"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"/>
-</FrameLayout>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/layout/toolbar.xml b/packages/EasterEgg/res/layout/toolbar.xml
new file mode 100644
index 0000000..9a5a9c5
--- /dev/null
+++ b/packages/EasterEgg/res/layout/toolbar.xml
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 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.
+-->
+<com.android.egg.paint.CutoutAvoidingToolbar
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="50dp"
+ android:orientation="horizontal"
+ android:gravity="left"
+ android:background="@drawable/toolbar_bg"
+ android:elevation="20dp"
+ >
+
+ <Space
+ android:tag="cutoutLeft"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ />
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:tag="beforeCutout"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ android:layout_weight="1"
+ tools:ignore="UselessParent">
+
+ <ImageButton
+ android:id="@+id/btnBrush"
+ android:layout_width="48dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:tint="@color/toolbar_icon_color"
+ android:background="@drawable/toolbar_button_bg"
+ />
+
+ <ImageButton
+ android:id="@+id/btnColor"
+ android:layout_width="48dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:tint="@color/toolbar_icon_color"
+ android:background="@drawable/toolbar_button_bg"
+ />
+
+ <ImageButton
+ android:id="@+id/btnSample"
+ android:layout_width="48dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="@drawable/toolbar_button_bg"
+ android:tint="@color/toolbar_icon_color"
+ android:src="@drawable/ic_dropper" />
+
+ </LinearLayout>
+
+ <Space
+ android:tag="cutoutCenter"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ />
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:tag="afterCutout"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ android:layout_weight="1"
+ tools:ignore="UselessParent">
+
+ <ImageButton
+ android:id="@+id/btnZen"
+ android:layout_width="48dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="@drawable/toolbar_button_bg"
+ android:tint="@color/toolbar_icon_color"
+ android:src="@drawable/ic_hourglass" />
+
+ <ImageButton
+ android:id="@+id/btnClear"
+ android:layout_width="48dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="@drawable/toolbar_button_bg"
+ android:tint="@color/toolbar_icon_color"
+ android:src="@drawable/ic_clear" />
+
+ </LinearLayout>
+
+ <Space
+ android:tag="cutoutRight"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ />
+
+</com.android.egg.paint.CutoutAvoidingToolbar>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/values/dimens.xml b/packages/EasterEgg/res/values-night/colors.xml
similarity index 65%
copy from packages/EasterEgg/res/values/dimens.xml
copy to packages/EasterEgg/res/values-night/colors.xml
index e9dcebd..7c188f7 100644
--- a/packages/EasterEgg/res/values/dimens.xml
+++ b/packages/EasterEgg/res/values-night/colors.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-Copyright (C) 2016 The Android Open Source Project
+ Copyright (C) 2018 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -14,6 +14,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <dimen name="neko_display_size">64dp</dimen>
-</resources>
+<resources>
+ <color name="toolbar_bg_color">#FF333333</color>
+ <color name="paper_color">#FF000000</color>
+ <color name="paint_color">#FFFFFFFF</color>
+</resources>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/values-night/styles.xml b/packages/EasterEgg/res/values-night/styles.xml
new file mode 100644
index 0000000..4edf692
--- /dev/null
+++ b/packages/EasterEgg/res/values-night/styles.xml
@@ -0,0 +1,21 @@
+<!--
+ Copyright (C) 2018 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.
+-->
+<resources>
+ <style name="AppTheme" parent="@android:style/Theme.DeviceDefault.NoActionBar.Fullscreen">
+ <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
+ <item name="android:windowLightNavigationBar">false</item>
+ </style>
+</resources>
diff --git a/packages/EasterEgg/res/xml/filepaths.xml b/packages/EasterEgg/res/values/attrs_toolbar_view.xml
similarity index 68%
copy from packages/EasterEgg/res/xml/filepaths.xml
copy to packages/EasterEgg/res/values/attrs_toolbar_view.xml
index 2130025..ed1360f 100644
--- a/packages/EasterEgg/res/xml/filepaths.xml
+++ b/packages/EasterEgg/res/values/attrs_toolbar_view.xml
@@ -1,8 +1,7 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
-Copyright (C) 2017 The Android Open Source Project
+ Copyright (C) 2018 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -14,6 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<paths>
- <external-path name="cats" path="Pictures/Cats" />
-</paths>
\ No newline at end of file
+<resources>
+ <declare-styleable name="ToolbarView">
+ </declare-styleable>
+</resources>
diff --git a/packages/EasterEgg/res/values/dimens.xml b/packages/EasterEgg/res/values/colors.xml
similarity index 66%
copy from packages/EasterEgg/res/values/dimens.xml
copy to packages/EasterEgg/res/values/colors.xml
index e9dcebd..1a5388b 100644
--- a/packages/EasterEgg/res/values/dimens.xml
+++ b/packages/EasterEgg/res/values/colors.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-Copyright (C) 2016 The Android Open Source Project
+ Copyright (C) 2018 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -14,6 +14,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <dimen name="neko_display_size">64dp</dimen>
-</resources>
+<resources>
+ <color name="toolbar_bg_color">#FFDDDDDD</color>
+ <color name="paper_color">#FFFFFFFF</color>
+ <color name="paint_color">#FF000000</color>
+</resources>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/values/strings.xml b/packages/EasterEgg/res/values/strings.xml
index 61e3834..32dbc97 100644
--- a/packages/EasterEgg/res/values/strings.xml
+++ b/packages/EasterEgg/res/values/strings.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-Copyright (C) 2016 The Android Open Source Project
+Copyright (C) 2018 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.
@@ -15,40 +15,5 @@
limitations under the License.
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <string name="app_name" translatable="false">Android Easter Egg</string>
- <string name="notification_name" translatable="false">Android Neko</string>
- <string name="notification_channel_name" translatable="false">New cats</string>
- <string name="default_tile_name" translatable="false">\????</string>
- <string name="notification_title" translatable="false">A cat is here.</string>
- <string name="default_cat_name" translatable="false">Cat #%s</string>
- <string name="directory_name" translatable="false">Cats</string>
- <string name="confirm_delete" translatable="false">Forget %s?</string>
- <string-array name="food_names" translatable="false">
- <item>Empty dish</item>
- <item>Bits</item>
- <item>Fish</item>
- <item>Chicken</item>
- <item>Treat</item>
- </string-array>
- <array name="food_icons">
- <item>@drawable/food_dish</item>
- <item>@drawable/food_bits</item>
- <item>@drawable/food_sysuituna</item>
- <item>@drawable/food_chicken</item>
- <item>@drawable/food_cookie</item>
- </array>
- <integer-array name="food_intervals">
- <item>0</item>
- <item>15</item>
- <item>30</item>
- <item>60</item>
- <item>120</item>
- </integer-array>
- <integer-array name="food_new_cat_prob">
- <item>0</item>
- <item>5</item>
- <item>35</item>
- <item>65</item>
- <item>90</item>
- </integer-array>
+ <string name="app_name" translatable="false">PAINT.APK</string>
</resources>
diff --git a/packages/EasterEgg/res/values/styles.xml b/packages/EasterEgg/res/values/styles.xml
new file mode 100644
index 0000000..44e2ce5
--- /dev/null
+++ b/packages/EasterEgg/res/values/styles.xml
@@ -0,0 +1,23 @@
+<!--
+ Copyright (C) 2018 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.
+-->
+<resources>
+
+ <style name="AppTheme" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar.Fullscreen">
+ <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
+ <item name="android:windowLightNavigationBar">true</item>
+ </style>
+
+</resources>
diff --git a/packages/EasterEgg/src/com/android/egg/neko/Cat.java b/packages/EasterEgg/src/com/android/egg/neko/Cat.java
deleted file mode 100644
index dd1bd07..0000000
--- a/packages/EasterEgg/src/com/android/egg/neko/Cat.java
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Copyright (C) 2016 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.egg.neko;
-
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.graphics.*;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
-import android.os.Bundle;
-
-import java.io.ByteArrayOutputStream;
-import java.util.Random;
-import java.util.concurrent.ThreadLocalRandom;
-
-import com.android.egg.R;
-import com.android.internal.logging.MetricsLogger;
-
-import static com.android.egg.neko.NekoLand.CHAN_ID;
-
-public class Cat extends Drawable {
- public static final long[] PURR = {0, 40, 20, 40, 20, 40, 20, 40, 20, 40, 20, 40};
-
- private Random mNotSoRandom;
- private Bitmap mBitmap;
- private long mSeed;
- private String mName;
- private int mBodyColor;
- private int mFootType;
- private boolean mBowTie;
-
- private synchronized Random notSoRandom(long seed) {
- if (mNotSoRandom == null) {
- mNotSoRandom = new Random();
- mNotSoRandom.setSeed(seed);
- }
- return mNotSoRandom;
- }
-
- public static final float frandrange(Random r, float a, float b) {
- return (b-a)*r.nextFloat() + a;
- }
-
- public static final Object choose(Random r, Object...l) {
- return l[r.nextInt(l.length)];
- }
-
- public static final int chooseP(Random r, int[] a) {
- int pct = r.nextInt(1000);
- final int stop = a.length-2;
- int i=0;
- while (i<stop) {
- pct -= a[i];
- if (pct < 0) break;
- i+=2;
- }
- return a[i+1];
- }
-
- public static final int getColorIndex(int q, int[] a) {
- for(int i = 1; i < a.length; i+=2) {
- if (a[i] == q) {
- return i/2;
- }
- }
- return -1;
- }
-
- public static final int[] P_BODY_COLORS = {
- 180, 0xFF212121, // black
- 180, 0xFFFFFFFF, // white
- 140, 0xFF616161, // gray
- 140, 0xFF795548, // brown
- 100, 0xFF90A4AE, // steel
- 100, 0xFFFFF9C4, // buff
- 100, 0xFFFF8F00, // orange
- 5, 0xFF29B6F6, // blue..?
- 5, 0xFFFFCDD2, // pink!?
- 5, 0xFFCE93D8, // purple?!?!?
- 4, 0xFF43A047, // yeah, why not green
- 1, 0, // ?!?!?!
- };
-
- public static final int[] P_COLLAR_COLORS = {
- 250, 0xFFFFFFFF,
- 250, 0xFF000000,
- 250, 0xFFF44336,
- 50, 0xFF1976D2,
- 50, 0xFFFDD835,
- 50, 0xFFFB8C00,
- 50, 0xFFF48FB1,
- 50, 0xFF4CAF50,
- };
-
- public static final int[] P_BELLY_COLORS = {
- 750, 0,
- 250, 0xFFFFFFFF,
- };
-
- public static final int[] P_DARK_SPOT_COLORS = {
- 700, 0,
- 250, 0xFF212121,
- 50, 0xFF6D4C41,
- };
-
- public static final int[] P_LIGHT_SPOT_COLORS = {
- 700, 0,
- 300, 0xFFFFFFFF,
- };
-
- private CatParts D;
-
- public static void tint(int color, Drawable ... ds) {
- for (Drawable d : ds) {
- if (d != null) {
- d.mutate().setTint(color);
- }
- }
- }
-
- public static boolean isDark(int color) {
- final int r = (color & 0xFF0000) >> 16;
- final int g = (color & 0x00FF00) >> 8;
- final int b = color & 0x0000FF;
- return (r + g + b) < 0x80;
- }
-
- public Cat(Context context, long seed) {
- D = new CatParts(context);
- mSeed = seed;
-
- setName(context.getString(R.string.default_cat_name,
- String.valueOf(mSeed % 1000)));
-
- final Random nsr = notSoRandom(seed);
-
- // body color
- mBodyColor = chooseP(nsr, P_BODY_COLORS);
- if (mBodyColor == 0) mBodyColor = Color.HSVToColor(new float[] {
- nsr.nextFloat()*360f, frandrange(nsr,0.5f,1f), frandrange(nsr,0.5f, 1f)});
-
- tint(mBodyColor, D.body, D.head, D.leg1, D.leg2, D.leg3, D.leg4, D.tail,
- D.leftEar, D.rightEar, D.foot1, D.foot2, D.foot3, D.foot4, D.tailCap);
- tint(0x20000000, D.leg2Shadow, D.tailShadow);
- if (isDark(mBodyColor)) {
- tint(0xFFFFFFFF, D.leftEye, D.rightEye, D.mouth, D.nose);
- }
- tint(isDark(mBodyColor) ? 0xFFEF9A9A : 0x20D50000, D.leftEarInside, D.rightEarInside);
-
- tint(chooseP(nsr, P_BELLY_COLORS), D.belly);
- tint(chooseP(nsr, P_BELLY_COLORS), D.back);
- final int faceColor = chooseP(nsr, P_BELLY_COLORS);
- tint(faceColor, D.faceSpot);
- if (!isDark(faceColor)) {
- tint(0xFF000000, D.mouth, D.nose);
- }
-
- mFootType = 0;
- if (nsr.nextFloat() < 0.25f) {
- mFootType = 4;
- tint(0xFFFFFFFF, D.foot1, D.foot2, D.foot3, D.foot4);
- } else {
- if (nsr.nextFloat() < 0.25f) {
- mFootType = 2;
- tint(0xFFFFFFFF, D.foot1, D.foot3);
- } else if (nsr.nextFloat() < 0.25f) {
- mFootType = 3; // maybe -2 would be better? meh.
- tint(0xFFFFFFFF, D.foot2, D.foot4);
- } else if (nsr.nextFloat() < 0.1f) {
- mFootType = 1;
- tint(0xFFFFFFFF, (Drawable) choose(nsr, D.foot1, D.foot2, D.foot3, D.foot4));
- }
- }
-
- tint(nsr.nextFloat() < 0.333f ? 0xFFFFFFFF : mBodyColor, D.tailCap);
-
- final int capColor = chooseP(nsr, isDark(mBodyColor) ? P_LIGHT_SPOT_COLORS : P_DARK_SPOT_COLORS);
- tint(capColor, D.cap);
- //tint(chooseP(nsr, isDark(bodyColor) ? P_LIGHT_SPOT_COLORS : P_DARK_SPOT_COLORS), D.nose);
-
- final int collarColor = chooseP(nsr, P_COLLAR_COLORS);
- tint(collarColor, D.collar);
- mBowTie = nsr.nextFloat() < 0.1f;
- tint(mBowTie ? collarColor : 0, D.bowtie);
- }
-
- public static Cat create(Context context) {
- return new Cat(context, Math.abs(ThreadLocalRandom.current().nextInt()));
- }
-
- public Notification.Builder buildNotification(Context context) {
- final Bundle extras = new Bundle();
- extras.putString("android.substName", context.getString(R.string.notification_name));
- final Intent intent = new Intent(Intent.ACTION_MAIN)
- .setClass(context, NekoLand.class)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- return new Notification.Builder(context)
- .setSmallIcon(Icon.createWithResource(context, R.drawable.stat_icon))
- .setLargeIcon(createNotificationLargeIcon(context))
- .setColor(getBodyColor())
- .setPriority(Notification.PRIORITY_LOW)
- .setContentTitle(context.getString(R.string.notification_title))
- .setShowWhen(true)
- .setCategory(Notification.CATEGORY_STATUS)
- .setContentText(getName())
- .setContentIntent(PendingIntent.getActivity(context, 0, intent, 0))
- .setAutoCancel(true)
- .setChannel(CHAN_ID)
- .setVibrate(PURR)
- .addExtras(extras);
- }
-
- public long getSeed() {
- return mSeed;
- }
-
- @Override
- public void draw(Canvas canvas) {
- final int w = Math.min(canvas.getWidth(), canvas.getHeight());
- final int h = w;
-
- if (mBitmap == null || mBitmap.getWidth() != w || mBitmap.getHeight() != h) {
- mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
- final Canvas bitCanvas = new Canvas(mBitmap);
- slowDraw(bitCanvas, 0, 0, w, h);
- }
- canvas.drawBitmap(mBitmap, 0, 0, null);
- }
-
- private void slowDraw(Canvas canvas, int x, int y, int w, int h) {
- for (int i = 0; i < D.drawingOrder.length; i++) {
- final Drawable d = D.drawingOrder[i];
- if (d != null) {
- d.setBounds(x, y, x+w, y+h);
- d.draw(canvas);
- }
- }
-
- }
-
- public Bitmap createBitmap(int w, int h) {
- if (mBitmap != null && mBitmap.getWidth() == w && mBitmap.getHeight() == h) {
- return mBitmap.copy(mBitmap.getConfig(), true);
- }
- Bitmap result = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
- slowDraw(new Canvas(result), 0, 0, w, h);
- return result;
- }
-
- public static Icon recompressIcon(Icon bitmapIcon) {
- if (bitmapIcon.getType() != Icon.TYPE_BITMAP) return bitmapIcon;
- final Bitmap bits = bitmapIcon.getBitmap();
- final ByteArrayOutputStream ostream = new ByteArrayOutputStream(
- bits.getWidth() * bits.getHeight() * 2); // guess 50% compression
- final boolean ok = bits.compress(Bitmap.CompressFormat.PNG, 100, ostream);
- if (!ok) return null;
- return Icon.createWithData(ostream.toByteArray(), 0, ostream.size());
- }
-
- public Icon createNotificationLargeIcon(Context context) {
- final Resources res = context.getResources();
- final int w = 2*res.getDimensionPixelSize(android.R.dimen.notification_large_icon_width);
- final int h = 2*res.getDimensionPixelSize(android.R.dimen.notification_large_icon_height);
- return recompressIcon(createIcon(context, w, h));
- }
-
- public Icon createIcon(Context context, int w, int h) {
- Bitmap result = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
- final Canvas canvas = new Canvas(result);
- final Paint pt = new Paint();
- float[] hsv = new float[3];
- Color.colorToHSV(mBodyColor, hsv);
- hsv[2] = (hsv[2]>0.5f)
- ? (hsv[2] - 0.25f)
- : (hsv[2] + 0.25f);
- pt.setColor(Color.HSVToColor(hsv));
- float r = w/2;
- canvas.drawCircle(r, r, r, pt);
- int m = w/10;
-
- slowDraw(canvas, m, m, w-m-m, h-m-m);
-
- return Icon.createWithBitmap(result);
- }
-
- @Override
- public void setAlpha(int i) {
-
- }
-
- @Override
- public void setColorFilter(ColorFilter colorFilter) {
-
- }
-
- @Override
- public int getOpacity() {
- return PixelFormat.TRANSLUCENT;
- }
-
- public String getName() {
- return mName;
- }
-
- public void setName(String name) {
- this.mName = name;
- }
-
- public int getBodyColor() {
- return mBodyColor;
- }
-
- public void logAdd(Context context) {
- logCatAction(context, "egg_neko_add");
- }
-
- public void logRename(Context context) {
- logCatAction(context, "egg_neko_rename");
- }
-
- public void logRemove(Context context) {
- logCatAction(context, "egg_neko_remove");
- }
-
- public void logShare(Context context) {
- logCatAction(context, "egg_neko_share");
- }
-
- private void logCatAction(Context context, String prefix) {
- MetricsLogger.count(context, prefix, 1);
- MetricsLogger.histogram(context, prefix +"_color",
- getColorIndex(mBodyColor, P_BODY_COLORS));
- MetricsLogger.histogram(context, prefix + "_bowtie", mBowTie ? 1 : 0);
- MetricsLogger.histogram(context, prefix + "_feet", mFootType);
- }
-
- public static class CatParts {
- public Drawable leftEar;
- public Drawable rightEar;
- public Drawable rightEarInside;
- public Drawable leftEarInside;
- public Drawable head;
- public Drawable faceSpot;
- public Drawable cap;
- public Drawable mouth;
- public Drawable body;
- public Drawable foot1;
- public Drawable leg1;
- public Drawable foot2;
- public Drawable leg2;
- public Drawable foot3;
- public Drawable leg3;
- public Drawable foot4;
- public Drawable leg4;
- public Drawable tail;
- public Drawable leg2Shadow;
- public Drawable tailShadow;
- public Drawable tailCap;
- public Drawable belly;
- public Drawable back;
- public Drawable rightEye;
- public Drawable leftEye;
- public Drawable nose;
- public Drawable bowtie;
- public Drawable collar;
- public Drawable[] drawingOrder;
-
- public CatParts(Context context) {
- body = context.getDrawable(R.drawable.body);
- head = context.getDrawable(R.drawable.head);
- leg1 = context.getDrawable(R.drawable.leg1);
- leg2 = context.getDrawable(R.drawable.leg2);
- leg3 = context.getDrawable(R.drawable.leg3);
- leg4 = context.getDrawable(R.drawable.leg4);
- tail = context.getDrawable(R.drawable.tail);
- leftEar = context.getDrawable(R.drawable.left_ear);
- rightEar = context.getDrawable(R.drawable.right_ear);
- rightEarInside = context.getDrawable(R.drawable.right_ear_inside);
- leftEarInside = context.getDrawable(R.drawable.left_ear_inside);
- faceSpot = context.getDrawable(R.drawable.face_spot);
- cap = context.getDrawable(R.drawable.cap);
- mouth = context.getDrawable(R.drawable.mouth);
- foot4 = context.getDrawable(R.drawable.foot4);
- foot3 = context.getDrawable(R.drawable.foot3);
- foot1 = context.getDrawable(R.drawable.foot1);
- foot2 = context.getDrawable(R.drawable.foot2);
- leg2Shadow = context.getDrawable(R.drawable.leg2_shadow);
- tailShadow = context.getDrawable(R.drawable.tail_shadow);
- tailCap = context.getDrawable(R.drawable.tail_cap);
- belly = context.getDrawable(R.drawable.belly);
- back = context.getDrawable(R.drawable.back);
- rightEye = context.getDrawable(R.drawable.right_eye);
- leftEye = context.getDrawable(R.drawable.left_eye);
- nose = context.getDrawable(R.drawable.nose);
- collar = context.getDrawable(R.drawable.collar);
- bowtie = context.getDrawable(R.drawable.bowtie);
- drawingOrder = getDrawingOrder();
- }
- private Drawable[] getDrawingOrder() {
- return new Drawable[] {
- collar,
- leftEar, leftEarInside, rightEar, rightEarInside,
- head,
- faceSpot,
- cap,
- leftEye, rightEye,
- nose, mouth,
- tail, tailCap, tailShadow,
- foot1, leg1,
- foot2, leg2,
- foot3, leg3,
- foot4, leg4,
- leg2Shadow,
- body, belly,
- bowtie
- };
- }
- }
-}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/Food.java b/packages/EasterEgg/src/com/android/egg/neko/Food.java
deleted file mode 100644
index 5c0f12e..0000000
--- a/packages/EasterEgg/src/com/android/egg/neko/Food.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2016 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.egg.neko;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
-
-import com.android.egg.R;
-
-public class Food {
- private final int mType;
-
- private static int[] sIcons;
- private static String[] sNames;
-
- public Food(int type) {
- mType = type;
- }
-
- public Icon getIcon(Context context) {
- if (sIcons == null) {
- TypedArray icons = context.getResources().obtainTypedArray(R.array.food_icons);
- sIcons = new int[icons.length()];
- for (int i = 0; i < sIcons.length; i++) {
- sIcons[i] = icons.getResourceId(i, 0);
- }
- icons.recycle();
- }
- return Icon.createWithResource(context, sIcons[mType]);
- }
-
- public String getName(Context context) {
- if (sNames == null) {
- sNames = context.getResources().getStringArray(R.array.food_names);
- }
- return sNames[mType];
- }
-
- public long getInterval(Context context) {
- return context.getResources().getIntArray(R.array.food_intervals)[mType];
- }
-
- public int getType() {
- return mType;
- }
-}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java b/packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java
deleted file mode 100644
index c0b725c..0000000
--- a/packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2016 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.egg.neko;
-
-import android.app.Activity;
-import android.content.ComponentName;
-import android.content.pm.PackageManager;
-import android.util.Log;
-import android.widget.Toast;
-
-import com.android.internal.logging.MetricsLogger;
-
-public class NekoActivationActivity extends Activity {
- private void toastUp(String s) {
- Toast toast = Toast.makeText(this, s, Toast.LENGTH_SHORT);
- toast.getView().setBackgroundDrawable(null);
- toast.show();
- }
-
- @Override
- public void onStart() {
- super.onStart();
-
- final PackageManager pm = getPackageManager();
- final ComponentName cn = new ComponentName(this, NekoTile.class);
- if (pm.getComponentEnabledSetting(cn) == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
- if (NekoLand.DEBUG) {
- Log.v("Neko", "Disabling tile.");
- }
- pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
- PackageManager.DONT_KILL_APP);
- MetricsLogger.histogram(this, "egg_neko_enable", 0);
- toastUp("\uD83D\uDEAB");
- } else {
- if (NekoLand.DEBUG) {
- Log.v("Neko", "Enabling tile.");
- }
- pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
- PackageManager.DONT_KILL_APP);
- MetricsLogger.histogram(this, "egg_neko_enable", 1);
- toastUp("\uD83D\uDC31");
- }
- finish();
- }
-}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoDialog.java b/packages/EasterEgg/src/com/android/egg/neko/NekoDialog.java
deleted file mode 100644
index ee89041..0000000
--- a/packages/EasterEgg/src/com/android/egg/neko/NekoDialog.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2016 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.egg.neko;
-
-import androidx.annotation.NonNull;
-import android.app.Dialog;
-import android.content.Context;
-import androidx.recyclerview.widget.GridLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.egg.R;
-import com.android.internal.logging.MetricsLogger;
-
-import java.util.ArrayList;
-
-public class NekoDialog extends Dialog {
-
- private final Adapter mAdapter;
-
- public NekoDialog(@NonNull Context context) {
- super(context, android.R.style.Theme_Material_Dialog_NoActionBar);
- RecyclerView view = new RecyclerView(getContext());
- mAdapter = new Adapter(getContext());
- view.setLayoutManager(new GridLayoutManager(getContext(), 2));
- view.setAdapter(mAdapter);
- final float dp = context.getResources().getDisplayMetrics().density;
- final int pad = (int)(16*dp);
- view.setPadding(pad, pad, pad, pad);
- setContentView(view);
- }
-
- private void onFoodSelected(Food food) {
- PrefState prefs = new PrefState(getContext());
- int currentState = prefs.getFoodState();
- if (currentState == 0 && food.getType() != 0) {
- NekoService.registerJob(getContext(), food.getInterval(getContext()));
- }
- MetricsLogger.histogram(getContext(), "egg_neko_offered_food", food.getType());
- prefs.setFoodState(food.getType());
- dismiss();
- }
-
- private class Adapter extends RecyclerView.Adapter<Holder> {
-
- private final Context mContext;
- private final ArrayList<Food> mFoods = new ArrayList<>();
-
- public Adapter(Context context) {
- mContext = context;
- int[] foods = context.getResources().getIntArray(R.array.food_names);
- // skip food 0, you can't choose it
- for (int i=1; i<foods.length; i++) {
- mFoods.add(new Food(i));
- }
- }
-
- @Override
- public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
- return new Holder(LayoutInflater.from(parent.getContext())
- .inflate(R.layout.food_layout, parent, false));
- }
-
- @Override
- public void onBindViewHolder(final Holder holder, int position) {
- final Food food = mFoods.get(position);
- ((ImageView) holder.itemView.findViewById(R.id.icon))
- .setImageIcon(food.getIcon(mContext));
- ((TextView) holder.itemView.findViewById(R.id.text))
- .setText(food.getName(mContext));
- holder.itemView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- onFoodSelected(mFoods.get(holder.getAdapterPosition()));
- }
- });
- }
-
- @Override
- public int getItemCount() {
- return mFoods.size();
- }
- }
-
- public static class Holder extends RecyclerView.ViewHolder {
-
- public Holder(View itemView) {
- super(itemView);
- }
- }
-}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoLand.java b/packages/EasterEgg/src/com/android/egg/neko/NekoLand.java
deleted file mode 100644
index ceb2170..0000000
--- a/packages/EasterEgg/src/com/android/egg/neko/NekoLand.java
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * Copyright (C) 2016 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.egg.neko;
-
-import android.Manifest;
-import android.app.ActionBar;
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.graphics.drawable.Drawable;
-import android.media.MediaScannerConnection;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Environment;
-import android.provider.MediaStore.Images;
-import androidx.core.content.FileProvider;
-import androidx.recyclerview.widget.GridLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-import android.util.Log;
-import android.view.ContextThemeWrapper;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnLongClickListener;
-import android.view.ViewGroup;
-import android.widget.EditText;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.egg.R;
-import com.android.egg.neko.PrefState.PrefsListener;
-import com.android.internal.logging.MetricsLogger;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-public class NekoLand extends Activity implements PrefsListener {
- public static String CHAN_ID = "EGG";
-
- public static boolean DEBUG = false;
- public static boolean DEBUG_NOTIFICATIONS = false;
-
- private static final int EXPORT_BITMAP_SIZE = 600;
-
- private static final int STORAGE_PERM_REQUEST = 123;
-
- private static boolean CAT_GEN = false;
- private PrefState mPrefs;
- private CatAdapter mAdapter;
- private Cat mPendingShareCat;
-
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.neko_activity);
- final ActionBar actionBar = getActionBar();
- if (actionBar != null) {
- actionBar.setLogo(Cat.create(this));
- actionBar.setDisplayUseLogoEnabled(false);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
- mPrefs = new PrefState(this);
- mPrefs.setListener(this);
- final RecyclerView recyclerView = findViewById(R.id.holder);
- mAdapter = new CatAdapter();
- recyclerView.setAdapter(mAdapter);
- recyclerView.setLayoutManager(new GridLayoutManager(this, 3));
- int numCats = updateCats();
- MetricsLogger.histogram(this, "egg_neko_visit_gallery", numCats);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- mPrefs.setListener(null);
- }
-
- private int updateCats() {
- Cat[] cats;
- if (CAT_GEN) {
- cats = new Cat[50];
- for (int i = 0; i < cats.length; i++) {
- cats[i] = Cat.create(this);
- }
- } else {
- final float[] hsv = new float[3];
- List<Cat> list = mPrefs.getCats();
- Collections.sort(list, new Comparator<Cat>() {
- @Override
- public int compare(Cat cat, Cat cat2) {
- Color.colorToHSV(cat.getBodyColor(), hsv);
- float bodyH1 = hsv[0];
- Color.colorToHSV(cat2.getBodyColor(), hsv);
- float bodyH2 = hsv[0];
- return Float.compare(bodyH1, bodyH2);
- }
- });
- cats = list.toArray(new Cat[0]);
- }
- mAdapter.setCats(cats);
- return cats.length;
- }
-
- private void onCatClick(Cat cat) {
- if (CAT_GEN) {
- mPrefs.addCat(cat);
- new AlertDialog.Builder(NekoLand.this)
- .setTitle("Cat added")
- .setPositiveButton(android.R.string.ok, null)
- .show();
- } else {
- showNameDialog(cat);
- }
-// noman.notify(1, cat.buildNotification(NekoLand.this).build());
- }
-
- private void onCatRemove(Cat cat) {
- cat.logRemove(this);
- mPrefs.removeCat(cat);
- }
-
- private void showNameDialog(final Cat cat) {
- final Context context = new ContextThemeWrapper(this,
- android.R.style.Theme_Material_Light_Dialog_NoActionBar);
- // TODO: Move to XML, add correct margins.
- View view = LayoutInflater.from(context).inflate(R.layout.edit_text, null);
- final EditText text = (EditText) view.findViewById(android.R.id.edit);
- text.setText(cat.getName());
- text.setSelection(cat.getName().length());
- final int size = context.getResources()
- .getDimensionPixelSize(android.R.dimen.app_icon_size);
- Drawable catIcon = cat.createIcon(this, size, size).loadDrawable(this);
- new AlertDialog.Builder(context)
- .setTitle(" ")
- .setIcon(catIcon)
- .setView(view)
- .setPositiveButton(android.R.string.ok, new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- cat.logRename(context);
- cat.setName(text.getText().toString().trim());
- mPrefs.addCat(cat);
- }
- }).show();
- }
-
- @Override
- public void onPrefsChanged() {
- updateCats();
- }
-
- private class CatAdapter extends RecyclerView.Adapter<CatHolder> {
-
- private Cat[] mCats;
-
- public void setCats(Cat[] cats) {
- mCats = cats;
- notifyDataSetChanged();
- }
-
- @Override
- public CatHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- return new CatHolder(LayoutInflater.from(parent.getContext())
- .inflate(R.layout.cat_view, parent, false));
- }
-
- private void setContextGroupVisible(final CatHolder holder, boolean vis) {
- final View group = holder.contextGroup;
- if (vis && group.getVisibility() != View.VISIBLE) {
- group.setAlpha(0);
- group.setVisibility(View.VISIBLE);
- group.animate().alpha(1.0f).setDuration(333);
- Runnable hideAction = new Runnable() {
- @Override
- public void run() {
- setContextGroupVisible(holder, false);
- }
- };
- group.setTag(hideAction);
- group.postDelayed(hideAction, 5000);
- } else if (!vis && group.getVisibility() == View.VISIBLE) {
- group.removeCallbacks((Runnable) group.getTag());
- group.animate().alpha(0f).setDuration(250).withEndAction(new Runnable() {
- @Override
- public void run() {
- group.setVisibility(View.INVISIBLE);
- }
- });
- }
- }
-
- @Override
- public void onBindViewHolder(final CatHolder holder, int position) {
- Context context = holder.itemView.getContext();
- final int size = context.getResources().getDimensionPixelSize(R.dimen.neko_display_size);
- holder.imageView.setImageIcon(mCats[position].createIcon(context, size, size));
- holder.textView.setText(mCats[position].getName());
- holder.itemView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- onCatClick(mCats[holder.getAdapterPosition()]);
- }
- });
- holder.itemView.setOnLongClickListener(new OnLongClickListener() {
- @Override
- public boolean onLongClick(View v) {
- setContextGroupVisible(holder, true);
- return true;
- }
- });
- holder.delete.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- setContextGroupVisible(holder, false);
- new AlertDialog.Builder(NekoLand.this)
- .setTitle(getString(R.string.confirm_delete, mCats[position].getName()))
- .setNegativeButton(android.R.string.cancel, null)
- .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- onCatRemove(mCats[holder.getAdapterPosition()]);
- }
- })
- .show();
- }
- });
- holder.share.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- setContextGroupVisible(holder, false);
- Cat cat = mCats[holder.getAdapterPosition()];
- if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
- != PackageManager.PERMISSION_GRANTED) {
- mPendingShareCat = cat;
- requestPermissions(
- new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
- STORAGE_PERM_REQUEST);
- return;
- }
- shareCat(cat);
- }
- });
- }
-
- @Override
- public int getItemCount() {
- return mCats.length;
- }
- }
-
- private void shareCat(Cat cat) {
- final File dir = new File(
- Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
- getString(R.string.directory_name));
- if (!dir.exists() && !dir.mkdirs()) {
- Log.e("NekoLand", "save: error: can't create Pictures directory");
- return;
- }
- final File png = new File(dir, cat.getName().replaceAll("[/ #:]+", "_") + ".png");
- Bitmap bitmap = cat.createBitmap(EXPORT_BITMAP_SIZE, EXPORT_BITMAP_SIZE);
- if (bitmap != null) {
- try {
- OutputStream os = new FileOutputStream(png);
- bitmap.compress(Bitmap.CompressFormat.PNG, 0, os);
- os.close();
- MediaScannerConnection.scanFile(
- this,
- new String[] {png.toString()},
- new String[] {"image/png"},
- null);
- Log.v("Neko", "cat file: " + png);
- Uri uri = FileProvider.getUriForFile(this, "com.android.egg.fileprovider", png);
- Log.v("Neko", "cat uri: " + uri);
- Intent intent = new Intent(Intent.ACTION_SEND);
- intent.putExtra(Intent.EXTRA_STREAM, uri);
- intent.putExtra(Intent.EXTRA_SUBJECT, cat.getName());
- intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
- intent.setType("image/png");
- startActivity(Intent.createChooser(intent, null));
- cat.logShare(this);
- } catch (IOException e) {
- Log.e("NekoLand", "save: error: " + e);
- }
- }
- }
-
- @Override
- public void onRequestPermissionsResult(int requestCode,
- String permissions[], int[] grantResults) {
- if (requestCode == STORAGE_PERM_REQUEST) {
- if (mPendingShareCat != null) {
- shareCat(mPendingShareCat);
- mPendingShareCat = null;
- }
- }
- }
-
- private static class CatHolder extends RecyclerView.ViewHolder {
- private final ImageView imageView;
- private final TextView textView;
- private final View contextGroup;
- private final View delete;
- private final View share;
-
- public CatHolder(View itemView) {
- super(itemView);
- imageView = (ImageView) itemView.findViewById(android.R.id.icon);
- textView = (TextView) itemView.findViewById(android.R.id.title);
- contextGroup = itemView.findViewById(R.id.contextGroup);
- delete = itemView.findViewById(android.R.id.closeButton);
- share = itemView.findViewById(android.R.id.shareText);
- }
- }
-}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoLockedActivity.java b/packages/EasterEgg/src/com/android/egg/neko/NekoLockedActivity.java
deleted file mode 100644
index e0876a4..0000000
--- a/packages/EasterEgg/src/com/android/egg/neko/NekoLockedActivity.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2016 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.egg.neko;
-
-import androidx.annotation.Nullable;
-import android.app.Activity;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnDismissListener;
-import android.os.Bundle;
-import android.view.WindowManager;
-
-public class NekoLockedActivity extends Activity implements OnDismissListener {
-
- private NekoDialog mDialog;
-
- @Override
- public void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
-
- mDialog = new NekoDialog(this);
- mDialog.setOnDismissListener(this);
- mDialog.show();
- }
-
- @Override
- public void onDismiss(DialogInterface dialog) {
- finish();
- }
-}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoService.java b/packages/EasterEgg/src/com/android/egg/neko/NekoService.java
deleted file mode 100644
index 42506e6..0000000
--- a/packages/EasterEgg/src/com/android/egg/neko/NekoService.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2016 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.egg.neko;
-
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.app.job.JobInfo;
-import android.app.job.JobParameters;
-import android.app.job.JobScheduler;
-import android.app.job.JobService;
-import android.content.ComponentName;
-import android.content.Context;
-import android.net.Uri;
-import android.os.Bundle;
-
-import java.util.List;
-import android.util.Log;
-
-import com.android.egg.R;
-
-import java.util.Random;
-
-import static com.android.egg.neko.Cat.PURR;
-import static com.android.egg.neko.NekoLand.CHAN_ID;
-
-public class NekoService extends JobService {
-
- private static final String TAG = "NekoService";
-
- public static int JOB_ID = 42;
-
- public static int CAT_NOTIFICATION = 1;
- public static int DEBUG_NOTIFICATION = 1234;
-
- public static float CAT_CAPTURE_PROB = 1.0f; // generous
-
- public static long SECONDS = 1000;
- public static long MINUTES = 60 * SECONDS;
-
- public static long INTERVAL_FLEX = 5 * MINUTES;
-
- public static float INTERVAL_JITTER_FRAC = 0.25f;
-
- private static void setupNotificationChannels(Context context) {
- NotificationManager noman = context.getSystemService(NotificationManager.class);
- NotificationChannel eggChan = new NotificationChannel(CHAN_ID,
- context.getString(R.string.notification_channel_name),
- NotificationManager.IMPORTANCE_DEFAULT);
- eggChan.setSound(Uri.EMPTY, Notification.AUDIO_ATTRIBUTES_DEFAULT); // cats are quiet
- eggChan.setVibrationPattern(PURR); // not totally quiet though
- eggChan.setBlockableSystem(true); // unlike a real cat, you can push this one off your lap
- eggChan.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC); // cats sit in the window
- noman.createNotificationChannel(eggChan);
- }
-
- @Override
- public boolean onStartJob(JobParameters params) {
- Log.v(TAG, "Starting job: " + String.valueOf(params));
-
- NotificationManager noman = getSystemService(NotificationManager.class);
- if (NekoLand.DEBUG_NOTIFICATIONS) {
- final Bundle extras = new Bundle();
- extras.putString("android.substName", getString(R.string.notification_name));
- final int size = getResources()
- .getDimensionPixelSize(android.R.dimen.notification_large_icon_width);
- final Cat cat = Cat.create(this);
- final Notification.Builder builder
- = cat.buildNotification(this)
- .setContentTitle("DEBUG")
- .setChannel(NekoLand.CHAN_ID)
- .setContentText("Ran job: " + params);
- noman.notify(DEBUG_NOTIFICATION, builder.build());
- }
-
- final PrefState prefs = new PrefState(this);
- int food = prefs.getFoodState();
- if (food != 0) {
- prefs.setFoodState(0); // nom
- final Random rng = new Random();
- if (rng.nextFloat() <= CAT_CAPTURE_PROB) {
- Cat cat;
- List<Cat> cats = prefs.getCats();
- final int[] probs = getResources().getIntArray(R.array.food_new_cat_prob);
- final float new_cat_prob = (float)((food < probs.length) ? probs[food] : 50) / 100f;
-
- if (cats.size() == 0 || rng.nextFloat() <= new_cat_prob) {
- cat = Cat.create(this);
- prefs.addCat(cat);
- cat.logAdd(this);
- Log.v(TAG, "A new cat is here: " + cat.getName());
- } else {
- cat = cats.get(rng.nextInt(cats.size()));
- Log.v(TAG, "A cat has returned: " + cat.getName());
- }
-
- final Notification.Builder builder = cat.buildNotification(this);
- noman.notify(CAT_NOTIFICATION, builder.build());
- }
- }
- cancelJob(this);
- return false;
- }
-
- @Override
- public boolean onStopJob(JobParameters jobParameters) {
- return false;
- }
-
- public static void registerJobIfNeeded(Context context, long intervalMinutes) {
- JobScheduler jss = context.getSystemService(JobScheduler.class);
- JobInfo info = jss.getPendingJob(JOB_ID);
- if (info == null) {
- registerJob(context, intervalMinutes);
- }
- }
-
- public static void registerJob(Context context, long intervalMinutes) {
- setupNotificationChannels(context);
-
- JobScheduler jss = context.getSystemService(JobScheduler.class);
- jss.cancel(JOB_ID);
- long interval = intervalMinutes * MINUTES;
- long jitter = (long)(INTERVAL_JITTER_FRAC * interval);
- interval += (long)(Math.random() * (2 * jitter)) - jitter;
- final JobInfo jobInfo = new JobInfo.Builder(JOB_ID,
- new ComponentName(context, NekoService.class))
- .setPeriodic(interval, INTERVAL_FLEX)
- .build();
-
- Log.v(TAG, "A cat will visit in " + interval + "ms: " + String.valueOf(jobInfo));
- jss.schedule(jobInfo);
-
- if (NekoLand.DEBUG_NOTIFICATIONS) {
- NotificationManager noman = context.getSystemService(NotificationManager.class);
- noman.notify(DEBUG_NOTIFICATION, new Notification.Builder(context)
- .setSmallIcon(R.drawable.stat_icon)
- .setContentTitle(String.format("Job scheduled in %d min", (interval / MINUTES)))
- .setContentText(String.valueOf(jobInfo))
- .setPriority(Notification.PRIORITY_MIN)
- .setCategory(Notification.CATEGORY_SERVICE)
- .setChannel(NekoLand.CHAN_ID)
- .setShowWhen(true)
- .build());
- }
- }
-
- public static void cancelJob(Context context) {
- JobScheduler jss = context.getSystemService(JobScheduler.class);
- Log.v(TAG, "Canceling job");
- jss.cancel(JOB_ID);
- }
-}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoTile.java b/packages/EasterEgg/src/com/android/egg/neko/NekoTile.java
deleted file mode 100644
index 159b40a..0000000
--- a/packages/EasterEgg/src/com/android/egg/neko/NekoTile.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2016 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.egg.neko;
-
-import android.content.Intent;
-import android.service.quicksettings.Tile;
-import android.service.quicksettings.TileService;
-import android.util.Log;
-
-import com.android.egg.neko.PrefState.PrefsListener;
-import com.android.internal.logging.MetricsLogger;
-
-public class NekoTile extends TileService implements PrefsListener {
-
- private static final String TAG = "NekoTile";
-
- private PrefState mPrefs;
-
- @Override
- public void onCreate() {
- super.onCreate();
- mPrefs = new PrefState(this);
- }
-
- @Override
- public void onStartListening() {
- super.onStartListening();
- mPrefs.setListener(this);
- updateState();
- }
-
- @Override
- public void onStopListening() {
- super.onStopListening();
- mPrefs.setListener(null);
- }
-
- @Override
- public void onTileAdded() {
- super.onTileAdded();
- MetricsLogger.count(this, "egg_neko_tile_added", 1);
- }
-
- @Override
- public void onTileRemoved() {
- super.onTileRemoved();
- MetricsLogger.count(this, "egg_neko_tile_removed", 1);
- }
-
- @Override
- public void onPrefsChanged() {
- updateState();
- }
-
- private void updateState() {
- Tile tile = getQsTile();
- int foodState = mPrefs.getFoodState();
- Food food = new Food(foodState);
- if (foodState != 0) {
- NekoService.registerJobIfNeeded(this, food.getInterval(this));
- }
- tile.setIcon(food.getIcon(this));
- tile.setLabel(food.getName(this));
- tile.setState(foodState != 0 ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
- tile.updateTile();
- }
-
- @Override
- public void onClick() {
- if (mPrefs.getFoodState() != 0) {
- // there's already food loaded, let's empty it
- MetricsLogger.count(this, "egg_neko_empty_food", 1);
- mPrefs.setFoodState(0);
- NekoService.cancelJob(this);
- } else {
- // time to feed the cats
- if (isLocked()) {
- if (isSecure()) {
- Log.d(TAG, "startActivityAndCollapse");
- Intent intent = new Intent(this, NekoLockedActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivityAndCollapse(intent);
- } else {
- unlockAndRun(new Runnable() {
- @Override
- public void run() {
- showNekoDialog();
- }
- });
- }
- } else {
- showNekoDialog();
- }
- }
- }
-
- private void showNekoDialog() {
- Log.d(TAG, "showNekoDialog");
- MetricsLogger.count(this, "egg_neko_select_food", 1);
- showDialog(new NekoDialog(this));
- }
-}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/PrefState.java b/packages/EasterEgg/src/com/android/egg/neko/PrefState.java
deleted file mode 100644
index bf71b19..0000000
--- a/packages/EasterEgg/src/com/android/egg/neko/PrefState.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2016 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.egg.neko;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-public class PrefState implements OnSharedPreferenceChangeListener {
-
- private static final String FILE_NAME = "mPrefs";
-
- private static final String FOOD_STATE = "food";
-
- private static final String CAT_KEY_PREFIX = "cat:";
-
- private final Context mContext;
- private final SharedPreferences mPrefs;
- private PrefsListener mListener;
-
- public PrefState(Context context) {
- mContext = context;
- mPrefs = mContext.getSharedPreferences(FILE_NAME, 0);
- }
-
- // Can also be used for renaming.
- public void addCat(Cat cat) {
- mPrefs.edit()
- .putString(CAT_KEY_PREFIX + String.valueOf(cat.getSeed()), cat.getName())
- .apply();
- }
-
- public void removeCat(Cat cat) {
- mPrefs.edit().remove(CAT_KEY_PREFIX + String.valueOf(cat.getSeed())).apply();
- }
-
- public List<Cat> getCats() {
- ArrayList<Cat> cats = new ArrayList<>();
- Map<String, ?> map = mPrefs.getAll();
- for (String key : map.keySet()) {
- if (key.startsWith(CAT_KEY_PREFIX)) {
- long seed = Long.parseLong(key.substring(CAT_KEY_PREFIX.length()));
- Cat cat = new Cat(mContext, seed);
- cat.setName(String.valueOf(map.get(key)));
- cats.add(cat);
- }
- }
- return cats;
- }
-
- public int getFoodState() {
- return mPrefs.getInt(FOOD_STATE, 0);
- }
-
- public void setFoodState(int foodState) {
- mPrefs.edit().putInt(FOOD_STATE, foodState).apply();
- }
-
- public void setListener(PrefsListener listener) {
- mListener = listener;
- if (mListener != null) {
- mPrefs.registerOnSharedPreferenceChangeListener(this);
- } else {
- mPrefs.unregisterOnSharedPreferenceChangeListener(this);
- }
- }
-
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
- mListener.onPrefsChanged();
- }
-
- public interface PrefsListener {
- void onPrefsChanged();
- }
-}
diff --git a/packages/EasterEgg/src/com/android/egg/octo/Ocquarium.java b/packages/EasterEgg/src/com/android/egg/octo/Ocquarium.java
deleted file mode 100644
index 8a06cc6..0000000
--- a/packages/EasterEgg/src/com/android/egg/octo/Ocquarium.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.egg.octo;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-
-import com.android.egg.R;
-
-public class Ocquarium extends Activity {
- ImageView mImageView;
- private OctopusDrawable mOcto;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- final float dp = getResources().getDisplayMetrics().density;
-
- getWindow().setBackgroundDrawableResource(R.drawable.octo_bg);
-
- FrameLayout bg = new FrameLayout(this);
- setContentView(bg);
- bg.setAlpha(0f);
- bg.animate().setStartDelay(500).setDuration(5000).alpha(1f).start();
-
- mImageView = new ImageView(this);
- bg.addView(mImageView, new FrameLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
-
- mOcto = new OctopusDrawable(getApplicationContext());
- mOcto.setSizePx((int) (OctopusDrawable.randfrange(40f,180f) * dp));
- mImageView.setImageDrawable(mOcto);
-
- mImageView.setOnTouchListener(new View.OnTouchListener() {
- boolean touching;
- @Override
- public boolean onTouch(View view, MotionEvent motionEvent) {
- switch (motionEvent.getActionMasked()) {
- case MotionEvent.ACTION_DOWN:
- if (mOcto.hitTest(motionEvent.getX(), motionEvent.getY())) {
- touching = true;
- mOcto.stopDrift();
- }
- break;
- case MotionEvent.ACTION_MOVE:
- if (touching) {
- mOcto.moveTo(motionEvent.getX(), motionEvent.getY());
- }
- break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- touching = false;
- mOcto.startDrift();
- break;
- }
- return true;
- }
- });
- }
-
- @Override
- protected void onPause() {
- mOcto.stopDrift();
- super.onPause();
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- mOcto.startDrift();
- }
-}
diff --git a/packages/EasterEgg/src/com/android/egg/octo/OctopusDrawable.java b/packages/EasterEgg/src/com/android/egg/octo/OctopusDrawable.java
deleted file mode 100644
index 4f8c11b..0000000
--- a/packages/EasterEgg/src/com/android/egg/octo/OctopusDrawable.java
+++ /dev/null
@@ -1,436 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.egg.octo;
-
-import android.animation.TimeAnimator;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.DashPathEffect;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.PixelFormat;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import androidx.dynamicanimation.animation.DynamicAnimation;
-import androidx.dynamicanimation.animation.SpringForce;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.dynamicanimation.animation.SpringAnimation;
-import androidx.dynamicanimation.animation.FloatValueHolder;
-
-public class OctopusDrawable extends Drawable {
- private static float BASE_SCALE = 100f;
- public static boolean PATH_DEBUG = false;
-
- private static int BODY_COLOR = 0xFF101010;
- private static int ARM_COLOR = 0xFF101010;
- private static int ARM_COLOR_BACK = 0xFF000000;
- private static int EYE_COLOR = 0xFF808080;
-
- private static int[] BACK_ARMS = {1, 3, 4, 6};
- private static int[] FRONT_ARMS = {0, 2, 5, 7};
-
- private Paint mPaint = new Paint();
- private Arm[] mArms = new Arm[8];
- final PointF point = new PointF();
- private int mSizePx = 100;
- final Matrix M = new Matrix();
- final Matrix M_inv = new Matrix();
- private TimeAnimator mDriftAnimation;
- private boolean mBlinking;
- private float[] ptmp = new float[2];
- private float[] scaledBounds = new float[2];
-
- public static float randfrange(float a, float b) {
- return (float) (Math.random()*(b-a) + a);
- }
- public static float clamp(float v, float a, float b) {
- return v<a?a:v>b?b:v;
- }
-
- public OctopusDrawable(Context context) {
- float dp = context.getResources().getDisplayMetrics().density;
- setSizePx((int) (100*dp));
- mPaint.setAntiAlias(true);
- for (int i=0; i<mArms.length; i++) {
- final float bias = (float)i/(mArms.length-1) - 0.5f;
- mArms[i] = new Arm(
- 0,0, // arm will be repositioned on moveTo
- 10f*bias + randfrange(0,20f), randfrange(20f,50f),
- 40f*bias+randfrange(-60f,60f), randfrange(30f, 80f),
- randfrange(-40f,40f), randfrange(-80f,40f),
- 14f, 2f);
- }
- }
-
- public void setSizePx(int size) {
- mSizePx = size;
- M.setScale(mSizePx/BASE_SCALE, mSizePx/BASE_SCALE);
- // TaperedPathStroke.setMinStep(20f*BASE_SCALE/mSizePx); // nice little floaty circles
- TaperedPathStroke.setMinStep(8f*BASE_SCALE/mSizePx); // classic tentacles
- M.invert(M_inv);
- }
-
- public void startDrift() {
- if (mDriftAnimation == null) {
- mDriftAnimation = new TimeAnimator();
- mDriftAnimation.setTimeListener(new TimeAnimator.TimeListener() {
- float MAX_VY = 35f;
- float JUMP_VY = -100f;
- float MAX_VX = 15f;
- private float ax = 0f, ay = 30f;
- private float vx, vy;
- long nextjump = 0;
- long unblink = 0;
- @Override
- public void onTimeUpdate(TimeAnimator timeAnimator, long t, long dt) {
- float t_sec = 0.001f * t;
- float dt_sec = 0.001f * dt;
- if (t > nextjump) {
- vy = JUMP_VY;
- nextjump = t + (long) randfrange(5000, 10000);
- }
- if (unblink > 0 && t > unblink) {
- setBlinking(false);
- unblink = 0;
- } else if (Math.random() < 0.001f) {
- setBlinking(true);
- unblink = t + 200;
- }
-
- ax = (float) (MAX_VX * Math.sin(t_sec*.25f));
-
- vx = clamp(vx + dt_sec * ax, -MAX_VX, MAX_VX);
- vy = clamp(vy + dt_sec * ay, -100*MAX_VY, MAX_VY);
-
- // oob check
- if (point.y - BASE_SCALE/2 > scaledBounds[1]) {
- vy = JUMP_VY;
- } else if (point.y + BASE_SCALE < 0) {
- vy = MAX_VY;
- }
-
- point.x = clamp(point.x + dt_sec * vx, 0, scaledBounds[0]);
- point.y = point.y + dt_sec * vy;
-
- repositionArms();
- }
- });
- }
- mDriftAnimation.start();
- }
-
- public void stopDrift() {
- mDriftAnimation.cancel();
- }
-
- @Override
- public void onBoundsChange(Rect bounds) {
- final float w = bounds.width();
- final float h = bounds.height();
-
- lockArms(true);
- moveTo(w/2, h/2);
- lockArms(false);
-
- scaledBounds[0] = w;
- scaledBounds[1] = h;
- M_inv.mapPoints(scaledBounds);
- }
-
- // real pixel coordinates
- public void moveTo(float x, float y) {
- point.x = x;
- point.y = y;
- mapPointF(M_inv, point);
- repositionArms();
- }
-
- public boolean hitTest(float x, float y) {
- ptmp[0] = x;
- ptmp[1] = y;
- M_inv.mapPoints(ptmp);
- return Math.hypot(ptmp[0] - point.x, ptmp[1] - point.y) < BASE_SCALE/2;
- }
-
- private void lockArms(boolean l) {
- for (Arm arm : mArms) {
- arm.setLocked(l);
- }
- }
- private void repositionArms() {
- for (int i=0; i<mArms.length; i++) {
- final float bias = (float)i/(mArms.length-1) - 0.5f;
- mArms[i].setAnchor(
- point.x+bias*30f,point.y+26f);
- }
- invalidateSelf();
- }
-
- private void drawPupil(Canvas canvas, float x, float y, float size, boolean open,
- Paint pt) {
- final float r = open ? size*.33f : size * .1f;
- canvas.drawRoundRect(x - size, y - r, x + size, y + r, r, r, pt);
- }
-
- @Override
- public void draw(@NonNull Canvas canvas) {
- canvas.save();
- {
- canvas.concat(M);
-
- // arms behind
- mPaint.setColor(ARM_COLOR_BACK);
- for (int i : BACK_ARMS) {
- mArms[i].draw(canvas, mPaint);
- }
-
- // head/body/thing
- mPaint.setColor(EYE_COLOR);
- canvas.drawCircle(point.x, point.y, 36f, mPaint);
- mPaint.setColor(BODY_COLOR);
- canvas.save();
- {
- canvas.clipOutRect(point.x - 61f, point.y + 8f,
- point.x + 61f, point.y + 12f);
- canvas.drawOval(point.x-40f,point.y-60f,point.x+40f,point.y+40f, mPaint);
- }
- canvas.restore();
-
- // eyes
- mPaint.setColor(EYE_COLOR);
- if (mBlinking) {
- drawPupil(canvas, point.x - 16f, point.y - 12f, 6f, false, mPaint);
- drawPupil(canvas, point.x + 16f, point.y - 12f, 6f, false, mPaint);
- } else {
- canvas.drawCircle(point.x - 16f, point.y - 12f, 6f, mPaint);
- canvas.drawCircle(point.x + 16f, point.y - 12f, 6f, mPaint);
- }
-
- // too much?
- if (false) {
- mPaint.setColor(0xFF000000);
- drawPupil(canvas, point.x - 16f, point.y - 12f, 5f, true, mPaint);
- drawPupil(canvas, point.x + 16f, point.y - 12f, 5f, true, mPaint);
- }
-
- // arms in front
- mPaint.setColor(ARM_COLOR);
- for (int i : FRONT_ARMS) {
- mArms[i].draw(canvas, mPaint);
- }
-
- if (PATH_DEBUG) for (Arm arm : mArms) {
- arm.drawDebug(canvas);
- }
- }
- canvas.restore();
- }
-
- public void setBlinking(boolean b) {
- mBlinking = b;
- invalidateSelf();
- }
-
- @Override
- public void setAlpha(int i) {
- }
-
- @Override
- public void setColorFilter(@Nullable ColorFilter colorFilter) {
-
- }
-
- @Override
- public int getOpacity() {
- return PixelFormat.TRANSLUCENT;
- }
-
- static Path pathMoveTo(Path p, PointF pt) {
- p.moveTo(pt.x, pt.y);
- return p;
- }
- static Path pathQuadTo(Path p, PointF p1, PointF p2) {
- p.quadTo(p1.x, p1.y, p2.x, p2.y);
- return p;
- }
-
- static void mapPointF(Matrix m, PointF point) {
- float[] p = new float[2];
- p[0] = point.x;
- p[1] = point.y;
- m.mapPoints(p);
- point.x = p[0];
- point.y = p[1];
- }
-
- private class Link // he come to town
- implements DynamicAnimation.OnAnimationUpdateListener {
- final FloatValueHolder[] coords = new FloatValueHolder[2];
- final SpringAnimation[] anims = new SpringAnimation[coords.length];
- private float dx, dy;
- private boolean locked = false;
- Link next;
-
- Link(int index, float x1, float y1, float dx, float dy) {
- coords[0] = new FloatValueHolder(x1);
- coords[1] = new FloatValueHolder(y1);
- this.dx = dx;
- this.dy = dy;
- for (int i=0; i<coords.length; i++) {
- anims[i] = new SpringAnimation(coords[i]);
- anims[i].setSpring(new SpringForce()
- .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
- .setStiffness(
- index == 0 ? SpringForce.STIFFNESS_LOW
- : index == 1 ? SpringForce.STIFFNESS_VERY_LOW
- : SpringForce.STIFFNESS_VERY_LOW/2)
- .setFinalPosition(0f));
- anims[i].addUpdateListener(this);
- }
- }
- public void setLocked(boolean locked) {
- this.locked = locked;
- }
- public PointF start() {
- return new PointF(coords[0].getValue(), coords[1].getValue());
- }
- public PointF end() {
- return new PointF(coords[0].getValue()+dx,coords[1].getValue()+dy);
- }
- public PointF mid() {
- return new PointF(
- 0.5f*dx+(coords[0].getValue()),
- 0.5f*dy+(coords[1].getValue()));
- }
- public void animateTo(PointF target) {
- if (locked) {
- setStart(target.x, target.y);
- } else {
- anims[0].animateToFinalPosition(target.x);
- anims[1].animateToFinalPosition(target.y);
- }
- }
- @Override
- public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float v, float v1) {
- if (next != null) {
- next.animateTo(end());
- }
- OctopusDrawable.this.invalidateSelf();
- }
-
- public void setStart(float x, float y) {
- coords[0].setValue(x);
- coords[1].setValue(y);
- onAnimationUpdate(null, 0, 0);
- }
- }
-
- private class Arm {
- final Link link1, link2, link3;
- float max, min;
-
- public Arm(float x, float y, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3,
- float max, float min) {
- link1 = new Link(0, x, y, dx1, dy1);
- link2 = new Link(1, x+dx1, y+dy1, dx2, dy2);
- link3 = new Link(2, x+dx1+dx2, y+dy1+dy2, dx3, dy3);
- link1.next = link2;
- link2.next = link3;
-
- link1.setLocked(true);
- link2.setLocked(false);
- link3.setLocked(false);
-
- this.max = max;
- this.min = min;
- }
-
- // when the arm is locked, it moves rigidly, without physics
- public void setLocked(boolean locked) {
- link2.setLocked(locked);
- link3.setLocked(locked);
- }
-
- private void setAnchor(float x, float y) {
- link1.setStart(x,y);
- }
-
- public Path getPath() {
- Path p = new Path();
- pathMoveTo(p, link1.start());
- pathQuadTo(p, link2.start(), link2.mid());
- pathQuadTo(p, link2.end(), link3.end());
- return p;
- }
-
- public void draw(@NonNull Canvas canvas, Paint pt) {
- final Path p = getPath();
- TaperedPathStroke.drawPath(canvas, p, max, min, pt);
- }
-
- private final Paint dpt = new Paint();
- public void drawDebug(Canvas canvas) {
- dpt.setStyle(Paint.Style.STROKE);
- dpt.setStrokeWidth(0.75f);
- dpt.setStrokeCap(Paint.Cap.ROUND);
-
- dpt.setAntiAlias(true);
- dpt.setColor(0xFF336699);
-
- final Path path = getPath();
- canvas.drawPath(path, dpt);
-
- dpt.setColor(0xFFFFFF00);
-
- dpt.setPathEffect(new DashPathEffect(new float[] {2f, 2f}, 0f));
-
- canvas.drawLines(new float[] {
- link1.end().x, link1.end().y,
- link2.start().x, link2.start().y,
-
- link2.end().x, link2.end().y,
- link3.start().x, link3.start().y,
- }, dpt);
- dpt.setPathEffect(null);
-
- dpt.setColor(0xFF00CCFF);
-
- canvas.drawLines(new float[] {
- link1.start().x, link1.start().y,
- link1.end().x, link1.end().y,
-
- link2.start().x, link2.start().y,
- link2.end().x, link2.end().y,
-
- link3.start().x, link3.start().y,
- link3.end().x, link3.end().y,
- }, dpt);
-
- dpt.setColor(0xFFCCEEFF);
- canvas.drawCircle(link2.start().x, link2.start().y, 2f, dpt);
- canvas.drawCircle(link3.start().x, link3.start().y, 2f, dpt);
-
- dpt.setStyle(Paint.Style.FILL_AND_STROKE);
- canvas.drawCircle(link1.start().x, link1.start().y, 2f, dpt);
- canvas.drawCircle(link2.mid().x, link2.mid().y, 2f, dpt);
- canvas.drawCircle(link3.end().x, link3.end().y, 2f, dpt);
- }
-
- }
-}
diff --git a/packages/EasterEgg/src/com/android/egg/octo/TaperedPathStroke.java b/packages/EasterEgg/src/com/android/egg/octo/TaperedPathStroke.java
deleted file mode 100644
index e014fbc..0000000
--- a/packages/EasterEgg/src/com/android/egg/octo/TaperedPathStroke.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.egg.octo;
-
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.PathMeasure;
-import android.os.Debug;
-
-import java.util.Arrays;
-
-public class TaperedPathStroke {
- static float sMinStepPx = 4f;
- static PathMeasure pm = new PathMeasure();
- static float[] pos = {0,0};
- static float[] tan = {0,0};
- static float lerp(float t, float a, float b) {
- return a + t*(b-a);
- }
- public static void setMinStep(float px) {
- sMinStepPx = px;
- }
-
- // it's the variable-width brush algorithm from the Markers app, basically
- public static void drawPath(Canvas c, Path p, float r1, float r2, Paint pt) {
- pm.setPath(p,false);
- final float len = pm.getLength();
- float t=0;
- boolean last=false;
- while (true) {
- if (t>=len) {
- t=len;
- last=true;
- }
- pm.getPosTan(t, pos, tan);
- float r = len > 0 ? lerp(t/len, r1, r2) : r1;
- c.drawCircle(pos[0], pos[1], r, pt);
- t += Math.max(r*0.25f, sMinStepPx); // walk forward 1/4 radius, not too small though
- if (last) break;
- }
- }
-}
diff --git a/packages/EasterEgg/src/com/android/egg/paint/BrushPropertyDrawable.kt b/packages/EasterEgg/src/com/android/egg/paint/BrushPropertyDrawable.kt
new file mode 100644
index 0000000..4a02ee6
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/paint/BrushPropertyDrawable.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2018 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.egg.paint
+
+import android.content.Context
+import android.graphics.*
+import android.graphics.PixelFormat.TRANSLUCENT
+import android.graphics.drawable.Drawable
+import android.util.DisplayMetrics
+
+class BrushPropertyDrawable : Drawable {
+ val framePaint = Paint(Paint.ANTI_ALIAS_FLAG).also {
+ it.color = Color.BLACK
+ it.style = Paint.Style.FILL
+ }
+ val wellPaint = Paint(Paint.ANTI_ALIAS_FLAG).also {
+ it.color = Color.RED
+ it.style = Paint.Style.FILL
+ }
+
+ constructor(context: Context) {
+ _size = (24 * context.resources.displayMetrics.density).toInt()
+ }
+
+ private var _size = 24
+ private var _scale = 1f
+
+ fun setFrameColor(color: Int) {
+ framePaint.color = color
+ invalidateSelf()
+ }
+
+ fun setWellColor(color: Int) {
+ wellPaint.color = color
+ invalidateSelf()
+ }
+
+ fun setWellScale(scale: Float) {
+ _scale = scale
+ invalidateSelf()
+ }
+
+ override fun getIntrinsicWidth(): Int {
+ return _size
+ }
+
+ override fun getIntrinsicHeight(): Int {
+ return _size
+ }
+
+ override fun draw(c: Canvas?) {
+ c?.let {
+ val w = bounds.width().toFloat()
+ val h = bounds.height().toFloat()
+ val inset = _size / 12 // 2dp in a 24x24 icon
+ val r = Math.min(w, h) / 2
+
+ c.drawCircle(w/2, h/2, (r - inset) * _scale + 1 , wellPaint)
+
+ val p = Path()
+ p.addCircle(w/2, h/2, r, Path.Direction.CCW)
+ p.addCircle(w/2, h/2, r - inset, Path.Direction.CW)
+ c.drawPath(p, framePaint)
+ }
+ }
+
+ override fun setAlpha(p0: Int) {
+ //
+ }
+
+ override fun getOpacity(): Int {
+ return TRANSLUCENT
+ }
+
+ override fun setColorFilter(p0: ColorFilter?) {
+ //
+ }
+
+}
\ No newline at end of file
diff --git a/packages/EasterEgg/src/com/android/egg/paint/CutoutAvoidingToolbar.kt b/packages/EasterEgg/src/com/android/egg/paint/CutoutAvoidingToolbar.kt
new file mode 100644
index 0000000..164fc5a
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/paint/CutoutAvoidingToolbar.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2018 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.egg.paint
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.*
+import android.view.ViewGroup.LayoutParams.MATCH_PARENT
+import android.widget.LinearLayout
+
+class CutoutAvoidingToolbar : LinearLayout {
+ private var _insets: WindowInsets? = null
+
+ constructor(context: Context) : super(context) {
+ init(null, 0)
+ }
+
+ constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
+ init(attrs, 0)
+ }
+
+ constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
+ init(attrs, defStyle)
+ }
+
+ override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
+ super.onSizeChanged(w, h, oldw, oldh)
+ adjustLayout()
+ }
+
+ override fun onApplyWindowInsets(insets: WindowInsets?): WindowInsets {
+ _insets = insets
+ adjustLayout()
+ return super.onApplyWindowInsets(insets)
+ }
+
+ fun adjustLayout() {
+ _insets?.displayCutout?.boundingRects?.let {
+ var cutoutCenter = 0
+ var cutoutLeft = 0
+ var cutoutRight = 0
+
+ // collect at most three cutouts
+ for (r in it) {
+ if (r.top > 0) continue
+
+ if (r.left == left) {
+ cutoutLeft = r.width()
+ } else if (r.right == right) {
+ cutoutRight = r.width()
+ } else {
+ cutoutCenter = r.width()
+ }
+ }
+
+ // apply to layout
+ (findViewWithTag("cutoutLeft") as View?)?.let {
+ it.layoutParams = LayoutParams(cutoutLeft, MATCH_PARENT)
+ }
+ (findViewWithTag("cutoutCenter") as View?)?.let {
+ it.layoutParams = LayoutParams(cutoutCenter, MATCH_PARENT)
+ }
+ (findViewWithTag("cutoutRight") as View?)?.let {
+ it.layoutParams = LayoutParams(cutoutRight, MATCH_PARENT)
+ }
+
+ requestLayout()
+ }
+ }
+
+ private fun init(attrs: AttributeSet?, defStyle: Int) {
+ }
+
+}
diff --git a/packages/EasterEgg/src/com/android/egg/paint/PaintActivity.java b/packages/EasterEgg/src/com/android/egg/paint/PaintActivity.java
new file mode 100644
index 0000000..ac47fbd
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/paint/PaintActivity.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2018 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.egg.paint;
+
+import static android.view.MotionEvent.ACTION_CANCEL;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_MOVE;
+import static android.view.MotionEvent.ACTION_UP;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.animation.OvershootInterpolator;
+import android.widget.FrameLayout;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.Magnifier;
+
+import com.android.egg.R;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.stream.IntStream;
+
+public class PaintActivity extends Activity {
+ private static final float MAX_BRUSH_WIDTH_DP = 100f;
+ private static final float MIN_BRUSH_WIDTH_DP = 1f;
+
+ private static final int NUM_BRUSHES = 6;
+ private static final int NUM_COLORS = 6;
+
+ private Painting painting = null;
+ private CutoutAvoidingToolbar toolbar = null;
+ private LinearLayout brushes = null;
+ private LinearLayout colors = null;
+ private Magnifier magnifier = null;
+ private boolean sampling = false;
+
+ private View.OnClickListener buttonHandler = new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ switch (view.getId()) {
+ case R.id.btnBrush:
+ view.setSelected(true);
+ hideToolbar(colors);
+ toggleToolbar(brushes);
+ break;
+ case R.id.btnColor:
+ view.setSelected(true);
+ hideToolbar(brushes);
+ toggleToolbar(colors);
+ break;
+ case R.id.btnClear:
+ painting.clear();
+ break;
+ case R.id.btnSample:
+ sampling = true;
+ view.setSelected(true);
+ break;
+ case R.id.btnZen:
+ painting.setZenMode(!painting.getZenMode());
+ view.animate()
+ .setStartDelay(200)
+ .setInterpolator(new OvershootInterpolator())
+ .rotation(painting.getZenMode() ? 0f : 90f);
+ break;
+ }
+ }
+ };
+
+ private void showToolbar(View bar) {
+ if (bar.getVisibility() != View.GONE) return;
+ bar.setVisibility(View.VISIBLE);
+ bar.setTranslationY(toolbar.getHeight()/2);
+ bar.animate()
+ .translationY(toolbar.getHeight())
+ .alpha(1f)
+ .setDuration(220)
+ .start();
+ }
+
+ private void hideToolbar(View bar) {
+ if (bar.getVisibility() != View.VISIBLE) return;
+ bar.animate()
+ .translationY(toolbar.getHeight()/2)
+ .alpha(0f)
+ .setDuration(150)
+ .withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ bar.setVisibility(View.GONE);
+ }
+ })
+ .start();
+ }
+
+ private void toggleToolbar(View bar) {
+ if (bar.getVisibility() == View.VISIBLE) {
+ hideToolbar(bar);
+ } else {
+ showToolbar(bar);
+ }
+ }
+
+ private BrushPropertyDrawable widthButtonDrawable;
+ private BrushPropertyDrawable colorButtonDrawable;
+ private float maxBrushWidth, minBrushWidth;
+ private int nightMode = Configuration.UI_MODE_NIGHT_UNDEFINED;
+
+ static final float lerp(float f, float a, float b) {
+ return a + (b-a) * f;
+ }
+
+ void setupViews(Painting oldPainting) {
+ setContentView(R.layout.activity_paint);
+
+ painting = oldPainting != null ? oldPainting : new Painting(this);
+ ((FrameLayout) findViewById(R.id.contentView)).addView(painting,
+ new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+
+ painting.setPaperColor(getColor(R.color.paper_color));
+ painting.setPaintColor(getColor(R.color.paint_color));
+
+ toolbar = findViewById(R.id.toolbar);
+ brushes = findViewById(R.id.brushes);
+ colors = findViewById(R.id.colors);
+
+ magnifier = new Magnifier(painting);
+
+ painting.setOnTouchListener(
+ new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View view, MotionEvent event) {
+ switch (event.getActionMasked()) {
+ case ACTION_DOWN:
+ case ACTION_MOVE:
+ if (sampling) {
+ magnifier.show(event.getX(), event.getY());
+ colorButtonDrawable.setWellColor(
+ painting.sampleAt(event.getX(), event.getY()));
+ return true;
+ }
+ break;
+ case ACTION_CANCEL:
+ if (sampling) {
+ findViewById(R.id.btnSample).setSelected(false);
+ sampling = false;
+ magnifier.dismiss();
+ }
+ break;
+ case ACTION_UP:
+ if (sampling) {
+ findViewById(R.id.btnSample).setSelected(false);
+ sampling = false;
+ magnifier.dismiss();
+ painting.setPaintColor(
+ painting.sampleAt(event.getX(), event.getY()));
+ refreshBrushAndColor();
+ }
+ break;
+ }
+ return false; // allow view to continue handling
+ }
+ });
+
+ findViewById(R.id.btnBrush).setOnClickListener(buttonHandler);
+ findViewById(R.id.btnColor).setOnClickListener(buttonHandler);
+ findViewById(R.id.btnClear).setOnClickListener(buttonHandler);
+ findViewById(R.id.btnSample).setOnClickListener(buttonHandler);
+ findViewById(R.id.btnZen).setOnClickListener(buttonHandler);
+
+ findViewById(R.id.btnColor).setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View view) {
+ colors.removeAllViews();
+ showToolbar(colors);
+ refreshBrushAndColor();
+ return true;
+ }
+ });
+
+ findViewById(R.id.btnClear).setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View view) {
+ painting.invertContents();
+ return true;
+ }
+ });
+
+ widthButtonDrawable = new BrushPropertyDrawable(this);
+ widthButtonDrawable.setFrameColor(getColor(R.color.toolbar_icon_color));
+ colorButtonDrawable = new BrushPropertyDrawable(this);
+ colorButtonDrawable.setFrameColor(getColor(R.color.toolbar_icon_color));
+
+ ((ImageButton) findViewById(R.id.btnBrush)).setImageDrawable(widthButtonDrawable);
+ ((ImageButton) findViewById(R.id.btnColor)).setImageDrawable(colorButtonDrawable);
+
+ refreshBrushAndColor();
+ }
+
+ private void refreshBrushAndColor() {
+ final LinearLayout.LayoutParams button_lp = new LinearLayout.LayoutParams(
+ 0, ViewGroup.LayoutParams.WRAP_CONTENT);
+ button_lp.weight = 1f;
+ if (brushes.getChildCount() == 0) {
+ for (int i = 0; i < NUM_BRUSHES; i++) {
+ final BrushPropertyDrawable icon = new BrushPropertyDrawable(this);
+ icon.setFrameColor(getColor(R.color.toolbar_icon_color));
+ // exponentially increasing brush size
+ final float width = lerp(
+ (float) Math.pow((float) i / NUM_BRUSHES, 2f), minBrushWidth,
+ maxBrushWidth);
+ icon.setWellScale(width / maxBrushWidth);
+ icon.setWellColor(getColor(R.color.toolbar_icon_color));
+ final ImageButton button = new ImageButton(this);
+ button.setImageDrawable(icon);
+ button.setBackground(getDrawable(R.drawable.toolbar_button_bg));
+ button.setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ brushes.setSelected(false);
+ hideToolbar(brushes);
+ painting.setBrushWidth(width);
+ refreshBrushAndColor();
+ }
+ });
+ brushes.addView(button, button_lp);
+ }
+ }
+
+ if (colors.getChildCount() == 0) {
+ final Palette pal = new Palette(NUM_COLORS);
+ for (final int c : IntStream.concat(
+ IntStream.of(Color.BLACK, Color.WHITE),
+ Arrays.stream(pal.getColors())
+ ).toArray()) {
+ final BrushPropertyDrawable icon = new BrushPropertyDrawable(this);
+ icon.setFrameColor(getColor(R.color.toolbar_icon_color));
+ icon.setWellColor(c);
+ final ImageButton button = new ImageButton(this);
+ button.setImageDrawable(icon);
+ button.setBackground(getDrawable(R.drawable.toolbar_button_bg));
+ button.setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ colors.setSelected(false);
+ hideToolbar(colors);
+ painting.setPaintColor(c);
+ refreshBrushAndColor();
+ }
+ });
+ colors.addView(button, button_lp);
+ }
+ }
+
+ widthButtonDrawable.setWellScale(painting.getBrushWidth() / maxBrushWidth);
+ widthButtonDrawable.setWellColor(painting.getPaintColor());
+ colorButtonDrawable.setWellColor(painting.getPaintColor());
+ }
+
+ private void refreshNightMode(Configuration config) {
+ int newNightMode =
+ (config.uiMode & Configuration.UI_MODE_NIGHT_MASK);
+ if (nightMode != newNightMode) {
+ if (nightMode != Configuration.UI_MODE_NIGHT_UNDEFINED) {
+ painting.invertContents();
+
+ ((ViewGroup) painting.getParent()).removeView(painting);
+ setupViews(painting);
+
+ final View decorView = getWindow().getDecorView();
+ int decorSUIV = decorView.getSystemUiVisibility();
+
+ if (newNightMode == Configuration.UI_MODE_NIGHT_YES) {
+ decorView.setSystemUiVisibility(
+ decorSUIV & ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
+ } else {
+ decorView.setSystemUiVisibility(
+ decorSUIV | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
+ }
+ }
+ nightMode = newNightMode;
+ }
+ }
+
+ public PaintActivity() {
+
+ }
+
+ @Override
+ public void onTrimMemory(int level) {
+ super.onTrimMemory(level);
+
+ painting.onTrimMemory();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+
+ refreshNightMode(newConfig);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ WindowManager.LayoutParams lp = getWindow().getAttributes();
+ lp.flags = lp.flags
+ | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
+ getWindow().setAttributes(lp);
+
+ maxBrushWidth = MAX_BRUSH_WIDTH_DP * getResources().getDisplayMetrics().density;
+ minBrushWidth = MIN_BRUSH_WIDTH_DP * getResources().getDisplayMetrics().density;
+
+ setupViews(null);
+ refreshNightMode(getResources().getConfiguration());
+ }
+
+ @Override
+ public void onPostResume() {
+ super.onPostResume();
+ }
+
+}
diff --git a/packages/EasterEgg/src/com/android/egg/paint/Painting.kt b/packages/EasterEgg/src/com/android/egg/paint/Painting.kt
new file mode 100644
index 0000000..a4a3d3d
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/paint/Painting.kt
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2018 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.egg.paint
+
+import android.content.Context
+import android.content.res.Resources
+import android.graphics.*
+import android.provider.Settings
+import android.util.AttributeSet
+import android.util.DisplayMetrics
+import android.view.MotionEvent
+import android.view.View
+import android.view.WindowInsets
+import java.util.concurrent.TimeUnit
+import android.util.Log
+import android.provider.Settings.System
+
+import org.json.JSONObject
+
+fun hypot(x: Float, y: Float): Float {
+ return Math.hypot(x.toDouble(), y.toDouble()).toFloat()
+}
+
+fun invlerp(x: Float, a: Float, b: Float): Float {
+ return if (b > a) {
+ (x - a) / (b - a)
+ } else 1.0f
+}
+
+public class Painting : View, SpotFilter.Plotter {
+ companion object {
+ val FADE_MINS = TimeUnit.MINUTES.toMillis(3) // about how long a drawing should last
+ val ZEN_RATE = TimeUnit.SECONDS.toMillis(2) // how often to apply the fade
+ val ZEN_FADE = Math.max(1f, ZEN_RATE / FADE_MINS * 255f)
+
+ val FADE_TO_WHITE_CF = ColorMatrixColorFilter(ColorMatrix(floatArrayOf(
+ 1f, 0f, 0f, 0f, ZEN_FADE,
+ 0f, 1f, 0f, 0f, ZEN_FADE,
+ 0f, 0f, 1f, 0f, ZEN_FADE,
+ 0f, 0f, 0f, 1f, 0f
+ )))
+
+ val FADE_TO_BLACK_CF = ColorMatrixColorFilter(ColorMatrix(floatArrayOf(
+ 1f, 0f, 0f, 0f, -ZEN_FADE,
+ 0f, 1f, 0f, 0f, -ZEN_FADE,
+ 0f, 0f, 1f, 0f, -ZEN_FADE,
+ 0f, 0f, 0f, 1f, 0f
+ )))
+
+ val INVERT_CF = ColorMatrixColorFilter(ColorMatrix(floatArrayOf(
+ -1f, 0f, 0f, 0f, 255f,
+ 0f, -1f, 0f, 0f, 255f,
+ 0f, 0f, -1f, 0f, 255f,
+ 0f, 0f, 0f, 1f, 0f
+ )))
+
+ val TOUCH_STATS = "touch.stats" // Settings.System key
+ }
+
+ var devicePressureMin = 0f; // ideal value
+ var devicePressureMax = 1f; // ideal value
+
+ var zenMode = true
+ set(value) {
+ if (field != value) {
+ field = value
+ removeCallbacks(fadeRunnable)
+ if (value && isAttachedToWindow) {
+ handler.postDelayed(fadeRunnable, ZEN_RATE)
+ }
+ }
+ }
+
+ var bitmap: Bitmap? = null
+ var paperColor : Int = 0xFFFFFFFF.toInt()
+
+ private var _paintCanvas: Canvas? = null
+ private val _bitmapLock = Object()
+
+ private var _drawPaint = Paint(Paint.ANTI_ALIAS_FLAG)
+ private var _lastX = 0f
+ private var _lastY = 0f
+ private var _lastR = 0f
+ private var _insets: WindowInsets? = null
+
+ private var _brushWidth = 100f
+
+ private var _filter = SpotFilter(10, 0.5f, 0.9f, this)
+
+ private val fadeRunnable = object : Runnable {
+ private val pt = Paint()
+ override fun run() {
+ val c = _paintCanvas
+ if (c != null) {
+ pt.colorFilter =
+ if (paperColor.and(0xFF) > 0x80)
+ FADE_TO_WHITE_CF
+ else
+ FADE_TO_BLACK_CF
+
+ synchronized(_bitmapLock) {
+ c.drawBitmap(bitmap, 0f, 0f, pt)
+ }
+ invalidate()
+ }
+ postDelayed(this, ZEN_RATE)
+ }
+ }
+
+ constructor(context: Context) : super(context) {
+ init(null, 0)
+ }
+
+ constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
+ init(attrs, 0)
+ }
+
+ constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
+ init(attrs, defStyle)
+ }
+
+ private fun init(attrs: AttributeSet?, defStyle: Int) {
+ loadDevicePressureData()
+ }
+
+ override fun onAttachedToWindow() {
+ super.onAttachedToWindow()
+
+ setupBitmaps()
+
+ if (zenMode) {
+ handler.postDelayed(fadeRunnable, ZEN_RATE)
+ }
+ }
+
+ override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
+ super.onSizeChanged(w, h, oldw, oldh)
+ setupBitmaps()
+ }
+
+ override fun onDetachedFromWindow() {
+ if (zenMode) {
+ removeCallbacks(fadeRunnable)
+ }
+ super.onDetachedFromWindow()
+ }
+
+ fun onTrimMemory() {
+ }
+
+ override fun onApplyWindowInsets(insets: WindowInsets?): WindowInsets {
+ _insets = insets
+ if (insets != null && _paintCanvas == null) {
+ setupBitmaps()
+ }
+ return super.onApplyWindowInsets(insets)
+ }
+
+ private fun powf(a: Float, b: Float): Float {
+ return Math.pow(a.toDouble(), b.toDouble()).toFloat()
+ }
+
+ override fun plot(s: MotionEvent.PointerCoords) {
+ val c = _paintCanvas
+ if (c == null) return
+ synchronized(_bitmapLock) {
+ var x = _lastX
+ var y = _lastY
+ var r = _lastR
+ val newR = Math.max(1f, powf(adjustPressure(s.pressure), 2f).toFloat() * _brushWidth)
+
+ if (r >= 0) {
+ val d = hypot(s.x - x, s.y - y)
+ if (d > 1f && (r + newR) > 1f) {
+ val N = (2 * d / Math.min(4f, r + newR)).toInt()
+
+ val stepX = (s.x - x) / N
+ val stepY = (s.y - y) / N
+ val stepR = (newR - r) / N
+ for (i in 0 until N - 1) { // we will draw the last circle below
+ x += stepX
+ y += stepY
+ r += stepR
+ c.drawCircle(x, y, r, _drawPaint)
+ }
+ }
+ }
+
+ c.drawCircle(s.x, s.y, newR, _drawPaint)
+ _lastX = s.x
+ _lastY = s.y
+ _lastR = newR
+ }
+ }
+
+ private fun loadDevicePressureData() {
+ try {
+ val touchDataJson = Settings.System.getString(context.contentResolver, TOUCH_STATS)
+ val touchData = JSONObject(
+ if (touchDataJson != null) touchDataJson else "{}")
+ if (touchData.has("min")) devicePressureMin = touchData.getDouble("min").toFloat()
+ if (touchData.has("max")) devicePressureMax = touchData.getDouble("max").toFloat()
+ if (devicePressureMin < 0) devicePressureMin = 0f
+ if (devicePressureMax < devicePressureMin) devicePressureMax = devicePressureMin + 1f
+ } catch (e: Exception) {
+ }
+ }
+
+ private fun adjustPressure(pressure: Float): Float {
+ if (pressure > devicePressureMax) devicePressureMax = pressure
+ if (pressure < devicePressureMin) devicePressureMin = pressure
+ return invlerp(pressure, devicePressureMin, devicePressureMax)
+ }
+
+ override fun onTouchEvent(event: MotionEvent?): Boolean {
+ val c = _paintCanvas
+ if (event == null || c == null) return super.onTouchEvent(event)
+
+ /*
+ val pt = Paint(Paint.ANTI_ALIAS_FLAG)
+ pt.style = Paint.Style.STROKE
+ pt.color = 0x800000FF.toInt()
+ _paintCanvas?.drawCircle(event.x, event.y, 20f, pt)
+ */
+
+ when (event.actionMasked) {
+ MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
+ _filter.add(event)
+ _filter.finish()
+ invalidate()
+ }
+
+ MotionEvent.ACTION_DOWN -> {
+ _lastR = -1f
+ _filter.add(event)
+ invalidate()
+ }
+
+ MotionEvent.ACTION_MOVE -> {
+ _filter.add(event)
+
+ invalidate()
+ }
+ }
+
+ return true
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+
+ bitmap?.let {
+ canvas.drawBitmap(bitmap, 0f, 0f, _drawPaint);
+ }
+ }
+
+ // public api
+ fun clear() {
+ bitmap = null
+ setupBitmaps()
+ invalidate()
+ }
+
+ fun sampleAt(x: Float, y: Float): Int {
+ val localX = (x - left).toInt()
+ val localY = (y - top).toInt()
+ return bitmap?.getPixel(localX, localY) ?: Color.BLACK
+ }
+
+ fun setPaintColor(color: Int) {
+ _drawPaint.color = color
+ }
+
+ fun getPaintColor(): Int {
+ return _drawPaint.color
+ }
+
+ fun setBrushWidth(w: Float) {
+ _brushWidth = w
+ }
+
+ fun getBrushWidth(): Float {
+ return _brushWidth
+ }
+
+ private fun setupBitmaps() {
+ val dm = DisplayMetrics()
+ display.getRealMetrics(dm)
+ val w = dm.widthPixels
+ val h = dm.heightPixels
+ val oldBits = bitmap
+ var bits = oldBits
+ if (bits == null || bits.width != w || bits.height != h) {
+ bits = Bitmap.createBitmap(
+ w,
+ h,
+ Bitmap.Config.ARGB_8888
+ )
+ }
+ if (bits == null) return
+
+ val c = Canvas(bits)
+
+ if (oldBits != null) {
+ if (oldBits.width < oldBits.height != bits.width < bits.height) {
+ // orientation change. let's rotate things so they fit better
+ val matrix = Matrix()
+ if (bits.width > bits.height) {
+ // now landscape
+ matrix.postRotate(-90f)
+ matrix.postTranslate(0f, bits.height.toFloat())
+ } else {
+ // now portrait
+ matrix.postRotate(90f)
+ matrix.postTranslate(bits.width.toFloat(), 0f)
+ }
+ if (bits.width != oldBits.height || bits.height != oldBits.width) {
+ matrix.postScale(
+ bits.width.toFloat()/oldBits.height,
+ bits.height.toFloat()/oldBits.width)
+ }
+ c.matrix = matrix
+ }
+ // paint the old artwork atop the new
+ c.drawBitmap(oldBits, 0f, 0f, _drawPaint)
+ c.matrix = Matrix()
+ } else {
+ c.drawColor(paperColor)
+ }
+
+ bitmap = bits
+ _paintCanvas = c
+ }
+
+ fun invertContents() {
+ val invertPaint = Paint()
+ invertPaint.colorFilter = INVERT_CF
+ synchronized(_bitmapLock) {
+ _paintCanvas?.drawBitmap(bitmap, 0f, 0f, invertPaint)
+ }
+ invalidate()
+ }
+}
+
diff --git a/packages/EasterEgg/src/com/android/egg/paint/Palette.kt b/packages/EasterEgg/src/com/android/egg/paint/Palette.kt
new file mode 100644
index 0000000..7043efe
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/paint/Palette.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2018 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.egg.paint
+
+import android.graphics.Color
+
+class Palette {
+ var colors : IntArray
+ var lightest = 0
+ var darkest = 0
+
+ /**
+ * rough luminance calculation
+ * https://www.w3.org/TR/AERT/#color-contrast
+ */
+ private fun lum(rgb: Int): Float {
+ return (Color.red(rgb) * 299f + Color.green(rgb) * 587f + Color.blue(rgb) * 114f) / 1000f
+ }
+
+ /**
+ * create a random evenly-spaced color palette
+ * guaranteed to contrast!
+ */
+ fun randomize(S: Float, V: Float) {
+ val hsv = floatArrayOf((Math.random() * 360f).toFloat(), S, V)
+ val count = colors.size
+ colors[0] = Color.HSVToColor(hsv)
+ lightest = 0
+ darkest = 0
+
+ for (i in 0 until count) {
+ hsv[0] = (hsv[0] + 360f / count).rem(360f)
+ val color = Color.HSVToColor(hsv)
+ colors[i] = color
+
+ val lum = lum(colors[i])
+ if (lum < lum(colors[darkest])) darkest = i
+ if (lum > lum(colors[lightest])) lightest = i
+ }
+ }
+
+ override fun toString() : String {
+ val str = StringBuilder("Palette{ ")
+ for (c in colors) {
+ str.append(String.format("#%08x ", c))
+ }
+ str.append("}")
+ return str.toString()
+ }
+
+ constructor(count: Int) {
+ colors = IntArray(count)
+ randomize(1f, 1f)
+ }
+
+ constructor(count: Int, S: Float, V: Float) {
+ colors = IntArray(count)
+ randomize(S, V)
+ }
+
+ constructor(_colors: IntArray) {
+ colors = _colors
+ for (i in 0 until colors.size) {
+ val lum = lum(colors[i])
+ if (lum < lum(colors[darkest])) darkest = i
+ if (lum > lum(colors[lightest])) lightest = i
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/EasterEgg/src/com/android/egg/paint/SpotFilter.kt b/packages/EasterEgg/src/com/android/egg/paint/SpotFilter.kt
new file mode 100644
index 0000000..2c15c0d
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/paint/SpotFilter.kt
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2018 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.egg.paint
+
+import java.util.LinkedList
+
+import android.view.MotionEvent
+
+class SpotFilter(internal var mBufSize: Int, posDecay: Float, pressureDecay: Float, internal var mPlotter: Plotter) {
+ val spots = LinkedList<MotionEvent.PointerCoords>() // newest at front
+ val tmpSpot = MotionEvent.PointerCoords()
+ var lastTool = MotionEvent.TOOL_TYPE_UNKNOWN
+
+ val posDecay: Float
+ val pressureDecay: Float
+
+ interface Plotter {
+ fun plot(s: MotionEvent.PointerCoords)
+ }
+
+ init {
+ this.posDecay = if (posDecay in 0f..1f) posDecay else 1f
+ this.pressureDecay = if (pressureDecay in 0f..1f) pressureDecay else 1f
+ }
+
+ fun filterInto(out: MotionEvent.PointerCoords, tool: Int): MotionEvent.PointerCoords {
+ lastTool = tool
+
+ var wi = 1f // weight for ith component (position)
+ var w = 0f // total weight
+ var wi_press = 1f // weight for ith component (pressure)
+ var w_press = 0f // total weight (pressure)
+
+ var x = 0f
+ var y = 0f
+ var pressure = 0f
+ var size = 0f
+ for (pi in spots) {
+ x += pi.x * wi
+ y += pi.y * wi
+
+ pressure += pi.pressure * wi_press
+ size += pi.size * wi_press
+
+ w += wi
+ wi *= posDecay // exponential backoff
+
+ w_press += wi_press
+ wi_press *= pressureDecay
+
+ if (PRECISE_STYLUS_INPUT && tool == MotionEvent.TOOL_TYPE_STYLUS) {
+ // just take the newest one, no need to average
+ break
+ }
+ }
+
+ out.x = x / w
+ out.y = y / w
+ out.pressure = pressure / w_press
+ out.size = size / w_press
+ return out
+ }
+
+ protected fun addInternal(c: MotionEvent.PointerCoords, tool: Int) {
+ val coord =
+ if (spots.size == mBufSize) {
+ spots.removeLast()
+ } else {
+ MotionEvent.PointerCoords()
+ }
+ coord.copyFrom(c)
+
+ spots.add(0, coord)
+
+ filterInto(tmpSpot, tool)
+ mPlotter.plot(tmpSpot)
+ }
+
+ fun add(cv: List<MotionEvent.PointerCoords>, tool: Int) {
+ for (c in cv) {
+ addInternal(c, tool)
+ }
+ }
+
+ fun add(evt: MotionEvent) {
+ val tool = evt.getToolType(0)
+ for (i in 0 until evt.historySize) {
+ evt.getHistoricalPointerCoords(0, i, tmpSpot)
+ addInternal(tmpSpot, tool)
+ }
+ evt.getPointerCoords(0, tmpSpot)
+ addInternal(tmpSpot, tool)
+ }
+
+ fun finish() {
+ while (spots.size > 0) {
+ filterInto(tmpSpot, lastTool)
+ spots.removeLast()
+ mPlotter.plot(tmpSpot)
+ }
+
+ spots.clear()
+ }
+
+ companion object {
+ var PRECISE_STYLUS_INPUT = true
+ }
+}
+
+
diff --git a/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt b/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt
new file mode 100644
index 0000000..86b11e7
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2018 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.egg.paint
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.Rect
+import android.graphics.drawable.Drawable
+import android.text.TextPaint
+import android.transition.ChangeBounds
+import android.transition.Transition
+import android.transition.TransitionListenerAdapter
+import android.transition.TransitionManager
+import android.util.AttributeSet
+import android.view.*
+import android.view.animation.OvershootInterpolator
+import android.widget.FrameLayout
+
+class ToolbarView : FrameLayout {
+ var inTransition = false
+ var transitionListener: Transition.TransitionListener = object : TransitionListenerAdapter() {
+ override fun onTransitionStart(transition: Transition?) {
+ inTransition = true
+ }
+ override fun onTransitionEnd(transition: Transition?) {
+ inTransition = false
+ }
+ }
+
+ constructor(context: Context) : super(context) {
+ init(null, 0)
+ }
+
+ constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
+ init(attrs, 0)
+ }
+
+ constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
+ init(attrs, defStyle)
+ }
+
+ override fun onApplyWindowInsets(insets: WindowInsets?): WindowInsets {
+ var lp = layoutParams as FrameLayout.LayoutParams?
+ if (lp != null && insets != null) {
+ if (insets.hasStableInsets()) {
+ lp.topMargin = insets.stableInsetTop
+ lp.bottomMargin = insets.stableInsetBottom
+ } else {
+ lp.topMargin = insets.systemWindowInsetTop
+ lp.bottomMargin = insets.systemWindowInsetBottom
+ }
+ layoutParams = lp
+ }
+
+ return super.onApplyWindowInsets(insets)
+ }
+
+ private fun init(attrs: AttributeSet?, defStyle: Int) {
+ }
+
+}
diff --git a/packages/ExtServices/res/values/strings.xml b/packages/ExtServices/res/values/strings.xml
index 72647ab..617e49a 100644
--- a/packages/ExtServices/res/values/strings.xml
+++ b/packages/ExtServices/res/values/strings.xml
@@ -18,7 +18,6 @@
<string name="app_name">Android Services Library</string>
<string name="notification_assistant">Notification Assistant</string>
- <string name="prompt_block_reason">Too many dismissals:views</string>
<string name="autofill_field_classification_default_algorithm">EDIT_DISTANCE</string>
<string-array name="autofill_field_classification_available_algorithms">
diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
index f878822..fdd6a9c 100644
--- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java
+++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
@@ -292,8 +292,7 @@
if (DEBUG) Log.d(TAG, "User probably doesn't want " + key);
Bundle signals = new Bundle();
signals.putInt(Adjustment.KEY_USER_SENTIMENT, USER_SENTIMENT_NEGATIVE);
- return new Adjustment(packageName, key, signals,
- getContext().getString(R.string.prompt_block_reason), user);
+ return new Adjustment(packageName, key, signals, "", user);
}
// for testing
diff --git a/packages/InputDevices/res/values-in/strings.xml b/packages/InputDevices/res/values-in/strings.xml
index 0c3bd7e..16b2010 100644
--- a/packages/InputDevices/res/values-in/strings.xml
+++ b/packages/InputDevices/res/values-in/strings.xml
@@ -31,7 +31,7 @@
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Islandia"</string>
<string name="keyboard_layout_brazilian" msgid="5117896443147781939">"Brasil"</string>
<string name="keyboard_layout_portuguese" msgid="2888198587329660305">"Portugis"</string>
- <string name="keyboard_layout_slovak" msgid="2469379934672837296">"Slowakia"</string>
+ <string name="keyboard_layout_slovak" msgid="2469379934672837296">"Slovakia"</string>
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovenia"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turki"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukraina"</string>
diff --git a/packages/PrintSpooler/res/values-hy/strings.xml b/packages/PrintSpooler/res/values-hy/strings.xml
index 56045be..0009397 100644
--- a/packages/PrintSpooler/res/values-hy/strings.xml
+++ b/packages/PrintSpooler/res/values-hy/strings.xml
@@ -99,8 +99,8 @@
<item msgid="79513688117503758">"Կարճեզր"</item>
</string-array>
<string-array name="orientation_labels">
- <item msgid="4061931020926489228">"Դիմանկար"</item>
- <item msgid="3199660090246166812">"Լանդշաֆտ"</item>
+ <item msgid="4061931020926489228">"Ուղղաձիգ"</item>
+ <item msgid="3199660090246166812">"Հորիզոնական"</item>
</string-array>
<string name="print_write_error_message" msgid="5787642615179572543">"Հնարավոր չէ գրել ֆայլում"</string>
<string name="print_error_default_message" msgid="8602678405502922346">"Չհաջողվեց: Նորից փորձեք:"</string>
diff --git a/packages/PrintSpooler/res/values-km/strings.xml b/packages/PrintSpooler/res/values-km/strings.xml
index ed8219e..c878ebe 100644
--- a/packages/PrintSpooler/res/values-km/strings.xml
+++ b/packages/PrintSpooler/res/values-km/strings.xml
@@ -27,7 +27,7 @@
<string name="label_duplex" msgid="5370037254347072243">"សងខាង"</string>
<string name="label_orientation" msgid="2853142581990496477">"ទិស"</string>
<string name="label_pages" msgid="7768589729282182230">"ទំព័រ"</string>
- <string name="destination_default_text" msgid="5422708056807065710">"ជ្រើសម៉ាស៊ីនបោះពុម្ព"</string>
+ <string name="destination_default_text" msgid="5422708056807065710">"ជ្រើសរើសម៉ាស៊ីនបោះពុម្ព"</string>
<string name="template_all_pages" msgid="3322235982020148762">"<xliff:g id="PAGE_COUNT">%1$s</xliff:g> ទាំងអស់"</string>
<string name="template_page_range" msgid="428638530038286328">"ជួរនៃ <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
<string name="pages_range_example" msgid="8558694453556945172">"ឧ. 1—5,8,11—13"</string>
@@ -103,7 +103,7 @@
<item msgid="3199660090246166812">"ផ្ដេក"</item>
</string-array>
<string name="print_write_error_message" msgid="5787642615179572543">"មិនអាចសរសេរទៅកាន់ឯកសារ"</string>
- <string name="print_error_default_message" msgid="8602678405502922346">"សូមទោស វាមិនដំណើរការទេ។ ព្យាយាមម្ដងទៀត។"</string>
+ <string name="print_error_default_message" msgid="8602678405502922346">"សូមអភ័យទោស វាមិនដំណើរការទេ។ ព្យាយាមម្ដងទៀត។"</string>
<string name="print_error_retry" msgid="1426421728784259538">"ព្យាយាមម្ដងទៀត"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"ឥឡូវនេះ ម៉ាស៊ីនបោះពុម្ពនេះមិនអាចប្រើបាន។"</string>
<string name="print_cannot_load_page" msgid="6179560924492912009">"មិនអាចបង្ហាញការមើលជាមុនបានទេ"</string>
diff --git a/packages/PrintSpooler/res/values-sw/strings.xml b/packages/PrintSpooler/res/values-sw/strings.xml
index 8aaf6f4..12f5b60 100644
--- a/packages/PrintSpooler/res/values-sw/strings.xml
+++ b/packages/PrintSpooler/res/values-sw/strings.xml
@@ -103,7 +103,7 @@
<item msgid="3199660090246166812">"Mlalo"</item>
</string-array>
<string name="print_write_error_message" msgid="5787642615179572543">"Haikuweza kuandika kwenye faili"</string>
- <string name="print_error_default_message" msgid="8602678405502922346">"Samahani, hiyo haikufanya kazi. Jaribu tena."</string>
+ <string name="print_error_default_message" msgid="8602678405502922346">"Samahani, imeshindwa kufanya kazi. Jaribu tena."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Jaribu tena"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Printa hii haipatikani kwa sasa."</string>
<string name="print_cannot_load_page" msgid="6179560924492912009">"Haiwezi kupakia onyesho la kuchungulia"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index d8137b4..e3b4bc9 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -224,8 +224,7 @@
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"ব্লুটুথ অডিঅ\' চ্চেনেল ম\'ড"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="7234956835280563341">"ব্লুটুথ অডিঅ\' ক\'ডেকৰ বাছনি\nআৰম্ভ কৰক: চ্চেনেল ম\'ড"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"ব্লুটুথ অডিঅ’ LDAC ক’ডেক: পৰিৱেশনৰ মান"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (6893955536658137179) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="6893955536658137179">"ব্লুটুথ অডিঅ\' LDAC\nক\'ডেক বাছনি আৰম্ভ কৰক: প্লেবেকৰ গুণগত মান"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"ষ্ট্ৰীম কৰি থকা হৈছে: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"ব্যক্তিগত DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"ব্যক্তিগত DNS ম\'ড বাছনি কৰক"</string>
@@ -366,18 +365,12 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"ৰং শুধৰণী"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"এই সুবিধাটো পৰীক্ষামূলক, সেয়ে ই কাৰ্যক্ষমতাৰ ওপৰত প্ৰভাৱ পেলাব পাৰে।"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g>ৰ দ্বাৰা অগ্ৰাহ্য কৰা হৈছে"</string>
- <!-- no translation found for power_remaining_settings_home_page (4845022416859002011) -->
- <skip />
- <!-- no translation found for power_remaining_duration_only (6123167166221295462) -->
- <skip />
- <!-- no translation found for power_discharging_duration (8848256785736335185) -->
- <skip />
- <!-- no translation found for power_remaining_duration_only_enhanced (4189311599812296592) -->
- <skip />
- <!-- no translation found for power_discharging_duration_enhanced (1992003260664804080) -->
- <skip />
- <!-- no translation found for power_remaining_duration_only_short (3463575350656389957) -->
- <skip />
+ <string name="power_remaining_settings_home_page" msgid="4845022416859002011">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="6123167166221295462">"প্রায় <xliff:g id="TIME_REMAINING">%1$s</xliff:g> বাকী আছে"</string>
+ <string name="power_discharging_duration" msgid="8848256785736335185">"প্রায় <xliff:g id="TIME_REMAINING">%1$s</xliff:g> বাকী আছে (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
+ <string name="power_remaining_duration_only_enhanced" msgid="4189311599812296592">"আপোনাৰ ব্যৱহাৰৰ ওপৰত ভিত্তি কৰি প্ৰায় <xliff:g id="TIME_REMAINING">%1$s</xliff:g> বাকী আছে"</string>
+ <string name="power_discharging_duration_enhanced" msgid="1992003260664804080">"আপোনাৰ ব্যৱহাৰৰ ওপৰত ভিত্তি কৰি প্রায় <xliff:g id="TIME_REMAINING">%1$s</xliff:g> বাকী আছে (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
+ <string name="power_remaining_duration_only_short" msgid="3463575350656389957">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> বাকী আছে"</string>
<string name="power_discharge_by_enhanced" msgid="2095821536747992464">"আপোনাৰ ব্যৱহাৰৰ ওপৰত ভিত্তি কৰি বেটাৰি আনুমানিকভাৱে <xliff:g id="TIME">%1$s</xliff:g> লৈকে চলিব (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"আপোনাৰ ব্যৱহাৰৰ ওপৰত ভিত্তি কৰি বেটাৰি আনুমানিকভাৱে <xliff:g id="TIME">%1$s</xliff:g> লৈকে চলিব"</string>
<string name="power_discharge_by" msgid="6453537733650125582">"বেটাৰি আনুমানিকভাৱে <xliff:g id="TIME">%1$s</xliff:g> লৈকে চলিব (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 98a95c2..66f5c07 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -278,7 +278,7 @@
<string name="media_category" msgid="4388305075496848353">"মিডিয়া"</string>
<string name="debug_monitoring_category" msgid="7640508148375798343">"পর্যবেক্ষণে রাখা"</string>
<string name="strict_mode" msgid="1938795874357830695">"কঠোর মোড সক্ষম"</string>
- <string name="strict_mode_summary" msgid="142834318897332338">"মুখ্য থ্রেডে অ্যাপ্লিকেশানগুলির দীর্ঘ কার্যকলাপের সময় স্ক্রিন ফ্ল্যাশ করে"</string>
+ <string name="strict_mode_summary" msgid="142834318897332338">"মুখ্য থ্রেডে অ্যাপ্লিকেশানগুলির দীর্ঘ অ্যাক্টিভিটির সময় স্ক্রিন ফ্ল্যাশ করে"</string>
<string name="pointer_location" msgid="6084434787496938001">"পয়েন্টারের লোকেশন"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"স্ক্রিন ওভারলে বর্তমান স্পর্শ ডেটা দেখাচ্ছে"</string>
<string name="show_touches" msgid="2642976305235070316">"আলতো চাপ দেখান"</string>
@@ -302,7 +302,7 @@
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"সমস্ত স্থানের জন্য RTL এ স্ক্রিন লেআউট দিকনির্দেশে জোর দেয়"</string>
<string name="force_msaa" msgid="7920323238677284387">"4x MSAA এ জোর দিন"</string>
<string name="force_msaa_summary" msgid="9123553203895817537">"OpenGL ES 2.0 অ্যাপ্লিকেশানগুলির মধ্যে 4x MSAA সক্রিয় করুন"</string>
- <string name="show_non_rect_clip" msgid="505954950474595172">"অ-আয়তক্ষেত্রাকার ক্লিপ কার্যকলাপ ডিবাগ করুন"</string>
+ <string name="show_non_rect_clip" msgid="505954950474595172">"অ-আয়তক্ষেত্রাকার ক্লিপ অ্যাক্টিভিটি ডিবাগ করুন"</string>
<string name="track_frame_time" msgid="6094365083096851167">"প্রোফাইল HWUI রেন্ডারিং"</string>
<string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU ডিবাগ স্তর সক্ষম করুন"</string>
<string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"ডিবাগ অ্যাপের জন্য GPU ডিবাগ স্তর লোড হতে দিন"</string>
@@ -311,8 +311,8 @@
<string name="animator_duration_scale_title" msgid="3406722410819934083">"অ্যানিমেটর সময়কাল স্কেল"</string>
<string name="overlay_display_devices_title" msgid="5364176287998398539">"গৌণ প্রদর্শনগুলি নকল করুন"</string>
<string name="debug_applications_category" msgid="4206913653849771549">"অ্যাপ"</string>
- <string name="immediately_destroy_activities" msgid="1579659389568133959">"কার্যকলাপ রাখবেন না"</string>
- <string name="immediately_destroy_activities_summary" msgid="3592221124808773368">"ব্যবহারকারী এটি ছেড়ে যাওয়ার পরে যত তাড়াতাড়ি সম্ভব প্রতিটি কার্যকলাপ ধ্বংস করুন"</string>
+ <string name="immediately_destroy_activities" msgid="1579659389568133959">"অ্যাক্টিভিটি রাখবেন না"</string>
+ <string name="immediately_destroy_activities_summary" msgid="3592221124808773368">"ব্যবহারকারী এটি ছেড়ে যাওয়ার পরে যত তাড়াতাড়ি সম্ভব প্রতিটি অ্যাক্টিভিটি ধ্বংস করুন"</string>
<string name="app_process_limit_title" msgid="4280600650253107163">"পশ্চাদপট প্রক্রিয়ার সীমা"</string>
<string name="show_all_anrs" msgid="4924885492787069007">"ব্যাকগ্রাউন্ডের ANR দেখুন"</string>
<string name="show_all_anrs_summary" msgid="6636514318275139826">"ব্যাকগ্রাউন্ডের অ্যাপগুলির জন্য \'অ্যাপ থেকে সাড়া পাওয়া যাচ্ছে না\' মেসেজ দেখান"</string>
diff --git a/packages/SettingsLib/res/values-gl/arrays.xml b/packages/SettingsLib/res/values-gl/arrays.xml
index a25d136..c6c4a2e 100644
--- a/packages/SettingsLib/res/values-gl/arrays.xml
+++ b/packages/SettingsLib/res/values-gl/arrays.xml
@@ -209,15 +209,15 @@
<item msgid="1606809880904982133">"Ningunha"</item>
<item msgid="9033194758688161545">"480 p"</item>
<item msgid="1025306206556583600">"480 p (seguro)"</item>
- <item msgid="1853913333042744661">"720 p"</item>
- <item msgid="3414540279805870511">"720 p (seguro)"</item>
+ <item msgid="1853913333042744661">"720p"</item>
+ <item msgid="3414540279805870511">"720p (seguro)"</item>
<item msgid="9039818062847141551">"1080 p"</item>
<item msgid="4939496949750174834">"1080 p (seguro)"</item>
<item msgid="1833612718524903568">"4K"</item>
<item msgid="238303513127879234">"4K (seguro)"</item>
<item msgid="3547211260846843098">"4K (mellorado)"</item>
<item msgid="5411365648951414254">"4K (mellorado e seguro)"</item>
- <item msgid="1311305077526792901">"720 p, 1080 p (pantalla dual)"</item>
+ <item msgid="1311305077526792901">"720p, 1080p (pantalla dual)"</item>
</string-array>
<string-array name="enable_opengl_traces_entries">
<item msgid="3191973083884253830">"Ningún"</item>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index c84875e..987d075 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -224,8 +224,7 @@
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"ବ୍ଲୁ-ଟୂଥ୍ ଅଡିଓ ଚ୍ୟାନେଲ୍ ମୋଡ୍"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="7234956835280563341">"ବ୍ଲୁ-ଟୂଥ୍ ଅଡିଓ କୋଡେକ୍\nସିଲେକ୍ସନ୍କୁ ଗତିଶୀଳ କରନ୍ତୁ: ଚ୍ୟାନେଲ୍ ମୋଡ୍"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"ବ୍ଲୁ-ଟୂଥ୍ ଅଡିଓ LDAC କୋଡେକ୍: ପ୍ଲେବ୍ୟାକ୍ ଗୁଣବତ୍ତା"</string>
- <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (6893955536658137179) -->
- <skip />
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="6893955536658137179">"ବ୍ଲୁ-ଟୁଥ୍ ଅଡିଓ LDAC\nକୋଡେକ୍ ଚୟନକୁ ଗତିଶୀଳ କରନ୍ତୁ: ପ୍ଲେବ୍ୟାକ୍ କ୍ୱାଲିଟୀ"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"ଷ୍ଟ୍ରିମ୍ କରୁଛି: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"ବ୍ୟକ୍ତିଗତ DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"ବ୍ୟକ୍ତିଗତ DNS ମୋଡ୍ ବାଛନ୍ତୁ"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index d1726d3..dd623d0 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -195,7 +195,7 @@
<string name="bugreport_in_power" msgid="7923901846375587241">"Atalho para relatório do bug"</string>
<string name="bugreport_in_power_summary" msgid="1778455732762984579">"Mostrar um botão para gerar relatórios de bugs no menu do botão liga/desliga"</string>
<string name="keep_screen_on" msgid="1146389631208760344">"Permanecer ativo"</string>
- <string name="keep_screen_on_summary" msgid="2173114350754293009">"A tela nunca entrará em inatividade enquanto estiver carregando."</string>
+ <string name="keep_screen_on_summary" msgid="2173114350754293009">"A tela nunca entrará em suspensão enquanto estiver carregando."</string>
<string name="bt_hci_snoop_log" msgid="3340699311158865670">"Ativar log de rastreamento Bluetooth HCI"</string>
<string name="bt_hci_snoop_log_summary" msgid="366083475849911315">"Capturar todos os pacotes Bluetooth HCI em um arquivo (ative o Bluetooth depois de alterar esta configuração)"</string>
<string name="oem_unlock_enable" msgid="6040763321967327691">"Desbloqueio de OEM"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index d1726d3..dd623d0 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -195,7 +195,7 @@
<string name="bugreport_in_power" msgid="7923901846375587241">"Atalho para relatório do bug"</string>
<string name="bugreport_in_power_summary" msgid="1778455732762984579">"Mostrar um botão para gerar relatórios de bugs no menu do botão liga/desliga"</string>
<string name="keep_screen_on" msgid="1146389631208760344">"Permanecer ativo"</string>
- <string name="keep_screen_on_summary" msgid="2173114350754293009">"A tela nunca entrará em inatividade enquanto estiver carregando."</string>
+ <string name="keep_screen_on_summary" msgid="2173114350754293009">"A tela nunca entrará em suspensão enquanto estiver carregando."</string>
<string name="bt_hci_snoop_log" msgid="3340699311158865670">"Ativar log de rastreamento Bluetooth HCI"</string>
<string name="bt_hci_snoop_log_summary" msgid="366083475849911315">"Capturar todos os pacotes Bluetooth HCI em um arquivo (ative o Bluetooth depois de alterar esta configuração)"</string>
<string name="oem_unlock_enable" msgid="6040763321967327691">"Desbloqueio de OEM"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 77de8db..a421c72 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -56,7 +56,7 @@
<string name="bluetooth_disconnecting" msgid="8913264760027764974">"Отключение..."</string>
<string name="bluetooth_connecting" msgid="8555009514614320497">"Подключение..."</string>
<string name="bluetooth_connected" msgid="5427152882755735944">"Подключено<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
- <string name="bluetooth_pairing" msgid="1426882272690346242">"Сопряжение..."</string>
+ <string name="bluetooth_pairing" msgid="1426882272690346242">"Устанавливается соединение..."</string>
<string name="bluetooth_connected_no_headset" msgid="616068069034994802">"Подключено (кроме звонков)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
<string name="bluetooth_connected_no_a2dp" msgid="3736431800395923868">"Подключено (кроме аудио)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
<string name="bluetooth_connected_no_map" msgid="3200033913678466453">"Подключено (кроме сообщений)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
@@ -102,11 +102,11 @@
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Добавить"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ДОБАВИТЬ"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Отмена"</string>
- <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Сопряжение обеспечивает доступ к вашим контактам и журналу звонков при подключении."</string>
- <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Не удалось установить сопряжение с устройством \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\"."</string>
- <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Не удалось установить сопряжение с устройством \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\", так как введен неверный PIN-код или пароль."</string>
+ <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Установление соединения обеспечивает доступ к вашим контактам и журналу звонков при подключении."</string>
+ <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Не удалось подключиться к устройству \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\"."</string>
+ <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Не удалось подключиться к устройству \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\", так как введен неверный PIN-код или пароль."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Не удается установить соединение с устройством \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\"."</string>
- <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> не разрешает сопряжение."</string>
+ <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> не разрешает подключение."</string>
<string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Компьютер"</string>
<string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Гарнитура"</string>
<string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Телефон"</string>
diff --git a/packages/SettingsLib/res/values-sw/arrays.xml b/packages/SettingsLib/res/values-sw/arrays.xml
index f13c2ea..fdf9fd1 100644
--- a/packages/SettingsLib/res/values-sw/arrays.xml
+++ b/packages/SettingsLib/res/values-sw/arrays.xml
@@ -59,7 +59,7 @@
<item msgid="45075631231212732">"Kila wakati tumia ukakuaji wa HDCP"</item>
</string-array>
<string-array name="bluetooth_avrcp_versions">
- <item msgid="5347678900838034763">"AVRCP 1.4 (Chaguo msingi)"</item>
+ <item msgid="5347678900838034763">"AVRCP 1.4 (Chaguomsingi)"</item>
<item msgid="2809759619990248160">"AVRCP 1.3"</item>
<item msgid="6199178154704729352">"AVRCP 1.5"</item>
<item msgid="5172170854953034852">"AVRCP 1.6"</item>
@@ -71,7 +71,7 @@
<item msgid="3422726142222090896">"avrcp16"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_titles">
- <item msgid="7065842274271279580">"Tumia Uteuzi wa Mfumo (Chaguo msingi)"</item>
+ <item msgid="7065842274271279580">"Tumia Uteuzi wa Mfumo (Chaguomsingi)"</item>
<item msgid="7539690996561263909">"SBC"</item>
<item msgid="686685526567131661">"AAC"</item>
<item msgid="5254942598247222737">"Sauti ya <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
@@ -81,7 +81,7 @@
<item msgid="3304843301758635896">"Zima Kodeki Zisizo za Lazima"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_summaries">
- <item msgid="5062108632402595000">"Tumia Uteuzi wa Mfumo (Chaguo msingi)"</item>
+ <item msgid="5062108632402595000">"Tumia Uteuzi wa Mfumo (Chaguomsingi)"</item>
<item msgid="6898329690939802290">"SBC"</item>
<item msgid="6839647709301342559">"AAC"</item>
<item msgid="7848030269621918608">"Sauti ya <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
@@ -91,38 +91,38 @@
<item msgid="741805482892725657">"Zima Kodeki Zisizo za Lazima"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
- <item msgid="3093023430402746802">"Tumia Uteuzi wa Mfumo (Chaguo msingi)"</item>
+ <item msgid="3093023430402746802">"Tumia Uteuzi wa Mfumo (Chaguomsingi)"</item>
<item msgid="8895532488906185219">"kHz 44.1"</item>
<item msgid="2909915718994807056">"kHz 48.0"</item>
<item msgid="3347287377354164611">"kHz 88.2"</item>
<item msgid="1234212100239985373">"kHz 96.0"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
- <item msgid="3214516120190965356">"Tumia Uteuzi wa Mfumo (Chaguo msingi)"</item>
+ <item msgid="3214516120190965356">"Tumia Uteuzi wa Mfumo (Chaguomsingi)"</item>
<item msgid="4482862757811638365">"kHz 44.1"</item>
<item msgid="354495328188724404">"kHz 48.0"</item>
<item msgid="7329816882213695083">"kHz 88.2"</item>
<item msgid="6967397666254430476">"kHz 96.0"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
- <item msgid="2684127272582591429">"Tumia Uteuzi wa Mfumo (Chaguo msingi)"</item>
+ <item msgid="2684127272582591429">"Tumia Uteuzi wa Mfumo (Chaguomsingi)"</item>
<item msgid="5618929009984956469">"Biti 16 kwa kila sampuli"</item>
<item msgid="3412640499234627248">"Biti 24 kwa kila sampuli"</item>
<item msgid="121583001492929387">"Biti 32 kwa kila sampuli"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
- <item msgid="1081159789834584363">"Tumia Uteuzi wa Mfumo (Chaguo msingi)"</item>
+ <item msgid="1081159789834584363">"Tumia Uteuzi wa Mfumo (Chaguomsingi)"</item>
<item msgid="4726688794884191540">"Biti 16 kwa kila sampuli"</item>
<item msgid="305344756485516870">"Biti 24 kwa kila sampuli"</item>
<item msgid="244568657919675099">"Biti 32 kwa kila sampuli"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_channel_mode_titles">
- <item msgid="5226878858503393706">"Tumia Uteuzi wa Mfumo (Chaguo msingi)"</item>
+ <item msgid="5226878858503393706">"Tumia Uteuzi wa Mfumo (Chaguomsingi)"</item>
<item msgid="4106832974775067314">"Mono"</item>
<item msgid="5571632958424639155">"Stereo"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
- <item msgid="4118561796005528173">"Tumia Uteuzi wa Mfumo (Chaguo msingi)"</item>
+ <item msgid="4118561796005528173">"Tumia Uteuzi wa Mfumo (Chaguomsingi)"</item>
<item msgid="8900559293912978337">"Mono"</item>
<item msgid="8883739882299884241">"Stereo"</item>
</string-array>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 53f5d0c..2d752ea 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -138,7 +138,7 @@
<string name="user_guest" msgid="8475274842845401871">"Aliyealikwa"</string>
<string name="unknown" msgid="1592123443519355854">"Haijulikani"</string>
<string name="running_process_item_user_label" msgid="3129887865552025943">"Mtumiaji: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
- <string name="launch_defaults_some" msgid="313159469856372621">"Baadhi ya chaguo msingi zimewekwa"</string>
+ <string name="launch_defaults_some" msgid="313159469856372621">"Baadhi ya chaguomsingi zimewekwa"</string>
<string name="launch_defaults_none" msgid="4241129108140034876">"Hakuna chaguo-misingi zilizowekwa"</string>
<string name="tts_settings" msgid="8186971894801348327">"Mipangilio ya kusoma maandishi kwa sauti"</string>
<string name="tts_settings_title" msgid="1237820681016639683">"Kusoma maandishi kwa sauti"</string>
@@ -157,7 +157,7 @@
<string name="tts_engine_security_warning" msgid="8786238102020223650">"Hotuba hii inawezesha injini huenda ikaweza kukusanya maandishi ambayo yatazungumziwa, ikijumlisha data ya kibinafsi ya nenosiri na namba ya kaddi ya mkopo. Inatoka kwa injini ya <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g> Wezesha matumizi ya hotuba hii iliyowezeshwa ya injini?"</string>
<string name="tts_engine_network_required" msgid="1190837151485314743">"Lugha hii inahitaji muunganisho wa mtandao unaofanya kazi ili kipengele cha kusoma maandishi kwa sauti kifanye kazi."</string>
<string name="tts_default_sample_string" msgid="4040835213373086322">"Huu ni mfano wa usanisi usemaji"</string>
- <string name="tts_status_title" msgid="7268566550242584413">"Hali ya lugha chaguo msingi"</string>
+ <string name="tts_status_title" msgid="7268566550242584413">"Hali ya lugha chaguomsingi"</string>
<string name="tts_status_ok" msgid="1309762510278029765">"<xliff:g id="LOCALE">%1$s</xliff:g> inaweza kutumiwa kikamilifu"</string>
<string name="tts_status_requires_network" msgid="6042500821503226892">"<xliff:g id="LOCALE">%1$s</xliff:g> inahitaji muunganisho wa mtandao"</string>
<string name="tts_status_not_supported" msgid="4491154212762472495">"<xliff:g id="LOCALE">%1$s</xliff:g> haiwezi kutumiwa"</string>
@@ -167,7 +167,7 @@
<string name="tts_engine_preference_section_title" msgid="448294500990971413">"Injini inayofaa"</string>
<string name="tts_general_section_title" msgid="4402572014604490502">"Kwa ujumla"</string>
<string name="tts_reset_speech_pitch_title" msgid="5789394019544785915">"Weka upya mipangilio ya ubora wa matamshi"</string>
- <string name="tts_reset_speech_pitch_summary" msgid="8700539616245004418">"Rejesha mipangilio ya ubora wa matamshi kuwa ya chaguo msingi."</string>
+ <string name="tts_reset_speech_pitch_summary" msgid="8700539616245004418">"Rejesha mipangilio ya ubora wa matamshi kuwa ya chaguomsingi."</string>
<string-array name="tts_rate_entries">
<item msgid="6695494874362656215">"Polepole sana"</item>
<item msgid="4795095314303559268">"Polepole"</item>
@@ -331,7 +331,7 @@
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nenosiri jipya na uthibitisho havioani"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Imeshindwa kuweka nenosiri la hifadhi rudufu"</string>
<string-array name="color_mode_names">
- <item msgid="2425514299220523812">"Maridadi (chaguo msingi)"</item>
+ <item msgid="2425514299220523812">"Maridadi (chaguomsingi)"</item>
<item msgid="8446070607501413455">"Asili"</item>
<item msgid="6553408765810699025">"Muundo-msingi"</item>
</string-array>
@@ -410,7 +410,7 @@
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> zilizopita"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Zimesalia <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="screen_zoom_summary_small" msgid="5867245310241621570">"Ndogo"</string>
- <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Chaguo msingi"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Chaguomsingi"</string>
<string name="screen_zoom_summary_large" msgid="4835294730065424084">"Kubwa"</string>
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Kubwa kiasi"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Kubwa zaidi"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
index 955f64a..75c2533 100644
--- a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
@@ -381,7 +381,7 @@
// Create a lookup of local zone IDs.
final List<String> zoneIds = lookupTimeZoneIdsByCountry(locale.getCountry());
- localZoneIds = new HashSet<>(zoneIds);
+ localZoneIds = zoneIds != null ? new HashSet<>(zoneIds) : new HashSet<>();
}
@VisibleForTesting
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractWifiMacAddressPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractWifiMacAddressPreferenceController.java
index 89d2595..ffbda3a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractWifiMacAddressPreferenceController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractWifiMacAddressPreferenceController.java
@@ -38,6 +38,10 @@
@VisibleForTesting
static final String KEY_WIFI_MAC_ADDRESS = "wifi_mac_address";
+ @VisibleForTesting
+ static final int OFF = 0;
+ @VisibleForTesting
+ static final int ON = 1;
private static final String[] CONNECTIVITY_INTENTS = {
ConnectivityManager.CONNECTIVITY_ACTION,
@@ -80,13 +84,14 @@
protected void updateConnectivity() {
WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
final int macRandomizationMode = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED, 0);
+ Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED, OFF);
final String macAddress = wifiInfo == null ? null : wifiInfo.getMacAddress();
- if (TextUtils.isEmpty(macAddress)) {
- mWifiMacAddress.setSummary(R.string.status_unavailable);
- } else if (macRandomizationMode == 1 && WifiInfo.DEFAULT_MAC_ADDRESS.equals(macAddress)) {
+ if (macRandomizationMode == ON && WifiInfo.DEFAULT_MAC_ADDRESS.equals(macAddress)) {
mWifiMacAddress.setSummary(R.string.wifi_status_mac_randomized);
+ } else if (TextUtils.isEmpty(macAddress)
+ || WifiInfo.DEFAULT_MAC_ADDRESS.equals(macAddress)) {
+ mWifiMacAddress.setSummary(R.string.status_unavailable);
} else {
mWifiMacAddress.setSummary(macAddress);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java b/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
index f1d43bf..b55d2ef 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
@@ -16,6 +16,10 @@
package com.android.settingslib.drawer;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_KEY_PROFILE;
+import static com.android.settingslib.drawer.TileUtils.PROFILE_ALL;
+import static com.android.settingslib.drawer.TileUtils.PROFILE_PRIMARY;
+
import android.content.Intent;
import android.graphics.drawable.Icon;
import android.os.Bundle;
@@ -169,4 +173,11 @@
return new Tile[size];
}
};
+
+ public boolean isPrimaryProfileOnly() {
+ String profile = metaData != null ?
+ metaData.getString(META_DATA_KEY_PROFILE) : PROFILE_ALL;
+ profile = (profile != null ? profile : PROFILE_ALL);
+ return TextUtils.equals(profile, PROFILE_PRIMARY);
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
index 0f0e4e5..96ed0cd 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
@@ -34,8 +34,8 @@
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
-import android.widget.RemoteViews;
+import androidx.annotation.VisibleForTesting;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -96,11 +96,7 @@
/**
* The key used to get the category from metadata of activities of action
* {@link #EXTRA_SETTINGS_ACTION}
- * The value must be one of:
- * <li>com.android.settings.category.wireless</li>
- * <li>com.android.settings.category.device</li>
- * <li>com.android.settings.category.personal</li>
- * <li>com.android.settings.category.system</li>
+ * The value must be from {@link CategoryKey}.
*/
private static final String EXTRA_CATEGORY_KEY = "com.android.settings.category";
@@ -171,20 +167,37 @@
public static final String META_DATA_PREFERENCE_SUMMARY_URI =
"com.android.settings.summary_uri";
- /**
- * Name of the meta-data item that should be set in the AndroidManifest.xml to specify the
- * custom view which should be displayed for the preference. The custom view will be inflated
- * as a remote view.
- *
- * This also can be used with {@link #META_DATA_PREFERENCE_SUMMARY_URI}, by setting the id
- * of the summary TextView to '@android:id/summary'.
- */
- public static final String META_DATA_PREFERENCE_CUSTOM_VIEW =
- "com.android.settings.custom_view";
-
public static final String SETTING_PKG = "com.android.settings";
/**
+ * Value for {@link #META_DATA_KEY_PROFILE}. When the device has a managed profile,
+ * the app will always be run in the primary profile.
+ *
+ * @see #META_DATA_KEY_PROFILE
+ */
+ public static final String PROFILE_PRIMARY = "primary_profile_only";
+
+ /**
+ * Value for {@link #META_DATA_KEY_PROFILE}. When the device has a managed profile, the user
+ * will be presented with a dialog to choose the profile the app will be run in.
+ *
+ * @see #META_DATA_KEY_PROFILE
+ */
+ public static final String PROFILE_ALL = "all_profiles";
+
+ /**
+ * Name of the meta-data item that should be set in the AndroidManifest.xml
+ * to specify the profile in which the app should be run when the device has a managed profile.
+ * The default value is {@link #PROFILE_ALL} which means the user will be presented with a
+ * dialog to choose the profile. If set to {@link #PROFILE_PRIMARY} the app will always be
+ * run in the primary profile.
+ *
+ * @see #PROFILE_PRIMARY
+ * @see #PROFILE_ALL
+ */
+ public static final String META_DATA_KEY_PROFILE = "com.android.settings.profile";
+
+ /**
* Build a list of DashboardCategory. Each category must be defined in manifest.
* eg: .Settings$DeviceSettings
* @deprecated
@@ -442,11 +455,6 @@
keyHint = metaData.getString(META_DATA_PREFERENCE_KEYHINT);
}
}
- if (metaData.containsKey(META_DATA_PREFERENCE_CUSTOM_VIEW)) {
- int layoutId = metaData.getInt(META_DATA_PREFERENCE_CUSTOM_VIEW);
- tile.remoteViews = new RemoteViews(applicationInfo.packageName, layoutId);
- updateSummaryAndTitle(context, providerMap, tile);
- }
}
} catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) {
if (DEBUG) Log.d(LOG_TAG, "Couldn't find info", e);
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
index f7aa297..87f5b4f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
@@ -41,6 +41,7 @@
import android.util.Pair;
import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
import java.time.ZonedDateTime;
import java.util.Date;
@@ -86,7 +87,8 @@
* mContext.getResources().getInteger(R.integer.default_data_warning_level_mb);
}
- private INetworkStatsSession getSession() {
+ @VisibleForTesting
+ INetworkStatsSession getSession() {
if (mSession == null) {
try {
mSession = mStatsService.openSession();
@@ -176,6 +178,30 @@
}
}
+ /**
+ * Get the total usage level recorded in the network history
+ * @param template the network template to retrieve the network history
+ * @return the total usage level recorded in the network history
+ */
+ public long getHistoriclUsageLevel(NetworkTemplate template) {
+ final INetworkStatsSession session = getSession();
+ if (session != null) {
+ try {
+ final NetworkStatsHistory history = session.getHistoryForNetwork(template, FIELDS);
+ final long now = System.currentTimeMillis();
+ final NetworkStatsHistory.Entry entry =
+ history.getValues(0L /* start */, now /* end */, now, null /* recycle */);
+ if (entry != null) {
+ return entry.rxBytes + entry.txBytes;
+ }
+ Log.w(TAG, "Failed to get data usage, no entry data");
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to get data usage, remote call failed");
+ }
+ }
+ return 0L;
+ }
+
private NetworkPolicy findNetworkPolicy(NetworkTemplate template) {
if (mPolicyManager == null || template == null) return null;
final NetworkPolicy[] policies = mPolicyManager.getNetworkPolicies();
diff --git a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionList.java b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionList.java
deleted file mode 100644
index a890920..0000000
--- a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionList.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.suggestions;
-
-import android.content.Intent;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-
-import com.android.settingslib.drawer.Tile;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-public class SuggestionList {
- // Category -> list of suggestion map
- private final Map<SuggestionCategory, List<Tile>> mSuggestions;
-
- // A flatten list of all suggestions.
- private List<Tile> mSuggestionList;
-
- public SuggestionList() {
- mSuggestions = new ArrayMap<>();
- }
-
- public void addSuggestions(SuggestionCategory category, List<Tile> suggestions) {
- mSuggestions.put(category, suggestions);
- }
-
- public List<Tile> getSuggestions() {
- if (mSuggestionList != null) {
- return mSuggestionList;
- }
- mSuggestionList = new ArrayList<>();
- for (List<Tile> suggestions : mSuggestions.values()) {
- mSuggestionList.addAll(suggestions);
- }
- dedupeSuggestions(mSuggestionList);
- return mSuggestionList;
- }
-
- public boolean isExclusiveSuggestionCategory() {
- if (mSuggestions.size() != 1) {
- // If there is no category, or more than 1 category, it's not exclusive by definition.
- return false;
- }
- for (SuggestionCategory category : mSuggestions.keySet()) {
- if (category.exclusive) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Filter suggestions list so they are all unique.
- */
- private void dedupeSuggestions(List<Tile> suggestions) {
- final Set<String> intents = new ArraySet<>();
- for (int i = suggestions.size() - 1; i >= 0; i--) {
- final Tile suggestion = suggestions.get(i);
- final String intentUri = suggestion.intent.toUri(Intent.URI_INTENT_SCHEME);
- if (intents.contains(intentUri)) {
- suggestions.remove(i);
- } else {
- intents.add(intentUri);
- }
- }
- }
-}
diff --git a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java
deleted file mode 100644
index 8705c98..0000000
--- a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java
+++ /dev/null
@@ -1,498 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.settingslib.suggestions;
-
-import android.Manifest;
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.annotation.RequiresPermission;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
-import android.content.pm.UserInfo;
-import android.content.res.Resources;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-import androidx.annotation.VisibleForTesting;
-import android.text.TextUtils;
-import android.text.format.DateUtils;
-import android.util.ArrayMap;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.Pair;
-import android.util.Xml;
-import android.view.InflateException;
-
-import com.android.settingslib.drawer.Tile;
-import com.android.settingslib.drawer.TileUtils;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-public class SuggestionParser {
-
- private static final String TAG = "SuggestionParser";
-
- // If defined, only returns this suggestion if the feature is supported.
- public static final String META_DATA_REQUIRE_FEATURE = "com.android.settings.require_feature";
-
- // If defined, only display this optional step if an account of that type exists.
- private static final String META_DATA_REQUIRE_ACCOUNT = "com.android.settings.require_account";
-
- // If defined and not true, do not should optional step.
- private static final String META_DATA_IS_SUPPORTED = "com.android.settings.is_supported";
-
- // If defined, only display this optional step if the current user is of that type.
- private static final String META_DATA_REQUIRE_USER_TYPE =
- "com.android.settings.require_user_type";
-
- // If defined, only display this optional step if a connection is available.
- private static final String META_DATA_IS_CONNECTION_REQUIRED =
- "com.android.settings.require_connection";
-
- // The valid values that setup wizard recognizes for differentiating user types.
- private static final String META_DATA_PRIMARY_USER_TYPE_VALUE = "primary";
- private static final String META_DATA_ADMIN_USER_TYPE_VALUE = "admin";
- private static final String META_DATA_GUEST_USER_TYPE_VALUE = "guest";
- private static final String META_DATA_RESTRICTED_USER_TYPE_VALUE = "restricted";
-
- /**
- * Allows suggestions to appear after a certain number of days, and to re-appear if dismissed.
- * For instance:
- * 0,10
- * Will appear immediately, but if the user removes it, it will come back after 10 days.
- *
- * Another example:
- * 10,30
- * Will only show up after 10 days, and then again after 30.
- */
- public static final String META_DATA_DISMISS_CONTROL = "com.android.settings.dismiss";
-
- // Shared prefs keys for storing dismissed state.
- // Index into current dismissed state.
- public static final String SETUP_TIME = "_setup_time";
- private static final String IS_DISMISSED = "_is_dismissed";
-
- // Default dismiss control for smart suggestions.
- private static final String DEFAULT_SMART_DISMISS_CONTROL = "0";
-
- private final Context mContext;
- private final List<SuggestionCategory> mSuggestionList;
- private final ArrayMap<Pair<String, String>, Tile> mAddCache = new ArrayMap<>();
- private final SharedPreferences mSharedPrefs;
- private final String mDefaultDismissControl;
-
- public SuggestionParser(Context context, SharedPreferences sharedPrefs, int orderXml,
- String defaultDismissControl) {
- this(
- context,
- sharedPrefs,
- (List<SuggestionCategory>) new SuggestionOrderInflater(context).parse(orderXml),
- defaultDismissControl);
- }
-
- public SuggestionParser(Context context, SharedPreferences sharedPrefs, int orderXml) {
- this(context, sharedPrefs, orderXml, DEFAULT_SMART_DISMISS_CONTROL);
- }
-
- @VisibleForTesting
- public SuggestionParser(
- Context context,
- SharedPreferences sharedPrefs,
- List<SuggestionCategory> suggestionList,
- String defaultDismissControl) {
- mContext = context;
- mSuggestionList = suggestionList;
- mSharedPrefs = sharedPrefs;
- mDefaultDismissControl = defaultDismissControl;
- }
-
- public SuggestionList getSuggestions(boolean isSmartSuggestionEnabled) {
- final SuggestionList suggestionList = new SuggestionList();
- final int N = mSuggestionList.size();
- for (int i = 0; i < N; i++) {
- final SuggestionCategory category = mSuggestionList.get(i);
- if (category.exclusive && !isExclusiveCategoryExpired(category)) {
- // If suggestions from an exclusive category are present, parsing is stopped
- // and only suggestions from that category are displayed. Note that subsequent
- // exclusive categories are also ignored.
- final List<Tile> exclusiveSuggestions = new ArrayList<>();
-
- // Read suggestion and force isSmartSuggestion to be false so the rule defined
- // from each suggestion itself is used.
- readSuggestions(category, exclusiveSuggestions, false /* isSmartSuggestion */);
- if (!exclusiveSuggestions.isEmpty()) {
- final SuggestionList exclusiveList = new SuggestionList();
- exclusiveList.addSuggestions(category, exclusiveSuggestions);
- return exclusiveList;
- }
- } else {
- // Either the category is not exclusive, or the exclusiveness expired so we should
- // treat it as a normal category.
- final List<Tile> suggestions = new ArrayList<>();
- readSuggestions(category, suggestions, isSmartSuggestionEnabled);
- suggestionList.addSuggestions(category, suggestions);
- }
- }
- return suggestionList;
- }
-
- /**
- * Dismisses a suggestion, returns true if the suggestion has no more dismisses left and should
- * be disabled.
- */
- public boolean dismissSuggestion(Tile suggestion) {
- final String keyBase = suggestion.intent.getComponent().flattenToShortString();
- mSharedPrefs.edit()
- .putBoolean(keyBase + IS_DISMISSED, true)
- .commit();
- return true;
- }
-
- @VisibleForTesting
- public void filterSuggestions(
- List<Tile> suggestions, int countBefore, boolean isSmartSuggestionEnabled) {
- for (int i = countBefore; i < suggestions.size(); i++) {
- if (!isAvailable(suggestions.get(i)) ||
- !isSupported(suggestions.get(i)) ||
- !satisifesRequiredUserType(suggestions.get(i)) ||
- !satisfiesRequiredAccount(suggestions.get(i)) ||
- !satisfiesConnectivity(suggestions.get(i)) ||
- isDismissed(suggestions.get(i), isSmartSuggestionEnabled)) {
- suggestions.remove(i--);
- }
- }
- }
-
- @VisibleForTesting
- void readSuggestions(
- SuggestionCategory category, List<Tile> suggestions, boolean isSmartSuggestionEnabled) {
- int countBefore = suggestions.size();
- Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.addCategory(category.category);
- if (category.pkg != null) {
- intent.setPackage(category.pkg);
- }
- TileUtils.getTilesForIntent(mContext, new UserHandle(UserHandle.myUserId()), intent,
- mAddCache, null, suggestions, true, false, false, true /* shouldUpdateTiles */);
- filterSuggestions(suggestions, countBefore, isSmartSuggestionEnabled);
- if (!category.multiple && suggestions.size() > (countBefore + 1)) {
- // If there are too many, remove them all and only re-add the one with the highest
- // priority.
- Tile item = suggestions.remove(suggestions.size() - 1);
- while (suggestions.size() > countBefore) {
- Tile last = suggestions.remove(suggestions.size() - 1);
- if (last.priority > item.priority) {
- item = last;
- }
- }
- // If category is marked as done, do not add any item.
- if (!isCategoryDone(category.category)) {
- suggestions.add(item);
- }
- }
- }
-
- private boolean isAvailable(Tile suggestion) {
- final String featuresRequired = suggestion.metaData.getString(META_DATA_REQUIRE_FEATURE);
- if (featuresRequired != null) {
- for (String feature : featuresRequired.split(",")) {
- if (TextUtils.isEmpty(feature)) {
- Log.w(TAG, "Found empty substring when parsing required features: "
- + featuresRequired);
- } else if (!mContext.getPackageManager().hasSystemFeature(feature)) {
- Log.i(TAG, suggestion.title + " requires unavailable feature " + feature);
- return false;
- }
- }
- }
- return true;
- }
-
- @RequiresPermission(Manifest.permission.MANAGE_USERS)
- private boolean satisifesRequiredUserType(Tile suggestion) {
- final String requiredUser = suggestion.metaData.getString(META_DATA_REQUIRE_USER_TYPE);
- if (requiredUser != null) {
- final UserManager userManager = mContext.getSystemService(UserManager.class);
- UserInfo userInfo = userManager.getUserInfo(UserHandle.myUserId());
- for (String userType : requiredUser.split("\\|")) {
- final boolean primaryUserCondtionMet = userInfo.isPrimary()
- && META_DATA_PRIMARY_USER_TYPE_VALUE.equals(userType);
- final boolean adminUserConditionMet = userInfo.isAdmin()
- && META_DATA_ADMIN_USER_TYPE_VALUE.equals(userType);
- final boolean guestUserCondtionMet = userInfo.isGuest()
- && META_DATA_GUEST_USER_TYPE_VALUE.equals(userType);
- final boolean restrictedUserCondtionMet = userInfo.isRestricted()
- && META_DATA_RESTRICTED_USER_TYPE_VALUE.equals(userType);
- if (primaryUserCondtionMet || adminUserConditionMet || guestUserCondtionMet
- || restrictedUserCondtionMet) {
- return true;
- }
- }
- Log.i(TAG, suggestion.title + " requires user type " + requiredUser);
- return false;
- }
- return true;
- }
-
- public boolean satisfiesRequiredAccount(Tile suggestion) {
- final String requiredAccountType = suggestion.metaData.getString(META_DATA_REQUIRE_ACCOUNT);
- if (requiredAccountType == null) {
- return true;
- }
- AccountManager accountManager = mContext.getSystemService(AccountManager.class);
- Account[] accounts = accountManager.getAccountsByType(requiredAccountType);
- boolean satisfiesRequiredAccount = accounts.length > 0;
- if (!satisfiesRequiredAccount) {
- Log.i(TAG, suggestion.title + " requires unavailable account type "
- + requiredAccountType);
- }
- return satisfiesRequiredAccount;
- }
-
- public boolean isSupported(Tile suggestion) {
- final int isSupportedResource = suggestion.metaData.getInt(META_DATA_IS_SUPPORTED);
- try {
- if (suggestion.intent == null) {
- return false;
- }
- final Resources res = mContext.getPackageManager().getResourcesForActivity(
- suggestion.intent.getComponent());
- boolean isSupported =
- isSupportedResource != 0 ? res.getBoolean(isSupportedResource) : true;
- if (!isSupported) {
- Log.i(TAG, suggestion.title + " requires unsupported resource "
- + isSupportedResource);
- }
- return isSupported;
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "Cannot find resources for " + suggestion.intent.getComponent());
- return false;
- } catch (Resources.NotFoundException e) {
- Log.w(TAG, "Cannot find resources for " + suggestion.intent.getComponent(), e);
- return false;
- }
- }
-
- private boolean satisfiesConnectivity(Tile suggestion) {
- final boolean isConnectionRequired =
- suggestion.metaData.getBoolean(META_DATA_IS_CONNECTION_REQUIRED);
- if (!isConnectionRequired) {
- return true;
- }
- ConnectivityManager cm =
- (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo netInfo = cm.getActiveNetworkInfo();
- boolean satisfiesConnectivity = netInfo != null && netInfo.isConnectedOrConnecting();
- if (!satisfiesConnectivity) {
- Log.i(TAG, suggestion.title + " is missing required connection.");
- }
- return satisfiesConnectivity;
- }
-
- public boolean isCategoryDone(String category) {
- String name = Settings.Secure.COMPLETED_CATEGORY_PREFIX + category;
- return Settings.Secure.getInt(mContext.getContentResolver(), name, 0) != 0;
- }
-
- public void markCategoryDone(String category) {
- String name = Settings.Secure.COMPLETED_CATEGORY_PREFIX + category;
- Settings.Secure.putInt(mContext.getContentResolver(), name, 1);
- }
-
- /**
- * Whether or not the category's exclusiveness has expired.
- */
- private boolean isExclusiveCategoryExpired(SuggestionCategory category) {
- final String keySetupTime = category.category + SETUP_TIME;
- final long currentTime = System.currentTimeMillis();
- if (!mSharedPrefs.contains(keySetupTime)) {
- mSharedPrefs.edit()
- .putLong(keySetupTime, currentTime)
- .commit();
- }
- if (category.exclusiveExpireDaysInMillis < 0) {
- // negative means never expires
- return false;
- }
- final long setupTime = mSharedPrefs.getLong(keySetupTime, 0);
- final long elapsedTime = currentTime - setupTime;
- Log.d(TAG, "Day " + elapsedTime / DateUtils.DAY_IN_MILLIS + " for " + category.category);
- return elapsedTime > category.exclusiveExpireDaysInMillis;
- }
-
- @VisibleForTesting
- boolean isDismissed(Tile suggestion, boolean isSmartSuggestionEnabled) {
- String dismissControl = getDismissControl(suggestion, isSmartSuggestionEnabled);
- String keyBase = suggestion.intent.getComponent().flattenToShortString();
- if (!mSharedPrefs.contains(keyBase + SETUP_TIME)) {
- mSharedPrefs.edit()
- .putLong(keyBase + SETUP_TIME, System.currentTimeMillis())
- .commit();
- }
- // Check if it's already manually dismissed
- final boolean isDismissed = mSharedPrefs.getBoolean(keyBase + IS_DISMISSED, false);
- if (isDismissed) {
- return true;
- }
- if (dismissControl == null) {
- return false;
- }
- // Parse when suggestion should first appear. return true to artificially hide suggestion
- // before then.
- int firstAppearDay = parseDismissString(dismissControl);
- long firstAppearDayInMs = getEndTime(mSharedPrefs.getLong(keyBase + SETUP_TIME, 0),
- firstAppearDay);
- if (System.currentTimeMillis() >= firstAppearDayInMs) {
- // Dismiss timeout has passed, undismiss it.
- mSharedPrefs.edit()
- .putBoolean(keyBase + IS_DISMISSED, false)
- .commit();
- return false;
- }
- return true;
- }
-
- private long getEndTime(long startTime, int daysDelay) {
- long days = daysDelay * DateUtils.DAY_IN_MILLIS;
- return startTime + days;
- }
-
- /**
- * Parse the first int from a string formatted as "0,1,2..."
- * The value means suggestion should first appear on Day X.
- */
- private int parseDismissString(String dismissControl) {
- final String[] dismissStrs = dismissControl.split(",");
- return Integer.parseInt(dismissStrs[0]);
- }
-
- private String getDismissControl(Tile suggestion, boolean isSmartSuggestionEnabled) {
- if (isSmartSuggestionEnabled) {
- return mDefaultDismissControl;
- } else {
- return suggestion.metaData.getString(META_DATA_DISMISS_CONTROL);
- }
- }
-
- private static class SuggestionOrderInflater {
- private static final String TAG_LIST = "optional-steps";
- private static final String TAG_ITEM = "step";
-
- private static final String ATTR_CATEGORY = "category";
- private static final String ATTR_PACKAGE = "package";
- private static final String ATTR_MULTIPLE = "multiple";
- private static final String ATTR_EXCLUSIVE = "exclusive";
- private static final String ATTR_EXCLUSIVE_EXPIRE_DAYS = "exclusiveExpireDays";
-
- private final Context mContext;
-
- public SuggestionOrderInflater(Context context) {
- mContext = context;
- }
-
- public Object parse(int resource) {
- XmlPullParser parser = mContext.getResources().getXml(resource);
- final AttributeSet attrs = Xml.asAttributeSet(parser);
- try {
- // Look for the root node.
- int type;
- do {
- type = parser.next();
- } while (type != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT);
-
- if (type != XmlPullParser.START_TAG) {
- throw new InflateException(parser.getPositionDescription()
- + ": No start tag found!");
- }
-
- // Temp is the root that was found in the xml
- Object xmlRoot = onCreateItem(parser.getName(), attrs);
-
- // Inflate all children under temp
- rParse(parser, xmlRoot, attrs);
- return xmlRoot;
- } catch (XmlPullParserException | IOException e) {
- Log.w(TAG, "Problem parser resource " + resource, e);
- return null;
- }
- }
-
- /**
- * Recursive method used to descend down the xml hierarchy and instantiate
- * items, instantiate their children.
- */
- private void rParse(XmlPullParser parser, Object parent, final AttributeSet attrs)
- throws XmlPullParserException, IOException {
- final int depth = parser.getDepth();
-
- int type;
- while (((type = parser.next()) != XmlPullParser.END_TAG ||
- parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
- if (type != XmlPullParser.START_TAG) {
- continue;
- }
-
- final String name = parser.getName();
-
- Object item = onCreateItem(name, attrs);
- onAddChildItem(parent, item);
- rParse(parser, item, attrs);
- }
- }
-
- protected void onAddChildItem(Object parent, Object child) {
- if (parent instanceof List<?> && child instanceof SuggestionCategory) {
- ((List<SuggestionCategory>) parent).add((SuggestionCategory) child);
- } else {
- throw new IllegalArgumentException("Parent was not a list");
- }
- }
-
- protected Object onCreateItem(String name, AttributeSet attrs) {
- if (name.equals(TAG_LIST)) {
- return new ArrayList<SuggestionCategory>();
- } else if (name.equals(TAG_ITEM)) {
- SuggestionCategory category = new SuggestionCategory();
- category.category = attrs.getAttributeValue(null, ATTR_CATEGORY);
- category.pkg = attrs.getAttributeValue(null, ATTR_PACKAGE);
- String multiple = attrs.getAttributeValue(null, ATTR_MULTIPLE);
- category.multiple = !TextUtils.isEmpty(multiple) && Boolean.parseBoolean(multiple);
- String exclusive = attrs.getAttributeValue(null, ATTR_EXCLUSIVE);
- category.exclusive =
- !TextUtils.isEmpty(exclusive) && Boolean.parseBoolean(exclusive);
- String expireDaysAttr = attrs.getAttributeValue(null,
- ATTR_EXCLUSIVE_EXPIRE_DAYS);
- long expireDays = !TextUtils.isEmpty(expireDaysAttr)
- ? Integer.parseInt(expireDaysAttr)
- : -1;
- category.exclusiveExpireDaysInMillis = DateUtils.DAY_IN_MILLIS * expireDays;
- return category;
- } else {
- throw new IllegalArgumentException("Unknown item " + name);
- }
- }
- }
-}
-
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index b9c7601..18a44ed 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -756,10 +756,7 @@
}
public CharSequence getSsid() {
- final SpannableString str = new SpannableString(ssid);
- str.setSpan(new TtsSpan.TelephoneBuilder(ssid).build(), 0, ssid.length(),
- Spannable.SPAN_INCLUSIVE_INCLUSIVE);
- return str;
+ return ssid;
}
public String getConfigName() {
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index e435a72..0324799 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -104,18 +104,13 @@
}
@Test
- public void testSsidIsTelephoneSpan() {
+ public void testSsidIsSpannableString_returnFalse() {
final Bundle bundle = new Bundle();
bundle.putString("key_ssid", TEST_SSID);
final AccessPoint ap = new AccessPoint(InstrumentationRegistry.getTargetContext(), bundle);
final CharSequence ssid = ap.getSsid();
- assertThat(ssid instanceof SpannableString).isTrue();
-
- TtsSpan[] spans = ((SpannableString) ssid).getSpans(0, TEST_SSID.length(), TtsSpan.class);
-
- assertThat(spans.length).isEqualTo(1);
- assertThat(spans[0].getType()).isEqualTo(TtsSpan.TYPE_TELEPHONE);
+ assertThat(ssid instanceof SpannableString).isFalse();
}
@Test
diff --git a/packages/SettingsLib/tests/robotests/res/xml/suggestion_ordering.xml b/packages/SettingsLib/tests/robotests/res/xml/suggestion_ordering.xml
deleted file mode 100644
index f02ac15..0000000
--- a/packages/SettingsLib/tests/robotests/res/xml/suggestion_ordering.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-
-<optional-steps>
- <step category="com.android.settings.suggested.category.DEFERRED_SETUP"
- exclusive="true" />
- <step category="com.android.settings.suggested.category.LOCK_SCREEN" />
- <step category="com.android.settings.suggested.category.TRUST_AGENT" />
- <step category="com.android.settings.suggested.category.EMAIL" />
- <step category="com.android.settings.suggested.category.PARTNER_ACCOUNT"
- multiple="true" />
- <step category="com.android.settings.suggested.category.GESTURE" />
- <step category="com.android.settings.suggested.category.HOTWORD" />
- <step category="com.android.settings.suggested.category.DEFAULT"
- multiple="true" />
- <step category="com.android.settings.suggested.category.SETTINGS_ONLY"
- multiple="true" />
-</optional-steps>
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java
index ddbcb87..757df5b 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java
@@ -16,11 +16,10 @@
package com.android.settingslib.deviceinfo;
+import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.spy;
import android.annotation.SuppressLint;
import android.content.Context;
@@ -40,6 +39,7 @@
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
import java.util.Arrays;
import java.util.List;
@@ -48,12 +48,16 @@
@RunWith(SettingsLibRobolectricTestRunner.class)
public class WifiMacAddressPreferenceControllerTest {
@Mock
- private Context mContext;
- @Mock
private Lifecycle mLifecycle;
@Mock
private PreferenceScreen mScreen;
@Mock
+ private WifiManager mWifiManager;
+ @Mock
+ private WifiInfo mWifiInfo;
+
+ private AbstractWifiMacAddressPreferenceController mController;
+ private Context mContext;
private Preference mPreference;
private static final String TEST_MAC_ADDRESS = "00:11:22:33:44:55";
@@ -61,14 +65,20 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+
+ mContext = spy(RuntimeEnvironment.application);
+ mPreference = new Preference(mContext);
+
doReturn(mPreference).when(mScreen)
.findPreference(AbstractWifiMacAddressPreferenceController.KEY_WIFI_MAC_ADDRESS);
+ doReturn(mWifiManager).when(mContext).getSystemService(WifiManager.class);
+ doReturn(mWifiInfo).when(mWifiManager).getConnectionInfo();
+
+ mController = new ConcreteWifiMacAddressPreferenceController(mContext, mLifecycle);
}
@Test
public void testHasIntentFilters() {
- final AbstractWifiMacAddressPreferenceController wifiMacAddressPreferenceController =
- new ConcreteWifiMacAddressPreferenceController(mContext, mLifecycle);
final List<String> expectedIntents = Arrays.asList(
ConnectivityManager.CONNECTIVITY_ACTION,
WifiManager.LINK_CONFIGURATION_CHANGED_ACTION,
@@ -76,37 +86,110 @@
assertWithMessage("Intent filter should contain expected intents")
- .that(wifiMacAddressPreferenceController.getConnectivityIntents())
+ .that(mController.getConnectivityIntents())
.asList().containsAllIn(expectedIntents);
}
@Test
- public void testWifiMacAddress() {
- final WifiManager wifiManager = mock(WifiManager.class);
- final WifiInfo wifiInfo = mock(WifiInfo.class);
-
- doReturn(null).when(wifiManager).getConnectionInfo();
- doReturn(wifiManager).when(mContext).getSystemService(WifiManager.class);
-
- final AbstractWifiMacAddressPreferenceController wifiMacAddressPreferenceController =
- new ConcreteWifiMacAddressPreferenceController(mContext, mLifecycle);
-
- wifiMacAddressPreferenceController.displayPreference(mScreen);
- verify(mPreference).setSummary(R.string.status_unavailable);
-
- doReturn(wifiInfo).when(wifiManager).getConnectionInfo();
- doReturn(TEST_MAC_ADDRESS).when(wifiInfo).getMacAddress();
- wifiMacAddressPreferenceController.displayPreference(mScreen);
- verify(mPreference).setSummary(TEST_MAC_ADDRESS);
-
+ public void updateConnectivity_nullWifiInfoWithMacRandomizationOff_setMacUnavailable() {
Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED, 1);
- wifiMacAddressPreferenceController.displayPreference(mScreen);
- verify(mPreference, times(2)).setSummary(TEST_MAC_ADDRESS);
+ Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED,
+ AbstractWifiMacAddressPreferenceController.OFF);
+ doReturn(null).when(mWifiManager).getConnectionInfo();
- doReturn(WifiInfo.DEFAULT_MAC_ADDRESS).when(wifiInfo).getMacAddress();
- wifiMacAddressPreferenceController.displayPreference(mScreen);
- verify(mPreference).setSummary(R.string.wifi_status_mac_randomized);
+ mController.displayPreference(mScreen);
+
+ assertThat(mPreference.getSummary())
+ .isEqualTo(mContext.getString(R.string.status_unavailable));
+ }
+
+ @Test
+ public void updateConnectivity_nullMacWithMacRandomizationOff_setMacUnavailable() {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED,
+ AbstractWifiMacAddressPreferenceController.OFF);
+ doReturn(null).when(mWifiInfo).getMacAddress();
+
+ mController.displayPreference(mScreen);
+
+ assertThat(mPreference.getSummary())
+ .isEqualTo(mContext.getString(R.string.status_unavailable));
+ }
+
+ @Test
+ public void updateConnectivity_defaultMacWithMacRandomizationOff_setMacUnavailable() {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED,
+ AbstractWifiMacAddressPreferenceController.OFF);
+ doReturn(WifiInfo.DEFAULT_MAC_ADDRESS).when(mWifiInfo).getMacAddress();
+
+ mController.displayPreference(mScreen);
+
+ assertThat(mPreference.getSummary())
+ .isEqualTo(mContext.getString(R.string.status_unavailable));
+ }
+
+ @Test
+ public void updateConnectivity_validMacWithMacRandomizationOff_setValidMac() {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED,
+ AbstractWifiMacAddressPreferenceController.OFF);
+ doReturn(TEST_MAC_ADDRESS).when(mWifiInfo).getMacAddress();
+
+ mController.displayPreference(mScreen);
+
+ assertThat(mPreference.getSummary()).isEqualTo(TEST_MAC_ADDRESS);
+ }
+
+ @Test
+ public void updateConnectivity_nullWifiInfoWithMacRandomizationOn_setMacUnavailable() {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED,
+ AbstractWifiMacAddressPreferenceController.ON);
+ doReturn(null).when(mWifiManager).getConnectionInfo();
+
+ mController.displayPreference(mScreen);
+
+ assertThat(mPreference.getSummary())
+ .isEqualTo(mContext.getString(R.string.status_unavailable));
+ }
+
+ @Test
+ public void updateConnectivity_nullMacWithMacRandomizationOn_setMacUnavailable() {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED,
+ AbstractWifiMacAddressPreferenceController.ON);
+ doReturn(null).when(mWifiInfo).getMacAddress();
+
+ mController.displayPreference(mScreen);
+
+ assertThat(mPreference.getSummary())
+ .isEqualTo(mContext.getString(R.string.status_unavailable));
+ }
+
+ @Test
+ public void updateConnectivity_defaultMacWithMacRandomizationOn_setMacRandomized() {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED,
+ AbstractWifiMacAddressPreferenceController.ON);
+ doReturn(WifiInfo.DEFAULT_MAC_ADDRESS).when(mWifiInfo).getMacAddress();
+
+ mController.displayPreference(mScreen);
+
+ assertThat(mPreference.getSummary())
+ .isEqualTo(mContext.getString(R.string.wifi_status_mac_randomized));
+ }
+
+ @Test
+ public void updateConnectivity_validMacWithMacRandomizationOn_setValidMac() {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED,
+ AbstractWifiMacAddressPreferenceController.ON);
+ doReturn(TEST_MAC_ADDRESS).when(mWifiInfo).getMacAddress();
+
+ mController.displayPreference(mScreen);
+
+ assertThat(mPreference.getSummary()).isEqualTo(TEST_MAC_ADDRESS);
}
private static class ConcreteWifiMacAddressPreferenceController
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java
new file mode 100644
index 0000000..996a122
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java
@@ -0,0 +1,48 @@
+package com.android.settingslib.drawer;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static com.android.settingslib.drawer.TileUtils.META_DATA_KEY_PROFILE;
+import static com.android.settingslib.drawer.TileUtils.PROFILE_ALL;
+import static com.android.settingslib.drawer.TileUtils.PROFILE_PRIMARY;
+
+import android.os.Bundle;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.junit.Test;
+
+@RunWith(RobolectricTestRunner.class)
+public class TileTest {
+
+ private Tile mTile;
+
+ @Before
+ public void setUp() {
+ mTile = new Tile();
+ mTile.metaData = new Bundle();
+ }
+
+ @Test
+ public void isPrimaryProfileOnly_profilePrimary_shouldReturnTrue() {
+ mTile.metaData.putString(META_DATA_KEY_PROFILE, PROFILE_PRIMARY);
+ assertThat(mTile.isPrimaryProfileOnly()).isTrue();
+ }
+
+ @Test
+ public void isPrimaryProfileOnly_profileAll_shouldReturnFalse() {
+ mTile.metaData.putString(META_DATA_KEY_PROFILE, PROFILE_ALL);
+ assertThat(mTile.isPrimaryProfileOnly()).isFalse();
+ }
+
+ @Test
+ public void isPrimaryProfileOnly_noExplicitValue_shouldReturnFalse() {
+ assertThat(mTile.isPrimaryProfileOnly()).isFalse();
+ }
+
+ @Test
+ public void isPrimaryProfileOnly_nullMetadata_shouldReturnFalse() {
+ mTile.metaData = null;
+ assertThat(mTile.isPrimaryProfileOnly()).isFalse();
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
index fc1b2238..6e66805 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
@@ -28,7 +28,6 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.robolectric.RuntimeEnvironment.application;
-import static org.robolectric.shadow.api.Shadow.extract;
import android.app.ActivityManager;
import android.content.ContentResolver;
@@ -52,9 +51,6 @@
import android.util.Pair;
import android.widget.RemoteViews;
-import com.android.settingslib.R;
-import com.android.settingslib.suggestions.SuggestionParser;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -67,7 +63,6 @@
import org.robolectric.annotation.Implements;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -164,35 +159,6 @@
}
@Test
- public void getTilesForIntent_shouldSkipFilteredApps() {
- Intent intent = new Intent();
- Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
- List<Tile> outTiles = new ArrayList<>();
- List<ResolveInfo> info = new ArrayList<>();
- ResolveInfo resolveInfo = newInfo(true, null /* category */, null, URI_GET_ICON,
- URI_GET_SUMMARY);
- addMetadataToInfo(resolveInfo, "com.android.settings.require_account", "com.google");
- addMetadataToInfo(resolveInfo, "com.android.settings.require_connection", "true");
- info.add(resolveInfo);
-
- when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
- .thenReturn(info);
-
- TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
- null /* defaultCategory */, outTiles, false /* usePriority */,
- false /* checkCategory */, true /* forceTintExternalIcon */);
-
- assertThat(outTiles.size()).isEqualTo(1);
- SuggestionParser parser = new SuggestionParser(
- mContext,
- null,
- Collections.emptyList(),
- "0,10");
- parser.filterSuggestions(outTiles, 0, false);
- assertThat(outTiles.size()).isEqualTo(0);
- }
-
- @Test
public void getCategories_shouldHandleExtraIntentAction() {
final String testCategory = "category1";
final String testAction = "action1";
@@ -392,108 +358,6 @@
assertThat(outTiles.size()).isEqualTo(1);
}
- @Test
- public void getTilesForIntent_shouldShowRemoteViewIfSpecified() {
- Intent intent = new Intent();
- Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
- List<Tile> outTiles = new ArrayList<>();
- List<ResolveInfo> info = new ArrayList<>();
- ResolveInfo resolveInfo = newInfo(true, null /* category */);
- resolveInfo.activityInfo.metaData.putInt("com.android.settings.custom_view",
- R.layout.user_preference);
- info.add(resolveInfo);
-
- when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
- .thenReturn(info);
-
- TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
- null /* defaultCategory */, outTiles, false /* usePriority */,
- false /* checkCategory */, true /* forceTintExternalIcon */);
-
- assertThat(outTiles.size()).isEqualTo(1);
- Tile tile = outTiles.get(0);
- assertThat(tile.remoteViews).isNotNull();
- assertThat(tile.remoteViews.getLayoutId()).isEqualTo(R.layout.user_preference);
- }
-
- @Test
- public void getTilesForIntent_summaryUriSpecified_shouldOverrideRemoteViewSummary()
- throws RemoteException {
- Intent intent = new Intent();
- Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
- List<Tile> outTiles = new ArrayList<>();
- List<ResolveInfo> info = new ArrayList<>();
- ResolveInfo resolveInfo = newInfo(true, null /* category */, null,
- null, URI_GET_SUMMARY);
- resolveInfo.activityInfo.metaData.putInt("com.android.settings.custom_view",
- R.layout.user_preference);
- info.add(resolveInfo);
-
- when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
- .thenReturn(info);
-
- // Mock the content provider interaction.
- Bundle bundle = new Bundle();
- bundle.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY, "new summary text");
- when(mIContentProvider.call(anyString(),
- eq(TileUtils.getMethodFromUri(Uri.parse(URI_GET_SUMMARY))), eq(URI_GET_SUMMARY),
- any())).thenReturn(bundle);
- when(mContentResolver.acquireUnstableProvider(anyString()))
- .thenReturn(mIContentProvider);
- when(mContentResolver.acquireUnstableProvider(any(Uri.class)))
- .thenReturn(mIContentProvider);
-
- TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
- null /* defaultCategory */, outTiles, false /* usePriority */,
- false /* checkCategory */, true /* forceTintExternalIcon */);
-
- assertThat(outTiles.size()).isEqualTo(1);
- Tile tile = outTiles.get(0);
- assertThat(tile.remoteViews).isNotNull();
- assertThat(tile.remoteViews.getLayoutId()).isEqualTo(R.layout.user_preference);
- // Make sure the summary TextView got a new text string.
- TileUtilsShadowRemoteViews shadowRemoteViews = extract(tile.remoteViews);
- assertThat(shadowRemoteViews.overrideViewId).isEqualTo(android.R.id.summary);
- assertThat(shadowRemoteViews.overrideText).isEqualTo("new summary text");
- }
-
- @Test
- public void getTilesForIntent_providerUnavailable_shouldNotOverrideRemoteViewSummary()
- throws RemoteException {
- Intent intent = new Intent();
- Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
- List<Tile> outTiles = new ArrayList<>();
- List<ResolveInfo> info = new ArrayList<>();
- ResolveInfo resolveInfo = newInfo(true, null /* category */, null,
- null, URI_GET_SUMMARY);
- resolveInfo.activityInfo.metaData.putInt("com.android.settings.custom_view",
- R.layout.user_preference);
- info.add(resolveInfo);
-
- when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
- .thenReturn(info);
-
- // Mock the content provider interaction.
- Bundle bundle = new Bundle();
- bundle.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY, "new summary text");
- when(mIContentProvider.call(anyString(),
- eq(TileUtils.getMethodFromUri(Uri.parse(URI_GET_SUMMARY))), eq(URI_GET_SUMMARY),
- any())).thenReturn(bundle);
-
- TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
- null /* defaultCategory */, outTiles, false /* usePriority */,
- false /* checkCategory */, true /* forceTintExternalIcon */);
-
- assertThat(outTiles.size()).isEqualTo(1);
- Tile tile = outTiles.get(0);
- assertThat(tile.remoteViews).isNotNull();
- assertThat(tile.remoteViews.getLayoutId()).isEqualTo(R.layout.user_preference);
- // Make sure the summary TextView didn't get any text view updates.
- TileUtilsShadowRemoteViews shadowRemoteViews = extract(tile.remoteViews);
- assertThat(shadowRemoteViews.overrideViewId).isNull();
- assertThat(shadowRemoteViews.overrideText).isNull();
- }
-
public static ResolveInfo newInfo(boolean systemApp, String category) {
return newInfo(systemApp, category, null);
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageControllerTest.java
new file mode 100644
index 0000000..1be856a
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageControllerTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2018 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.settingslib.net;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyLong;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.INetworkStatsSession;
+import android.net.NetworkStatsHistory;
+import android.net.NetworkStatsHistory.Entry;
+import android.net.NetworkTemplate;
+import android.os.RemoteException;
+import android.text.format.DateUtils;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+public class DataUsageControllerTest {
+
+ @Mock
+ private INetworkStatsSession mSession;
+
+ private Context mContext;
+ private DataUsageController mController;
+ private NetworkStatsHistory mNetworkStatsHistory;
+
+ @Before
+ public void setUp() throws RemoteException {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+ mController = spy(new DataUsageController(mContext));
+ mNetworkStatsHistory = spy(
+ new NetworkStatsHistory(DateUtils.DAY_IN_MILLIS /* bucketDuration */));
+ doReturn(mNetworkStatsHistory)
+ .when(mSession).getHistoryForNetwork(any(NetworkTemplate.class), anyInt());
+ }
+
+ @Test
+ public void getHistoriclUsageLevel_noNetworkSession_shouldReturn0() {
+ doReturn(null).when(mController).getSession();
+
+ assertThat(mController.getHistoriclUsageLevel(null /* template */)).isEqualTo(0L);
+
+ }
+
+ @Test
+ public void getHistoriclUsageLevel_noUsageData_shouldReturn0() {
+ doReturn(mSession).when(mController).getSession();
+
+ assertThat(mController.getHistoriclUsageLevel(NetworkTemplate.buildTemplateWifiWildcard()))
+ .isEqualTo(0L);
+
+ }
+
+ @Test
+ public void getHistoriclUsageLevel_hasUsageData_shouldReturnTotalUsage() {
+ doReturn(mSession).when(mController).getSession();
+ final long receivedBytes = 743823454L;
+ final long transmittedBytes = 16574289L;
+ final Entry entry = new Entry();
+ entry.bucketStart = 1521583200000L;
+ entry.rxBytes = receivedBytes;
+ entry.txBytes = transmittedBytes;
+ when(mNetworkStatsHistory.getValues(eq(0L), anyLong(), anyLong(), nullable(Entry.class)))
+ .thenReturn(entry);
+
+ assertThat(mController.getHistoriclUsageLevel(NetworkTemplate.buildTemplateWifiWildcard()))
+ .isEqualTo(receivedBytes + transmittedBytes);
+
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionParserTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionParserTest.java
deleted file mode 100644
index d05bcfd..0000000
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionParserTest.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.suggestions;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.robolectric.RuntimeEnvironment.application;
-import static org.robolectric.shadow.api.Shadow.extract;
-
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.ResolveInfo;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-
-import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.drawer.Tile;
-import com.android.settingslib.drawer.TileUtilsTest;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.shadows.ShadowPackageManager;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-@RunWith(SettingsLibRobolectricTestRunner.class)
-public class SuggestionParserTest {
-
- private ShadowPackageManager mPackageManager;
- private SuggestionParser mSuggestionParser;
- private SuggestionCategory mMultipleCategory;
- private SuggestionCategory mExclusiveCategory;
- private SuggestionCategory mExpiredExclusiveCategory;
- private List<Tile> mSuggestionsBeforeDismiss;
- private List<Tile> mSuggestionsAfterDismiss;
- private SharedPreferences mPrefs;
- private Tile mSuggestion;
-
- @Before
- public void setUp() {
- mPackageManager = extract(application.getPackageManager());
- mPrefs = PreferenceManager.getDefaultSharedPreferences(application);
- mSuggestion = new Tile();
- mSuggestion.intent = new Intent("action");
- mSuggestion.intent.setComponent(new ComponentName("pkg", "cls"));
- mSuggestion.metaData = new Bundle();
- mMultipleCategory = new SuggestionCategory();
- mMultipleCategory.category = "category1";
- mMultipleCategory.multiple = true;
- mExclusiveCategory = new SuggestionCategory();
- mExclusiveCategory.category = "category2";
- mExclusiveCategory.exclusive = true;
- mExpiredExclusiveCategory = new SuggestionCategory();
- mExpiredExclusiveCategory.category = "category3";
- mExpiredExclusiveCategory.exclusive = true;
- mExpiredExclusiveCategory.exclusiveExpireDaysInMillis = 0;
-
- mSuggestionParser = new SuggestionParser(application, mPrefs,
- Arrays.asList(mMultipleCategory, mExclusiveCategory, mExpiredExclusiveCategory),
- "0");
-
- ResolveInfo info1 = TileUtilsTest.newInfo(true, null);
- info1.activityInfo.packageName = "pkg";
- ResolveInfo infoDupe1 = TileUtilsTest.newInfo(true, null);
- infoDupe1.activityInfo.packageName = "pkg";
-
- ResolveInfo info2 = TileUtilsTest.newInfo(true, null);
- info2.activityInfo.packageName = "pkg2";
- ResolveInfo info3 = TileUtilsTest.newInfo(true, null);
- info3.activityInfo.packageName = "pkg3";
- ResolveInfo info4 = TileUtilsTest.newInfo(true, null);
- info4.activityInfo.packageName = "pkg4";
-
- Intent intent1 = new Intent(Intent.ACTION_MAIN).addCategory("category1");
- Intent intent2 = new Intent(Intent.ACTION_MAIN).addCategory("category2");
- Intent intent3 = new Intent(Intent.ACTION_MAIN).addCategory("category3");
-
- mPackageManager.addResolveInfoForIntent(intent1, info1);
- mPackageManager.addResolveInfoForIntent(intent1, info2);
- mPackageManager.addResolveInfoForIntent(intent1, infoDupe1);
- mPackageManager.addResolveInfoForIntent(intent2, info3);
- mPackageManager.addResolveInfoForIntent(intent3, info4);
- }
-
- @Test
- public void dismissSuggestion_shouldDismiss() {
- assertThat(mSuggestionParser.dismissSuggestion(mSuggestion)).isTrue();
- }
-
- @Test
- public void testGetSuggestions_withoutSmartSuggestions_shouldDismiss() {
- readAndDismissSuggestion(false);
- mSuggestionParser.readSuggestions(mMultipleCategory, mSuggestionsAfterDismiss, false);
- assertThat(mSuggestionsBeforeDismiss).hasSize(2);
- assertThat(mSuggestionsAfterDismiss).hasSize(1);
- assertThat(mSuggestionsBeforeDismiss.get(1)).isEqualTo(mSuggestionsAfterDismiss.get(0));
- }
-
- @Test
- public void testGetSuggestions_withSmartSuggestions_shouldDismiss() {
- readAndDismissSuggestion(true);
- assertThat(mSuggestionsBeforeDismiss).hasSize(2);
- assertThat(mSuggestionsAfterDismiss).hasSize(1);
- }
-
- @Test
- public void testGetSuggestion_exclusiveNotAvailable_onlyRegularCategoryAndNoDupe() {
- mPackageManager.removeResolveInfosForIntent(
- new Intent(Intent.ACTION_MAIN).addCategory("category2"),
- "pkg3");
- mPackageManager.removeResolveInfosForIntent(
- new Intent(Intent.ACTION_MAIN).addCategory("category3"),
- "pkg4");
-
- // If exclusive item is not available, the other categories should be shown
- final SuggestionList sl =
- mSuggestionParser.getSuggestions(false /* isSmartSuggestionEnabled */);
- final List<Tile> suggestions = sl.getSuggestions();
- assertThat(suggestions).hasSize(2);
-
- assertThat(suggestions.get(0).intent.getComponent().getPackageName()).isEqualTo("pkg");
- assertThat(suggestions.get(1).intent.getComponent().getPackageName()).isEqualTo("pkg2");
- }
-
- @Test
- public void testGetSuggestion_exclusiveExpiredAvailable_shouldLoadWithRegularCategory() {
- // First remove permanent exclusive
- mPackageManager.removeResolveInfosForIntent(
- new Intent(Intent.ACTION_MAIN).addCategory("category2"),
- "pkg3");
- // Set the other exclusive to be expired.
- mPrefs.edit()
- .putLong(mExpiredExclusiveCategory.category + "_setup_time",
- System.currentTimeMillis() - 1000)
- .commit();
-
- // If exclusive is expired, they should be shown together with the other categories
- final SuggestionList sl =
- mSuggestionParser.getSuggestions(true /* isSmartSuggestionEnabled */);
- final List<Tile> suggestions = sl.getSuggestions();
-
- assertThat(suggestions).hasSize(3);
- }
-
- @Test
- public void testGetSuggestions_exclusive() {
- final SuggestionList sl =
- mSuggestionParser.getSuggestions(false /* isSmartSuggestionEnabled */);
- final List<Tile> suggestions = sl.getSuggestions();
-
- assertThat(suggestions).hasSize(1);
- }
-
- @Test
- public void isSuggestionDismissed_dismissedSuggestion_shouldReturnTrue() {
- final Tile suggestion = new Tile();
- suggestion.metaData = new Bundle();
- suggestion.metaData.putString(SuggestionParser.META_DATA_DISMISS_CONTROL, "1,2,3");
- suggestion.intent = new Intent().setComponent(new ComponentName("pkg", "cls"));
-
- // Dismiss suggestion when smart suggestion is not enabled.
- mSuggestionParser.dismissSuggestion(suggestion);
-
- assertThat(mSuggestionParser.isDismissed(suggestion, true /* isSmartSuggestionEnabled */))
- .isTrue();
- }
-
- private void readAndDismissSuggestion(boolean isSmartSuggestionEnabled) {
- mSuggestionsBeforeDismiss = new ArrayList<>();
- mSuggestionsAfterDismiss = new ArrayList<>();
- mSuggestionParser.readSuggestions(
- mMultipleCategory, mSuggestionsBeforeDismiss, isSmartSuggestionEnabled);
-
- final Tile suggestion = mSuggestionsBeforeDismiss.get(0);
- if (mSuggestionParser.dismissSuggestion(suggestion)) {
- mPackageManager.removeResolveInfosForIntent(
- new Intent(Intent.ACTION_MAIN).addCategory(mMultipleCategory.category),
- suggestion.intent.getComponent().getPackageName());
- }
- mSuggestionParser.readSuggestions(
- mMultipleCategory, mSuggestionsAfterDismiss, isSmartSuggestionEnabled);
- }
-}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index f728684..9d398b5 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -841,7 +841,19 @@
WifiConfiguration config = WifiConfiguration
.getWifiConfigFromBackup(new DataInputStream(new ByteArrayInputStream(data)));
if (DEBUG) Log.d(TAG, "Successfully unMarshaled WifiConfiguration ");
+ int originalApBand = config.apBand;
mWifiManager.setWifiApConfiguration(config);
+
+ // Depending on device hardware, we may need to notify the user of a setting change for
+ // the apBand preference
+ boolean dualMode = mWifiManager.isDualModeSupported();
+ int storedApBand = mWifiManager.getWifiApConfiguration().apBand;
+ if (dualMode) {
+ if (storedApBand != originalApBand) {
+ Log.d(TAG, "restored ap configuration requires a conversion, notify the user");
+ mWifiManager.notifyUserOfApBandConversion();
+ }
+ }
} catch (IOException | BackupUtils.BadVersionException e) {
Log.e(TAG, "Failed to unMarshal SoftAPConfiguration " + e.getMessage());
}
diff --git a/packages/Shell/res/values-hy/strings.xml b/packages/Shell/res/values-hy/strings.xml
index 95b6131..3bc54b2 100644
--- a/packages/Shell/res/values-hy/strings.xml
+++ b/packages/Shell/res/values-hy/strings.xml
@@ -25,9 +25,9 @@
<string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"Վրիպակների մասին հաշվետվությունը շուտով կստանաք հեռախոսին"</string>
<string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"Ընտրեք՝ վրիպակի զեկույցն ուղարկելու համար"</string>
<string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Հպեք՝ վրիպակի զեկույցը տրամադրելու համար"</string>
- <string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"Ընտրեք՝ վրիպակի զեկույցն առանց էկրանի պատկերի ուղարկելու համար կամ սպասեք էկրանի պատկերի ստեղծմանը"</string>
- <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Հպեք՝ վրիպակի զեկույցն առանց էկրանի պատկերի ուղարկելու համար կամ սպասեք էկրանի պատկերի ստեղծմանը"</string>
- <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Հպեք՝ վրիպակի զեկույցն առանց էկրանի պատկերի ուղարկելու համար կամ սպասեք էկրանի պատկերի ստեղծմանը"</string>
+ <string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"Ընտրեք՝ վրիպակի զեկույցն առանց սքրինշոթի ուղարկելու համար կամ սպասեք էկրանի պատկերի ստեղծմանը"</string>
+ <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Հպեք՝ վրիպակի զեկույցն առանց սքրինշոթի ուղարկելու համար կամ սպասեք էկրանի պատկերի ստեղծմանը"</string>
+ <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Հպեք՝ վրիպակի զեկույցն առանց սքրինշոթի ուղարկելու համար կամ սպասեք էկրանի պատկերի ստեղծմանը"</string>
<string name="bugreport_confirm" msgid="5917407234515812495">"Վրիպակի զեկույցները պարունակում են տվյալներ համակարգի տարբեր մատյաններից և կարող են ներառել տեղեկություններ, որոնք դուք գաղտնի եք համարում (օրինակ՝ հավելվածի օգտագործման կամ տեղադրության մասին): Վրիպակի զեկույցները տրամադրեք միայն վստահելի մարդկանց և հավելվածներին:"</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Այլևս ցույց չտալ"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Վրիպակների հաշվետվություններ"</string>
@@ -35,9 +35,9 @@
<string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"Չհաջողվեց ավելացնել վրիպակի զեկույցի մանրամասները zip ֆայլին"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"անանուն"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Մանրամասներ"</string>
- <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Էկրանի պատկեր"</string>
- <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Էկրանի պատկերը հաջողությամբ ստացվեց:"</string>
- <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Չհաջողվեց ստանալ էկրանի պատկերը:"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Սքրինշոթ"</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Սքրինշոթը հաջողությամբ ստացվեց:"</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Չհաջողվեց ստանալ սքրինշոթը:"</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"<xliff:g id="ID">#%d</xliff:g> վրիպակի զեկույցի մանրամասները"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Ֆայլի անունը"</string>
<string name="bugreport_info_title" msgid="2306030793918239804">"Վրիպակի զեկույցի վերնագիրը"</string>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index beb4e9e..eab4b97 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -120,6 +120,7 @@
<uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
<uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
<uses-permission android:name="android.permission.TRUST_LISTENER" />
+ <uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.RESET_FINGERPRINT_LOCKOUT" />
<uses-permission android:name="android.permission.MANAGE_SLICE_PERMISSIONS" />
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index e217ace..47f2cdc 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -14,6 +14,7 @@
jaggies@google.com
jjaggi@google.com
juliacr@google.com
+kchyn@google.com
madym@google.com
ngmatthew@google.com
roosa@google.com
diff --git a/packages/SystemUI/res-keyguard/values-af/strings.xml b/packages/SystemUI/res-keyguard/values-af/strings.xml
index 41a3f10..f43d57a 100644
--- a/packages/SystemUI/res-keyguard/values-af/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-af/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Toestel is <xliff:g id="NUMBER_1">%d</xliff:g> uur lank nie ontsluit nie. Bevestig wagwoord.</item>
<item quantity="one">Toestel is <xliff:g id="NUMBER_0">%d</xliff:g> uur lank nie ontsluit nie. Bevestig wagwoord.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Nie herken nie"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Nie herken nie"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Nie herken nie"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">Voer SIM-PIN in. Jy het <xliff:g id="NUMBER_1">%d</xliff:g> pogings oor.</item>
<item quantity="one">Voer SIM-PIN in. Jy het <xliff:g id="NUMBER_0">%d</xliff:g> poging oor voordat jy jou diensverskaffer moet kontak om jou toestel te ontsluit.</item>
diff --git a/packages/SystemUI/res-keyguard/values-am/strings.xml b/packages/SystemUI/res-keyguard/values-am/strings.xml
index 0ee1820..11e099a 100644
--- a/packages/SystemUI/res-keyguard/values-am/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-am/strings.xml
@@ -140,7 +140,8 @@
<item quantity="one">መሣሪያው ለ<xliff:g id="NUMBER_1">%d</xliff:g> ሰዓቶች አልተከፈተም ነበር። የይለፍ ቃል ያረጋግጡ።</item>
<item quantity="other">መሣሪያው ለ<xliff:g id="NUMBER_1">%d</xliff:g> ሰዓቶች አልተከፈተም ነበር። የይለፍ ቃል ያረጋግጡ።</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"አልታወቀም"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"አልታወቀም"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"አልታወቀም"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">የሲም ፒን ያስገቡ። <xliff:g id="NUMBER_1">%d</xliff:g> ሙከራዎች ይቀረዎታል።</item>
<item quantity="other">የሲም ፒን ያስገቡ። <xliff:g id="NUMBER_1">%d</xliff:g> ሙከራዎች ይቀረዎታል።</item>
diff --git a/packages/SystemUI/res-keyguard/values-ar/strings.xml b/packages/SystemUI/res-keyguard/values-ar/strings.xml
index 9980d64..1117730 100644
--- a/packages/SystemUI/res-keyguard/values-ar/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ar/strings.xml
@@ -164,7 +164,8 @@
<item quantity="other">لم يتم إلغاء تأمين الجهاز لمدة <xliff:g id="NUMBER_1">%d</xliff:g> ساعة. تأكيد كلمة المرور.</item>
<item quantity="one">لم يتم إلغاء تأمين الجهاز لمدة <xliff:g id="NUMBER_0">%d</xliff:g> ساعة. تأكيد كلمة المرور.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"لم يتم التعرف عليها"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"لم يتم التعرف عليها."</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"لم يتم التعرّف عليه."</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="zero">أدخل رقم التعريف الشخصي لشريحة SIM. تتبقى لديك <xliff:g id="NUMBER_1">%d</xliff:g> محاولة.</item>
<item quantity="two">أدخل رقم التعريف الشخصي لشريحة SIM. تتبقى لديك محاولتان (<xliff:g id="NUMBER_1">%d</xliff:g>).</item>
diff --git a/packages/SystemUI/res-keyguard/values-as/strings.xml b/packages/SystemUI/res-keyguard/values-as/strings.xml
index 929d89c..50dd855 100644
--- a/packages/SystemUI/res-keyguard/values-as/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-as/strings.xml
@@ -140,7 +140,8 @@
<item quantity="one">ডিভাইচটো <xliff:g id="NUMBER_1">%d</xliff:g> ঘণ্টা ধৰি আনলক কৰা হোৱা নাই। পাছৱৰ্ড নিশ্চিত কৰক।</item>
<item quantity="other">ডিভাইচটো <xliff:g id="NUMBER_1">%d</xliff:g> ঘণ্টা ধৰি আনলক কৰা হোৱা নাই। পাছৱৰ্ড নিশ্চিত কৰক।</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"চিনাক্ত কৰিব পৰা নগ\'ল"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"চিনাক্ত কৰিব পৰা নাই"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"চিনাক্ত কৰিব পৰা নাই"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">ছিমৰ পিন দিয়ক। আপুনি আৰু <xliff:g id="NUMBER_1">%d</xliff:g>বাৰ প্ৰয়াস কৰিব পাৰে।</item>
<item quantity="other">ছিমৰ পিন দিয়ক। আপুনি আৰু <xliff:g id="NUMBER_1">%d</xliff:g>বাৰ প্ৰয়াস কৰিব পাৰে।</item>
diff --git a/packages/SystemUI/res-keyguard/values-az/strings.xml b/packages/SystemUI/res-keyguard/values-az/strings.xml
index 0926194..19a0963 100644
--- a/packages/SystemUI/res-keyguard/values-az/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-az/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Cihaz <xliff:g id="NUMBER_1">%d</xliff:g> saat kiliddən çıxarılmayıb. Parolu təsdiq edin.</item>
<item quantity="one">Cihaz <xliff:g id="NUMBER_0">%d</xliff:g> saat kiliddən çıxarılmayıb. Parolu təsdiq edin.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Tanınmır"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Tanınmır"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Tanınmır"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">SIM PIN-ni daxil edin. <xliff:g id="NUMBER_1">%d</xliff:g> cəhdiniz qalır.</item>
<item quantity="one">SIM PIN-ni daxil edin. Cihazınızı kiliddən çıxarmaq üçün operatorunuzla əlaqə saxlamadan öncə <xliff:g id="NUMBER_0">%d</xliff:g> cəhdiniz qalır.</item>
diff --git a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
index 67da7b8..1e8e443 100644
--- a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
@@ -146,7 +146,8 @@
<item quantity="few">Niste otključali uređaj <xliff:g id="NUMBER_1">%d</xliff:g> sata. Potvrdite lozinku.</item>
<item quantity="other">Niste otključali uređaj <xliff:g id="NUMBER_1">%d</xliff:g> sati. Potvrdite lozinku.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Nije prepoznat"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Nije prepoznat"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Nije prepoznat"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">Unesite PIN za SIM. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj.</item>
<item quantity="few">Unesite PIN za SIM. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja.</item>
diff --git a/packages/SystemUI/res-keyguard/values-be/strings.xml b/packages/SystemUI/res-keyguard/values-be/strings.xml
index 5b11a09..8251071 100644
--- a/packages/SystemUI/res-keyguard/values-be/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-be/strings.xml
@@ -152,7 +152,8 @@
<item quantity="many">Прылада не была разблакіравана на працягу <xliff:g id="NUMBER_1">%d</xliff:g> гадзін. Увядзіце пароль.</item>
<item quantity="other">Прылада не была разблакіравана на працягу <xliff:g id="NUMBER_1">%d</xliff:g> гадзіны. Увядзіце пароль.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Не распазнаны"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Не распазнана"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Не распазнана"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">Увядзіце PIN-код SIM-карты. У вас засталася <xliff:g id="NUMBER_1">%d</xliff:g> спроба.</item>
<item quantity="few">Увядзіце PIN-код SIM-карты. У вас засталося <xliff:g id="NUMBER_1">%d</xliff:g> спробы.</item>
diff --git a/packages/SystemUI/res-keyguard/values-bg/strings.xml b/packages/SystemUI/res-keyguard/values-bg/strings.xml
index 663d5f0..7438d7f 100644
--- a/packages/SystemUI/res-keyguard/values-bg/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bg/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Устройството не е отключвано от <xliff:g id="NUMBER_1">%d</xliff:g> часа. Потвърдете паролата.</item>
<item quantity="one">Устройството не е отключвано от <xliff:g id="NUMBER_0">%d</xliff:g> час. Потвърдете паролата.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Не е разпознато"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Не е разпознато"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Не е разпознато"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">Въведете ПИН кода за SIM картата – остават ви <xliff:g id="NUMBER_1">%d</xliff:g> опита.</item>
<item quantity="one">Въведете ПИН кода за SIM картата – остава ви <xliff:g id="NUMBER_0">%d</xliff:g> опит, преди да се наложи да се свържете с оператора си, за да отключите устройството.</item>
diff --git a/packages/SystemUI/res-keyguard/values-bn/strings.xml b/packages/SystemUI/res-keyguard/values-bn/strings.xml
index 7a3b575..814aafe 100644
--- a/packages/SystemUI/res-keyguard/values-bn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bn/strings.xml
@@ -140,7 +140,10 @@
<item quantity="one">ডিভাইসটি <xliff:g id="NUMBER_1">%d</xliff:g> ঘণ্টা ধরে আনলক করা হয় নি। পাসওয়ার্ড নিশ্চিত করুন।</item>
<item quantity="other">ডিভাইসটি <xliff:g id="NUMBER_1">%d</xliff:g> ঘণ্টা ধরে আনলক করা হয় নি। পাসওয়ার্ড নিশ্চিত করুন।</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"স্বীকৃত নয়"</string>
+ <!-- no translation found for kg_fingerprint_not_recognized (7854413849848459418) -->
+ <skip />
+ <!-- no translation found for kg_face_not_recognized (6382535088345875294) -->
+ <skip />
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">সিমের পিন লিখুন। আপনি আর <xliff:g id="NUMBER_1">%d</xliff:g> বার চেষ্টা করতে পারবেন।</item>
<item quantity="other">সিমের পিন লিখুন। আপনি আর <xliff:g id="NUMBER_1">%d</xliff:g> বার চেষ্টা করতে পারবেন।</item>
diff --git a/packages/SystemUI/res-keyguard/values-bs/strings.xml b/packages/SystemUI/res-keyguard/values-bs/strings.xml
index 319014e..a87b72a 100644
--- a/packages/SystemUI/res-keyguard/values-bs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bs/strings.xml
@@ -146,7 +146,8 @@
<item quantity="few">Uređaj nije otključavan <xliff:g id="NUMBER_1">%d</xliff:g> sata. Potvrdite lozinku.</item>
<item quantity="other">Uređaj nije otključavan <xliff:g id="NUMBER_1">%d</xliff:g> sati. Potvrdite lozinku.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Nije prepoznat"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Nije prepoznat"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Nije prepoznat"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">Unesite PIN za SIM. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj.</item>
<item quantity="few">Unesite PIN za SIM. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja.</item>
diff --git a/packages/SystemUI/res-keyguard/values-ca/strings.xml b/packages/SystemUI/res-keyguard/values-ca/strings.xml
index 7b53abe..093bd1c 100644
--- a/packages/SystemUI/res-keyguard/values-ca/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ca/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Fa <xliff:g id="NUMBER_1">%d</xliff:g> hores que no es desbloqueja el dispositiu. Confirma la contrasenya.</item>
<item quantity="one">Fa <xliff:g id="NUMBER_0">%d</xliff:g> hora que no es desbloqueja el dispositiu. Confirma la contrasenya.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"No s\'ha reconegut"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"No s\'ha reconegut"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"No s\'ha reconegut"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">Introdueix el PIN de la SIM. Et queden <xliff:g id="NUMBER_1">%d</xliff:g> intents.</item>
<item quantity="one">Introdueix el PIN de la SIM. Et queda <xliff:g id="NUMBER_0">%d</xliff:g> intent; si no l\'encertes, contacta amb l\'operador de telefonia mòbil per desbloquejar el dispositiu.</item>
diff --git a/packages/SystemUI/res-keyguard/values-cs/strings.xml b/packages/SystemUI/res-keyguard/values-cs/strings.xml
index d827b25..2142c9c 100644
--- a/packages/SystemUI/res-keyguard/values-cs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-cs/strings.xml
@@ -152,7 +152,8 @@
<item quantity="other">Zařízení již <xliff:g id="NUMBER_1">%d</xliff:g> hodin nebylo odemknuto. Zadejte heslo.</item>
<item quantity="one">Zařízení již <xliff:g id="NUMBER_0">%d</xliff:g> hodinu nebylo odemknuto. Zadejte heslo.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Nerozpoznáno"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Nerozpoznáno"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Nerozpoznáno"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="few">Zadejte PIN SIM karty. Zbývají <xliff:g id="NUMBER_1">%d</xliff:g> pokusy.</item>
<item quantity="many">Zadejte PIN SIM karty. Zbývá <xliff:g id="NUMBER_1">%d</xliff:g> pokusu.</item>
diff --git a/packages/SystemUI/res-keyguard/values-da/strings.xml b/packages/SystemUI/res-keyguard/values-da/strings.xml
index b65087a..df4ab21 100644
--- a/packages/SystemUI/res-keyguard/values-da/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-da/strings.xml
@@ -140,7 +140,8 @@
<item quantity="one">Enheden blev sidst låst op for <xliff:g id="NUMBER_1">%d</xliff:g> time siden. Bekræft adgangskoden.</item>
<item quantity="other">Enheden blev sidst låst op for <xliff:g id="NUMBER_1">%d</xliff:g> timer siden. Bekræft adgangskoden.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Ikke genkendt"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Ikke genkendt"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Ikke genkendt"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">Angiv pinkoden til SIM-kortet. Du har <xliff:g id="NUMBER_1">%d</xliff:g> forsøg tilbage.</item>
<item quantity="other">Angiv pinkoden til SIM-kortet. Du har <xliff:g id="NUMBER_1">%d</xliff:g> forsøg tilbage.</item>
diff --git a/packages/SystemUI/res-keyguard/values-de/strings.xml b/packages/SystemUI/res-keyguard/values-de/strings.xml
index 8a1de2c..c86a9ad 100644
--- a/packages/SystemUI/res-keyguard/values-de/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-de/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Das Gerät wurde seit <xliff:g id="NUMBER_1">%d</xliff:g> Stunden nicht mehr entsperrt. Bitte bestätige das Passwort.</item>
<item quantity="one">Das Gerät wurde seit <xliff:g id="NUMBER_0">%d</xliff:g> Stunde nicht mehr entsperrt. Bitte bestätige das Passwort.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Nicht erkannt"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Nicht erkannt"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Nicht erkannt"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">Gib die PIN für die SIM-Karte ein. Du hast noch <xliff:g id="NUMBER_1">%d</xliff:g> Versuche.</item>
<item quantity="one">Gib die PIN für die SIM-Karte ein. Du hast noch <xliff:g id="NUMBER_0">%d</xliff:g> Versuch, bevor das Gerät nur noch vom Mobilfunkanbieter entsperrt werden kann.</item>
diff --git a/packages/SystemUI/res-keyguard/values-el/strings.xml b/packages/SystemUI/res-keyguard/values-el/strings.xml
index 2eee705..59e7669 100644
--- a/packages/SystemUI/res-keyguard/values-el/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-el/strings.xml
@@ -46,7 +46,7 @@
<string name="keyguard_missing_sim_instructions" msgid="7350295932015220392">"Τοποθετήστε μια κάρτα SIM."</string>
<string name="keyguard_missing_sim_instructions_long" msgid="589889372883904477">"Η κάρτα SIM δεν υπάρχει ή δεν είναι δυνατή η ανάγνωσή της. Τοποθετήστε μια κάρτα SIM."</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="654102080186420706">"Η κάρτα SIM δεν μπορεί να χρησιμοποιηθεί."</string>
- <string name="keyguard_permanent_disabled_sim_instructions" msgid="4683178224791318347">"Η κάρτα SIM έχει απενεργοποιηθεί οριστικά.\n Επικοινωνήστε με τον παροχέα υπηρεσιών ασύρματου δικτύου για να λάβετε μια νέα κάρτα SIM."</string>
+ <string name="keyguard_permanent_disabled_sim_instructions" msgid="4683178224791318347">"Η κάρτα SIM έχει απενεργοποιηθεί οριστικά.\n Επικοινωνήστε με τον πάροχο υπηρεσιών ασύρματου δικτύου για να λάβετε μια νέα κάρτα SIM."</string>
<string name="keyguard_sim_locked_message" msgid="953766009432168127">"Η κάρτα SIM είναι κλειδωμένη."</string>
<string name="keyguard_sim_puk_locked_message" msgid="1772789643694942073">"Η κάρτα SIM είναι κλειδωμένη με κωδικό PUK."</string>
<string name="keyguard_sim_unlock_progress_dialog_message" msgid="3586601150825821675">"Ξεκλείδωμα κάρτας SIM…"</string>
@@ -140,7 +140,8 @@
<item quantity="other">Η συσκευή δεν έχει ξεκλειδωθεί εδώ και <xliff:g id="NUMBER_1">%d</xliff:g> ώρες. Επιβεβαιώστε τον κωδικό πρόσβασης.</item>
<item quantity="one">Η συσκευή δεν έχει ξεκλειδωθεί εδώ και <xliff:g id="NUMBER_0">%d</xliff:g> ώρα. Επιβεβαιώστε τον κωδικό πρόσβασης.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Δεν αναγνωρίστηκε"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Δεν αναγνωρίστηκε"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Δεν αναγνωρίστηκε"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">Εισαγάγετε τον αριθμό PIN της κάρτας SIM. Απομένουν άλλες <xliff:g id="NUMBER_1">%d</xliff:g> προσπάθειες.</item>
<item quantity="one">Εισαγάγετε τον αριθμό PIN της κάρτας SIM. Απομένει άλλη <xliff:g id="NUMBER_0">%d</xliff:g> προσπάθεια. Στη συνέχεια, θα πρέπει να επικοινωνήσετε με τον πάροχο κινητής τηλεφωνίας, για να ξεκλειδώσετε τη συσκευή.</item>
diff --git a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
index 44ef5524..77ff1b7 100644
--- a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Device hasn\'t been unlocked for <xliff:g id="NUMBER_1">%d</xliff:g> hours. Confirm password.</item>
<item quantity="one">Device hasn\'t been unlocked for <xliff:g id="NUMBER_0">%d</xliff:g> hour. Confirm password.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Not recognised"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Not recognised"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Not recognised"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">Enter SIM PIN. You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
<item quantity="one">Enter SIM PIN. You have <xliff:g id="NUMBER_0">%d</xliff:g> remaining attempt before you must contact your operator to unlock your device.</item>
diff --git a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
index 1bddc86..dafdd32 100644
--- a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Device hasn\'t been unlocked for <xliff:g id="NUMBER_1">%d</xliff:g> hours. Confirm password.</item>
<item quantity="one">Device hasn\'t been unlocked for <xliff:g id="NUMBER_0">%d</xliff:g> hour. Confirm password.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Not recognised"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Not recognised"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Not recognised"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">Enter SIM PIN. You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
<item quantity="one">Enter SIM PIN. You have <xliff:g id="NUMBER_0">%d</xliff:g> remaining attempt before you must contact your operator to unlock your device.</item>
diff --git a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
index 44ef5524..77ff1b7 100644
--- a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Device hasn\'t been unlocked for <xliff:g id="NUMBER_1">%d</xliff:g> hours. Confirm password.</item>
<item quantity="one">Device hasn\'t been unlocked for <xliff:g id="NUMBER_0">%d</xliff:g> hour. Confirm password.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Not recognised"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Not recognised"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Not recognised"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">Enter SIM PIN. You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
<item quantity="one">Enter SIM PIN. You have <xliff:g id="NUMBER_0">%d</xliff:g> remaining attempt before you must contact your operator to unlock your device.</item>
diff --git a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
index 44ef5524..77ff1b7 100644
--- a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Device hasn\'t been unlocked for <xliff:g id="NUMBER_1">%d</xliff:g> hours. Confirm password.</item>
<item quantity="one">Device hasn\'t been unlocked for <xliff:g id="NUMBER_0">%d</xliff:g> hour. Confirm password.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Not recognised"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Not recognised"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Not recognised"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">Enter SIM PIN. You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
<item quantity="one">Enter SIM PIN. You have <xliff:g id="NUMBER_0">%d</xliff:g> remaining attempt before you must contact your operator to unlock your device.</item>
diff --git a/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml b/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml
index 987d983..5eac25c 100644
--- a/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Device hasn\'t been unlocked for <xliff:g id="NUMBER_1">%d</xliff:g> hours. Confirm password.</item>
<item quantity="one">Device hasn\'t been unlocked for <xliff:g id="NUMBER_0">%d</xliff:g> hour. Confirm password.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Not recognized"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Not recognized"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Not recognized"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">Enter SIM PIN. You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
<item quantity="one">Enter SIM PIN. You have <xliff:g id="NUMBER_0">%d</xliff:g> remaining attempt before you must contact your carrier to unlock your device.</item>
diff --git a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
index 0583d4b..8af47fd 100644
--- a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Hace <xliff:g id="NUMBER_1">%d</xliff:g> horas que no se desbloquea el dispositivo. Confirma la contraseña.</item>
<item quantity="one">Hace <xliff:g id="NUMBER_0">%d</xliff:g> hora que no se desbloquea el dispositivo. Confirma la contraseña.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"No se reconoció"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"No se reconoció"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"No se reconoció"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">Ingresa el PIN de la SIM. Quedan <xliff:g id="NUMBER_1">%d</xliff:g> intentos más.</item>
<item quantity="one">Ingresa el PIN de la SIM. Queda <xliff:g id="NUMBER_0">%d</xliff:g> intento antes de que debas comunicarte con tu proveedor para desbloquear el dispositivo.</item>
diff --git a/packages/SystemUI/res-keyguard/values-es/strings.xml b/packages/SystemUI/res-keyguard/values-es/strings.xml
index 2d6721d..92dc58f 100644
--- a/packages/SystemUI/res-keyguard/values-es/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">El dispositivo no se ha desbloqueado durante <xliff:g id="NUMBER_1">%d</xliff:g> horas. Confirma la contraseña.</item>
<item quantity="one">El dispositivo no se ha desbloqueado durante <xliff:g id="NUMBER_0">%d</xliff:g> hora. Confirma la contraseña.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"No reconocido"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"No reconocida"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"No reconocida"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">Introduce el PIN de la tarjeta SIM. Te quedan <xliff:g id="NUMBER_1">%d</xliff:g> intentos.</item>
<item quantity="one">Introduce el PIN de la tarjeta SIM. Te queda <xliff:g id="NUMBER_0">%d</xliff:g> intento para tener que ponerte en contacto con tu operador para desbloquear el dispositivo.</item>
diff --git a/packages/SystemUI/res-keyguard/values-et/strings.xml b/packages/SystemUI/res-keyguard/values-et/strings.xml
index ac37c5c..ad6becd 100644
--- a/packages/SystemUI/res-keyguard/values-et/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-et/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Seadet pole avatud <xliff:g id="NUMBER_1">%d</xliff:g> tundi. Kinnitage parool.</item>
<item quantity="one">Seadet pole avatud <xliff:g id="NUMBER_0">%d</xliff:g> tund. Kinnitage parool.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Ei tuvastatud"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Ei tuvastatud"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Ei tuvastatud"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">Sisestage SIM-kaardi PIN-kood. Jäänud on <xliff:g id="NUMBER_1">%d</xliff:g> katset.</item>
<item quantity="one">Sisestage SIM-kaardi PIN-kood. Jäänud on <xliff:g id="NUMBER_0">%d</xliff:g> katse enne, kui peate seadme avamiseks ühendust võtma operaatoriga.</item>
diff --git a/packages/SystemUI/res-keyguard/values-eu/strings.xml b/packages/SystemUI/res-keyguard/values-eu/strings.xml
index 06bb32b..4036851 100644
--- a/packages/SystemUI/res-keyguard/values-eu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-eu/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Gailua ez da desblokeatu <xliff:g id="NUMBER_1">%d</xliff:g> orduz. Berretsi pasahitza.</item>
<item quantity="one">Gailua ez da desblokeatu <xliff:g id="NUMBER_0">%d</xliff:g> orduz. Berretsi pasahitza.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Ez da ezagutu"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Ez da ezagutu"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Ez da ezagutu"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">Idatzi SIM txartelaren PIN kodea. <xliff:g id="NUMBER_1">%d</xliff:g> saiakera geratzen zaizkizu.</item>
<item quantity="one">Idatzi SIM txartelaren PIN kodea. <xliff:g id="NUMBER_0">%d</xliff:g> saiakera geratzen zaizu; oker idatziz gero, operadoreari eskatu beharko diozu gailua desblokeatzeko.</item>
diff --git a/packages/SystemUI/res-keyguard/values-fa/strings.xml b/packages/SystemUI/res-keyguard/values-fa/strings.xml
index f273d6e..3b1d8d7 100644
--- a/packages/SystemUI/res-keyguard/values-fa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fa/strings.xml
@@ -140,7 +140,8 @@
<item quantity="one">قفل دستگاه <xliff:g id="NUMBER_1">%d</xliff:g> ساعت باز نشده است. گذرواژه را تأیید کنید.</item>
<item quantity="other">قفل دستگاه <xliff:g id="NUMBER_1">%d</xliff:g> ساعت باز نشده است. گذرواژه را تأیید کنید.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"شناسایی نشد"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"شناسایی نشد"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"شناسایی نشد"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">پین سیمکارت را وارد کنید. <xliff:g id="NUMBER_1">%d</xliff:g> تلاش دیگری باقی مانده است.</item>
<item quantity="other">پین سیمکارت را وارد کنید. <xliff:g id="NUMBER_1">%d</xliff:g> تلاش دیگری باقی مانده است.</item>
diff --git a/packages/SystemUI/res-keyguard/values-fi/strings.xml b/packages/SystemUI/res-keyguard/values-fi/strings.xml
index 5267151..34d830f 100644
--- a/packages/SystemUI/res-keyguard/values-fi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fi/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Laitteen lukitusta ei ole avattu <xliff:g id="NUMBER_1">%d</xliff:g> tuntiin. Vahvista salasana.</item>
<item quantity="one">Laitteen lukitusta ei ole avattu <xliff:g id="NUMBER_0">%d</xliff:g> tuntiin. Vahvista salasana.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Ei tunnistettu"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Ei tunnistettu"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Ei tunnistettu"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">Anna SIM-kortin PIN-koodi. Sinulla on <xliff:g id="NUMBER_1">%d</xliff:g> yritystä jäljellä.</item>
<item quantity="one">Anna SIM-kortin PIN-koodi. <xliff:g id="NUMBER_0">%d</xliff:g> yrityksen jälkeen laite lukittuu, ja vain operaattori voi avata sen.</item>
diff --git a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
index 742e1eb..c344807 100644
--- a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
@@ -140,7 +140,8 @@
<item quantity="one">L\'appareil n\'a pas été déverrouillé depuis <xliff:g id="NUMBER_1">%d</xliff:g> heure. Confirmez le mot de passe.</item>
<item quantity="other">L\'appareil n\'a pas été déverrouillé depuis <xliff:g id="NUMBER_1">%d</xliff:g> heures. Confirmez le mot de passe.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Doigt non reconnu"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Doigt non reconnu"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Doigt non reconnu"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">Entrez le NIP de votre carte SIM. Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentative.</item>
<item quantity="other">Entrez le NIP de votre carte SIM. Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentatives.</item>
diff --git a/packages/SystemUI/res-keyguard/values-fr/strings.xml b/packages/SystemUI/res-keyguard/values-fr/strings.xml
index 9ada218..bf8c7e8 100644
--- a/packages/SystemUI/res-keyguard/values-fr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr/strings.xml
@@ -140,7 +140,8 @@
<item quantity="one">L\'appareil n\'a pas été déverrouillé depuis <xliff:g id="NUMBER_1">%d</xliff:g> heure. Confirmez le mot de passe.</item>
<item quantity="other">L\'appareil n\'a pas été déverrouillé depuis <xliff:g id="NUMBER_1">%d</xliff:g> heures. Confirmez le mot de passe.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Non reconnu"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Non reconnu"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Non reconnu"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">Saisissez le code de la carte SIM. <xliff:g id="NUMBER_1">%d</xliff:g> tentative restante.</item>
<item quantity="other">Saisissez le code de la carte SIM. <xliff:g id="NUMBER_1">%d</xliff:g> tentatives restantes.</item>
diff --git a/packages/SystemUI/res-keyguard/values-gl/strings.xml b/packages/SystemUI/res-keyguard/values-gl/strings.xml
index 4a8fe8a..b4ff9ea 100644
--- a/packages/SystemUI/res-keyguard/values-gl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gl/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">O dispositivo non se desbloqueou durante <xliff:g id="NUMBER_1">%d</xliff:g> horas. Confirma o contrasinal.</item>
<item quantity="one">O dispositivo non se desbloqueou durante <xliff:g id="NUMBER_0">%d</xliff:g> hora. Confirma o contrasinal.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Non se recoñece"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Non se recoñeceu"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Non se recoñeceu"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">Introduce o código PIN da SIM. Quédanche <xliff:g id="NUMBER_1">%d</xliff:g> intentos.</item>
<item quantity="one">Introduce o código PIN da SIM. Quédache <xliff:g id="NUMBER_0">%d</xliff:g> intento antes de que teñas que contactar co operador para desbloquear o dispositivo.</item>
diff --git a/packages/SystemUI/res-keyguard/values-gu/strings.xml b/packages/SystemUI/res-keyguard/values-gu/strings.xml
index 6a10af5..e2cd09b 100644
--- a/packages/SystemUI/res-keyguard/values-gu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gu/strings.xml
@@ -140,7 +140,10 @@
<item quantity="one">ઉપકરણને <xliff:g id="NUMBER_1">%d</xliff:g> કલાક માટે અનલૉક કરવામાં આવ્યું નથી. પાસવર્ડની પુષ્ટિ કરો.</item>
<item quantity="other">ઉપકરણને <xliff:g id="NUMBER_1">%d</xliff:g> કલાક માટે અનલૉક કરવામાં આવ્યું નથી. પાસવર્ડની પુષ્ટિ કરો.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"ઓળખાયેલ નથી"</string>
+ <!-- no translation found for kg_fingerprint_not_recognized (7854413849848459418) -->
+ <skip />
+ <!-- no translation found for kg_face_not_recognized (6382535088345875294) -->
+ <skip />
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">સિમનો પિન દાખલ કરો, તમારી પાસે <xliff:g id="NUMBER_1">%d</xliff:g> પ્રયાસ બાકી છે.</item>
<item quantity="other">સિમનો પિન દાખલ કરો, તમારી પાસે <xliff:g id="NUMBER_1">%d</xliff:g> પ્રયાસો બાકી છે.</item>
diff --git a/packages/SystemUI/res-keyguard/values-hi/strings.xml b/packages/SystemUI/res-keyguard/values-hi/strings.xml
index 553f663..539efd9 100644
--- a/packages/SystemUI/res-keyguard/values-hi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hi/strings.xml
@@ -140,7 +140,10 @@
<item quantity="one">डिवाइस को <xliff:g id="NUMBER_1">%d</xliff:g> घंटों से अनलॉक नहीं किया गया है. पासवर्ड की पुष्टि करें.</item>
<item quantity="other">डिवाइस को <xliff:g id="NUMBER_1">%d</xliff:g> घंटों से अनलॉक नहीं किया गया है. पासवर्ड की पुष्टि करें.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"उंगली की पहचान नहीं हो सकी"</string>
+ <!-- no translation found for kg_fingerprint_not_recognized (7854413849848459418) -->
+ <skip />
+ <!-- no translation found for kg_face_not_recognized (6382535088345875294) -->
+ <skip />
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">सिम का पिन डालें. आपके पास <xliff:g id="NUMBER_1">%d</xliff:g> मौके बचे हैं.</item>
<item quantity="other">सिम का पिन डालें. आपके पास <xliff:g id="NUMBER_1">%d</xliff:g> मौके बचे हैं.</item>
diff --git a/packages/SystemUI/res-keyguard/values-hr/strings.xml b/packages/SystemUI/res-keyguard/values-hr/strings.xml
index 7485cef..6ae39b2 100644
--- a/packages/SystemUI/res-keyguard/values-hr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hr/strings.xml
@@ -146,7 +146,8 @@
<item quantity="few">Uređaj nije bio otključan <xliff:g id="NUMBER_1">%d</xliff:g> sata. Potvrdite zaporku.</item>
<item quantity="other">Uređaj nije bio otključan <xliff:g id="NUMBER_1">%d</xliff:g> sati. Potvrdite zaporku.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Nije prepoznat"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Nije prepoznat"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Nije prepoznato"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">Unesite PIN za SIM. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj.</item>
<item quantity="few">Unesite PIN za SIM. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja.</item>
diff --git a/packages/SystemUI/res-keyguard/values-hu/strings.xml b/packages/SystemUI/res-keyguard/values-hu/strings.xml
index 371bc64..a03a8b2 100644
--- a/packages/SystemUI/res-keyguard/values-hu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hu/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Az eszköz zárolása <xliff:g id="NUMBER_1">%d</xliff:g> órája nem lett feloldva. Erősítse meg a jelszót.</item>
<item quantity="one">Az eszköz zárolása <xliff:g id="NUMBER_0">%d</xliff:g> órája nem lett feloldva. Erősítse meg a jelszót.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Nem sikerült felismerni"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Nem ismerhető fel"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Nem ismerhető fel"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">Adja meg a SIM-kártya PIN-kódját. <xliff:g id="NUMBER_1">%d</xliff:g> próbálkozása maradt.</item>
<item quantity="one">Adja meg a SIM-kártya PIN-kódját. <xliff:g id="NUMBER_0">%d</xliff:g> próbálkozása maradt. Ha elfogynak a próbálkozási lehetőségek, az eszköz feloldásához fel kell vennie a kapcsolatot szolgáltatójával.</item>
diff --git a/packages/SystemUI/res-keyguard/values-hy/strings.xml b/packages/SystemUI/res-keyguard/values-hy/strings.xml
index 92cb87a..8009371 100644
--- a/packages/SystemUI/res-keyguard/values-hy/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hy/strings.xml
@@ -140,7 +140,8 @@
<item quantity="one">Device hasn\'t been unlocked for <xliff:g id="NUMBER_1">%d</xliff:g> hours. Confirm password.</item>
<item quantity="other">Սարքը չի ապակողպվել <xliff:g id="NUMBER_1">%d</xliff:g> ժամվա ընթացքում: Հաստատեք գաղտնաբառը:</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Չճանաչվեց"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Չհաջողվեց ճանաչել"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Չհաջողվեց ճանաչել"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">Մուտքագրեք SIM քարտի PIN կոդը: Մնացել է <xliff:g id="NUMBER_1">%d</xliff:g> փորձ:</item>
<item quantity="other">Մուտքագրեք SIM քարտի PIN կոդը: Մնացել է <xliff:g id="NUMBER_1">%d</xliff:g> փորձ:</item>
diff --git a/packages/SystemUI/res-keyguard/values-in/strings.xml b/packages/SystemUI/res-keyguard/values-in/strings.xml
index c0c828b..c1a20c6 100644
--- a/packages/SystemUI/res-keyguard/values-in/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-in/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Perangkat belum dibuka kuncinya selama <xliff:g id="NUMBER_1">%d</xliff:g> jam. Konfirmasi sandi.</item>
<item quantity="one">Perangkat belum dibuka kuncinya selama <xliff:g id="NUMBER_0">%d</xliff:g> jam. Konfirmasi sandi.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Tidak dikenali"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Tidak dikenali"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Tidak dikenali"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">Masukkan PIN SIM. Tersisa <xliff:g id="NUMBER_1">%d</xliff:g> percobaan.</item>
<item quantity="one">Masukkan PIN SIM. Tersisa <xliff:g id="NUMBER_0">%d</xliff:g> percobaan sebelum Anda harus menghubungi operator untuk membuka kunci perangkat.</item>
diff --git a/packages/SystemUI/res-keyguard/values-is/strings.xml b/packages/SystemUI/res-keyguard/values-is/strings.xml
index dad5e69..0800b3e 100644
--- a/packages/SystemUI/res-keyguard/values-is/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-is/strings.xml
@@ -140,7 +140,8 @@
<item quantity="one">Tækið hefur ekki verið tekið úr lás í <xliff:g id="NUMBER_1">%d</xliff:g> klukkustund. Staðfestu aðgangsorðið.</item>
<item quantity="other">Tækið hefur ekki verið tekið úr lás í <xliff:g id="NUMBER_1">%d</xliff:g> klukkustundir. Staðfestu aðgangsorðið.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Þekktist ekki"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Þekktist ekki"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Þekktist ekki"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">Sláðu inn PIN-númer SIM-korts. Þú átt <xliff:g id="NUMBER_1">%d</xliff:g> tilraun eftir.</item>
<item quantity="other">Sláðu inn PIN-númer SIM-korts. Þú átt <xliff:g id="NUMBER_1">%d</xliff:g> tilraunir eftir.</item>
diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml
index 2f322e8..07830c2 100644
--- a/packages/SystemUI/res-keyguard/values-it/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-it/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Il dispositivo non viene sbloccato da <xliff:g id="NUMBER_1">%d</xliff:g> ore. Conferma la password.</item>
<item quantity="one">Il dispositivo non viene sbloccato da <xliff:g id="NUMBER_0">%d</xliff:g> ora. Conferma la password.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Non riconosciuta"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Non riconosciuta"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Non riconosciuta"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">Inserisci il codice PIN della SIM. Hai ancora <xliff:g id="NUMBER_1">%d</xliff:g> tentativi a disposizione.</item>
<item quantity="one">Inserisci il codice PIN della SIM. Hai ancora <xliff:g id="NUMBER_0">%d</xliff:g> tentativo a disposizione, dopodiché dovrai contattare l\'operatore per sbloccare il dispositivo.</item>
diff --git a/packages/SystemUI/res-keyguard/values-iw/strings.xml b/packages/SystemUI/res-keyguard/values-iw/strings.xml
index cfffcd2..6ed4e5f 100644
--- a/packages/SystemUI/res-keyguard/values-iw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-iw/strings.xml
@@ -152,7 +152,8 @@
<item quantity="other">נעילת המכשיר לא בוטלה במשך <xliff:g id="NUMBER_1">%d</xliff:g> שעות. הזן את הסיסמה.</item>
<item quantity="one">נעילת המכשיר לא בוטלה במשך <xliff:g id="NUMBER_0">%d</xliff:g> שעה. הזן את הסיסמה.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"לא זוהתה"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"לא זוהתה"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"לא זוהתה"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="two">יש להזין קוד גישה לכרטיס SIM. נותרו לך <xliff:g id="NUMBER_1">%d</xliff:g> ניסונות נוספים.</item>
<item quantity="many">יש להזין קוד גישה לכרטיס SIM. נותרו לך <xliff:g id="NUMBER_1">%d</xliff:g> ניסונות נוספים.</item>
diff --git a/packages/SystemUI/res-keyguard/values-ja/strings.xml b/packages/SystemUI/res-keyguard/values-ja/strings.xml
index 98e8ce0..c9acb55 100644
--- a/packages/SystemUI/res-keyguard/values-ja/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ja/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">端末のロックが <xliff:g id="NUMBER_1">%d</xliff:g> 時間、解除されていません。パスワードを確認してください。</item>
<item quantity="one">端末のロックが <xliff:g id="NUMBER_0">%d</xliff:g> 時間、解除されていません。パスワードを確認してください。</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"認識されませんでした"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"認識されませんでした"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"認識されませんでした"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">SIM PIN を入力してください。入力できるのはあと <xliff:g id="NUMBER_1">%d</xliff:g> 回です。</item>
<item quantity="one">SIM PIN を入力してください。入力できるのはあと <xliff:g id="NUMBER_0">%d</xliff:g> 回です。この回数を超えた場合は、携帯通信会社にお問い合わせください。</item>
diff --git a/packages/SystemUI/res-keyguard/values-ka/strings.xml b/packages/SystemUI/res-keyguard/values-ka/strings.xml
index df96979..c5f415b 100644
--- a/packages/SystemUI/res-keyguard/values-ka/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ka/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">მოწყობილობა არ განბლოკილა <xliff:g id="NUMBER_1">%d</xliff:g> საათის განმავლობაში. დაადასტურეთ პაროლი.</item>
<item quantity="one">მოწყობილობა არ განბლოკილა <xliff:g id="NUMBER_0">%d</xliff:g> საათის განმავლობაში. დაადასტურეთ პაროლი.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"არ არის ამოცნობილი"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"არ არის ამოცნობილი"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"არ არის ამოცნობილი"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">შეიყვანეთ SIM ბარათის PIN-კოდი. თქვენ დაგრჩათ <xliff:g id="NUMBER_1">%d</xliff:g> მცდელობა.</item>
<item quantity="one">შეიყვანეთ SIM ბარათის PIN-კოდი. თქვენ დაგრჩათ <xliff:g id="NUMBER_0">%d</xliff:g> მცდელობა, რომლის შემდეგაც მოწყობილობის განსაბლოკად დაგჭირდებათ თქვენს ოპერატორთან დაკავშირება.</item>
diff --git a/packages/SystemUI/res-keyguard/values-kk/strings.xml b/packages/SystemUI/res-keyguard/values-kk/strings.xml
index 6ed9f44..d206bcb 100644
--- a/packages/SystemUI/res-keyguard/values-kk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kk/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Құрылғы құлпы <xliff:g id="NUMBER_1">%d</xliff:g> сағаттан бері ашылмаған. Құпия сөзді растаңыз.</item>
<item quantity="one">Құрылғы құлпы <xliff:g id="NUMBER_0">%d</xliff:g> сағаттан бері ашылмаған. Құпия сөзді растаңыз.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Анықталмады"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Танылмады"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Танылмады"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">SIM PIN кодын енгізіңіз. <xliff:g id="NUMBER_1">%d</xliff:g> мүмкіндік қалды, одан кейін оператордан SIM картасының құлпын ашуды сұрауға тура келеді.</item>
<item quantity="one">SIM PIN кодын енгізіңіз. <xliff:g id="NUMBER_0">%d</xliff:g> мүмкіндік қалды, одан кейін оператордан SIM картасының құлпын ашуды сұрауға тура келеді.</item>
diff --git a/packages/SystemUI/res-keyguard/values-km/strings.xml b/packages/SystemUI/res-keyguard/values-km/strings.xml
index f7960e5..d38aa3f 100644
--- a/packages/SystemUI/res-keyguard/values-km/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-km/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">ឧបករណ៍បានជាប់សោអស់រយៈពេល <xliff:g id="NUMBER_1">%d</xliff:g> ម៉ោងហើយ។ សូមបញ្ជាក់ពាក្យសម្ងាត់។</item>
<item quantity="one">ឧបករណ៍បានជាប់សោអស់រយៈពេល <xliff:g id="NUMBER_0">%d</xliff:g> ម៉ោងហើយ។ សូមបញ្ជាក់ពាក្យសម្ងាត់។</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"មិនអាចសម្គាល់បានទេ"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"មិនអាចសម្គាល់បានទេ"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"មិនអាចសម្គាល់បានទេ"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">បញ្ចូលកូដ PIN របស់ស៊ីម។ អ្នកនៅសល់ការព្យាយាម <xliff:g id="NUMBER_1">%d</xliff:g> ដងទៀត។</item>
<item quantity="one">បញ្ចូលកូដ PIN របស់ស៊ីម។ អ្នកនៅសល់ការព្យាយាម <xliff:g id="NUMBER_0">%d</xliff:g> ដងទៀត មុនពេលដែលអ្នកត្រូវទាក់ទងទៅក្រុមហ៊ុនសេវាទូរសព្ទរបស់អ្នកដើម្បីដោះសោឧបករណ៍របស់អ្នក។</item>
diff --git a/packages/SystemUI/res-keyguard/values-kn/strings.xml b/packages/SystemUI/res-keyguard/values-kn/strings.xml
index e6b03f9..a435608 100644
--- a/packages/SystemUI/res-keyguard/values-kn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kn/strings.xml
@@ -140,7 +140,10 @@
<item quantity="one">ಸಾಧನವನ್ನು <xliff:g id="NUMBER_1">%d</xliff:g> ಗಂಟೆಗಳವರೆಗೆ ಅನ್ಲಾಕ್ ಮಾಡಿರಲಿಲ್ಲ. ಪಾಸ್ವರ್ಡ್ ಖಚಿತಪಡಿಸಿ.</item>
<item quantity="other">ಸಾಧನವನ್ನು <xliff:g id="NUMBER_1">%d</xliff:g> ಗಂಟೆಗಳವರೆಗೆ ಅನ್ಲಾಕ್ ಮಾಡಿರಲಿಲ್ಲ. ಪಾಸ್ವರ್ಡ್ ಖಚಿತಪಡಿಸಿ.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"ಗುರುತಿಸಲಾಗಿಲ್ಲ"</string>
+ <!-- no translation found for kg_fingerprint_not_recognized (7854413849848459418) -->
+ <skip />
+ <!-- no translation found for kg_face_not_recognized (6382535088345875294) -->
+ <skip />
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">ಸಿಮ್ ಪಿನ್ ನಮೂದಿಸಿ. ನಿಮ್ಮಲ್ಲಿ <xliff:g id="NUMBER_1">%d</xliff:g> ಪ್ರಯತ್ನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ.</item>
<item quantity="other">ಸಿಮ್ ಪಿನ್ ನಮೂದಿಸಿ. ನಿಮ್ಮಲ್ಲಿ <xliff:g id="NUMBER_1">%d</xliff:g> ಪ್ರಯತ್ನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ.</item>
diff --git a/packages/SystemUI/res-keyguard/values-ko/strings.xml b/packages/SystemUI/res-keyguard/values-ko/strings.xml
index ffdb1e5..87359ca 100644
--- a/packages/SystemUI/res-keyguard/values-ko/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ko/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">기기가 <xliff:g id="NUMBER_1">%d</xliff:g>시간 동안 잠금 해제되지 않았습니다. 비밀번호를 입력하세요.</item>
<item quantity="one">기기가 <xliff:g id="NUMBER_0">%d</xliff:g>시간 동안 잠금 해제되지 않았습니다. 비밀번호를 입력하세요.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"인식할 수 없음"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"인식할 수 없음"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"인식할 수 없음"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">SIM PIN을 입력하세요. 입력은 <xliff:g id="NUMBER_1">%d</xliff:g>번 더 시도할 수 있습니다.</item>
<item quantity="one">SIM PIN을 입력하세요. 입력에 <xliff:g id="NUMBER_0">%d</xliff:g>번 더 실패하면 이동통신사에 문의하여 기기를 잠금 해제해야 합니다.</item>
diff --git a/packages/SystemUI/res-keyguard/values-ky/strings.xml b/packages/SystemUI/res-keyguard/values-ky/strings.xml
index 80ae050..832e5af 100644
--- a/packages/SystemUI/res-keyguard/values-ky/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ky/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Түзмөктүн кулпусу <xliff:g id="NUMBER_1">%d</xliff:g> саат бою ачылган жок. Сырсөздү ырастаңыз.</item>
<item quantity="one">Түзмөктүн кулпусу <xliff:g id="NUMBER_0">%d</xliff:g> саат бою ачылган жок. Сырсөздү ырастаңыз.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Таанылган жок"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Таанылган жок"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Таанылган жок"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">SIM-картанын PIN кодун киргизиңиз. Сизде <xliff:g id="NUMBER_1">%d</xliff:g> аракет калды.</item>
<item quantity="one">SIM-картанын PIN кодун киргизиңиз. Сизде <xliff:g id="NUMBER_0">%d</xliff:g> аракет калды, андан кийин түзмөктү бөгөттөн чыгаруу үчүн байланыш операторуна кайрылышыңыз керек болот.</item>
diff --git a/packages/SystemUI/res-keyguard/values-lo/strings.xml b/packages/SystemUI/res-keyguard/values-lo/strings.xml
index b05915a..4d66dfe 100644
--- a/packages/SystemUI/res-keyguard/values-lo/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lo/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">ອຸປະກອນບໍ່ໄດ້ຖືກປົດລັອກເປັນເວລາ <xliff:g id="NUMBER_1">%d</xliff:g> ຊົ່ວໂມງ. ຢືນຢັນລະຫັດຜ່ານ.</item>
<item quantity="one">ອຸປະກອນບໍ່ໄດ້ຖືກປົດລັອກເປັນເວລາ <xliff:g id="NUMBER_0">%d</xliff:g> ຊົ່ວໂມງ. ຢືນຢັນລະຫັດຜ່ານ.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"ບໍ່ຮັບຮູ້"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"ບໍ່ຮູ້ຈັກ"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"ບໍ່ຮູ້ຈັກ"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">ລະຫັດ SIM PIN ບໍ່ຖືກຕ້ອງ. ທ່ານສາມາດລອງໄດ້ອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ເທື່ອ.</item>
<item quantity="one">ໃສ່ລະຫັດ SIM PIN. ທ່ານສາມາດລອງໄດ້ອີກ <xliff:g id="NUMBER_0">%d</xliff:g> ເທື່ອກ່ອນທີ່ຈະຕ້ອງຕິດຕໍ່ຜູ້ໃຫ້ບໍລິການເພື່ອປົດລັອກ.</item>
diff --git a/packages/SystemUI/res-keyguard/values-lt/strings.xml b/packages/SystemUI/res-keyguard/values-lt/strings.xml
index 5cd696f..18404e0 100644
--- a/packages/SystemUI/res-keyguard/values-lt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lt/strings.xml
@@ -152,7 +152,8 @@
<item quantity="many">Įrenginys nebuvo atrakintas <xliff:g id="NUMBER_1">%d</xliff:g> valandos. Patvirtinkite slaptažodį.</item>
<item quantity="other">Įrenginys nebuvo atrakintas <xliff:g id="NUMBER_1">%d</xliff:g> valandų. Patvirtinkite slaptažodį.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Neatpažinta"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Neatpažinta"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Neatpažinta"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">Įveskite SIM kortelės PIN kodą. Jums liko <xliff:g id="NUMBER_1">%d</xliff:g> bandymas.</item>
<item quantity="few">Įveskite SIM kortelės PIN kodą. Jums liko <xliff:g id="NUMBER_1">%d</xliff:g> bandymai.</item>
diff --git a/packages/SystemUI/res-keyguard/values-lv/strings.xml b/packages/SystemUI/res-keyguard/values-lv/strings.xml
index d4f6020..9ec52cf 100644
--- a/packages/SystemUI/res-keyguard/values-lv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lv/strings.xml
@@ -146,7 +146,8 @@
<item quantity="one">Ierīce nav tikusi atbloķēta <xliff:g id="NUMBER_1">%d</xliff:g> stundu. Apstipriniet paroli.</item>
<item quantity="other">Ierīce nav tikusi atbloķēta <xliff:g id="NUMBER_1">%d</xliff:g> stundas. Apstipriniet paroli.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Nav atpazīts"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Nav atpazīts"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Nav atpazīts"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="zero">Ievadiet SIM kartes PIN. Varat mēģināt vēl <xliff:g id="NUMBER_1">%d</xliff:g> reizes.</item>
<item quantity="one">Ievadiet SIM kartes PIN. Varat mēģināt vēl <xliff:g id="NUMBER_1">%d</xliff:g> reizi.</item>
diff --git a/packages/SystemUI/res-keyguard/values-mk/strings.xml b/packages/SystemUI/res-keyguard/values-mk/strings.xml
index aff4803..0685a10 100644
--- a/packages/SystemUI/res-keyguard/values-mk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mk/strings.xml
@@ -140,7 +140,8 @@
<item quantity="one">Уредот не е отклучен веќе <xliff:g id="NUMBER_1">%d</xliff:g> час. Потврдете ја лозинката.</item>
<item quantity="other">Уредот не е отклучен веќе <xliff:g id="NUMBER_1">%d</xliff:g> часа. Потврдете ја лозинката.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Непознат"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Непознат"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Непознат"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">Внесете PIN-код за SIM-картичката. Ви преостанува уште <xliff:g id="NUMBER_1">%d</xliff:g> обид.</item>
<item quantity="other">Внесете PIN-код за SIM-картичката. Ви преостануваат уште <xliff:g id="NUMBER_1">%d</xliff:g> обиди.</item>
diff --git a/packages/SystemUI/res-keyguard/values-ml/strings.xml b/packages/SystemUI/res-keyguard/values-ml/strings.xml
index d3283e1..c6aadb0 100644
--- a/packages/SystemUI/res-keyguard/values-ml/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ml/strings.xml
@@ -140,7 +140,10 @@
<item quantity="other">ഉപകരണം <xliff:g id="NUMBER_1">%d</xliff:g> മണിക്കൂറായി അൺലോക്ക് ചെയ്തിട്ടില്ല. പാസ്വേഡ് സ്ഥിരീകരിക്കുക.</item>
<item quantity="one">ഉപകരണം <xliff:g id="NUMBER_0">%d</xliff:g> മണിക്കൂറായി അൺലോക്ക് ചെയ്തിട്ടില്ല. പാസ്വേഡ് സ്ഥിരീകരിക്കുക.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"തിരിച്ചറിഞ്ഞില്ല"</string>
+ <!-- no translation found for kg_fingerprint_not_recognized (7854413849848459418) -->
+ <skip />
+ <!-- no translation found for kg_face_not_recognized (6382535088345875294) -->
+ <skip />
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">സിം പിൻ നൽകുക. നിങ്ങൾക്ക് <xliff:g id="NUMBER_1">%d</xliff:g> ശ്രമങ്ങൾ കൂടി ശേഷിക്കുന്നു.</item>
<item quantity="one">സിം പിൻ നൽകുക. ഉപകരണം അൺലോക്ക് ചെയ്യാൻ കാരിയറുമായി ബന്ധപ്പെടേണ്ടിവരുന്നതിന് മുമ്പ് <xliff:g id="NUMBER_0">%d</xliff:g> ശ്രമം കൂടി ശേഷിക്കുന്നു.</item>
diff --git a/packages/SystemUI/res-keyguard/values-mn/strings.xml b/packages/SystemUI/res-keyguard/values-mn/strings.xml
index 99c7339..3c1870d 100644
--- a/packages/SystemUI/res-keyguard/values-mn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mn/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Төхөөрөмжийн түгжээг <xliff:g id="NUMBER_1">%d</xliff:g> цагийн турш тайлаагүй байна. Нууц үгээ баталгаажуулна уу.</item>
<item quantity="one">Төхөөрөмжийн түгжээг <xliff:g id="NUMBER_0">%d</xliff:g> цагийн турш тайлаагүй байна. Нууц үгээ баталгаажуулна уу.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Танигдахгүй байна"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Таньж чадсангүй"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Таньж чадсангүй"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">SIM-н ПИН кодыг оруулна уу. Танд <xliff:g id="NUMBER_1">%d</xliff:g> оролдлого үлдлээ.</item>
<item quantity="one">SIM-н ПИН кодыг оруулна уу. Танд оператор компанитайгаа холбогдохгүйгээр төхөөрөмжийн түгжээг тайлах <xliff:g id="NUMBER_0">%d</xliff:g> оролдлого үлдлээ.</item>
diff --git a/packages/SystemUI/res-keyguard/values-mr/strings.xml b/packages/SystemUI/res-keyguard/values-mr/strings.xml
index 16a9d63..88724ce9 100644
--- a/packages/SystemUI/res-keyguard/values-mr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mr/strings.xml
@@ -140,7 +140,10 @@
<item quantity="one">डिव्हाइस <xliff:g id="NUMBER_1">%d</xliff:g> तासासाठी अनलॉक केले गेले नाही. पासवर्डची खात्री करा.</item>
<item quantity="other">डिव्हाइस <xliff:g id="NUMBER_1">%d</xliff:g> तासांसाठी अनलॉक केले गेले नाही. पासवर्डची खात्री करा.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"ओळखले नाही"</string>
+ <!-- no translation found for kg_fingerprint_not_recognized (7854413849848459418) -->
+ <skip />
+ <!-- no translation found for kg_face_not_recognized (6382535088345875294) -->
+ <skip />
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">सिम पिन एंटर करा, तुमच्याकडे <xliff:g id="NUMBER_1">%d</xliff:g> प्रयत्न शिल्लक आहे.</item>
<item quantity="other">सिम पिन एंटर करा, तुमच्याकडे <xliff:g id="NUMBER_1">%d</xliff:g> प्रयत्न शिल्लक आहेत.</item>
diff --git a/packages/SystemUI/res-keyguard/values-ms/strings.xml b/packages/SystemUI/res-keyguard/values-ms/strings.xml
index 19e53d5..bec3295 100644
--- a/packages/SystemUI/res-keyguard/values-ms/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ms/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Peranti tidak dibuka kuncinya selama <xliff:g id="NUMBER_1">%d</xliff:g> jam. Sahkan kata laluan.</item>
<item quantity="one">Peranti tidak dibuka kuncinya selama <xliff:g id="NUMBER_0">%d</xliff:g> jam. Sahkan kata laluan.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Tidak dikenali"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Tidak dikenali"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Tidak dikenali"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">Masukkan PIN SIM. Tinggal <xliff:g id="NUMBER_1">%d</xliff:g> percubaan lagi.</item>
<item quantity="one">Masukkan PIN SIM. Tinggal <xliff:g id="NUMBER_0">%d</xliff:g> percubaan lagi sebelum anda perlu menghubungi pembawa anda untuk membuka kunci peranti.</item>
diff --git a/packages/SystemUI/res-keyguard/values-my/strings.xml b/packages/SystemUI/res-keyguard/values-my/strings.xml
index c9a2e1c..017bf0a 100644
--- a/packages/SystemUI/res-keyguard/values-my/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-my/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">စက်ပစ္စည်းကို <xliff:g id="NUMBER_1">%d</xliff:g> နာရီကြာ လော့ခ်ဖွင့်ခဲ့ခြင်း မရှိပါ။ စကားဝှက်အား အတည်ပြုပါ။</item>
<item quantity="one">စက်ပစ္စည်းကို <xliff:g id="NUMBER_0">%d</xliff:g> နာရီကြာ လော့ခ်ဖွင့်ခဲ့ခြင်း မရှိပါ။ စကားဝှက်အား အတည်ပြုပါ။</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"မသိပါ"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"မသိပါ"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"မသိပါ"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">ဆင်းမ်ကဒ် ပင်နံပါတ် ထည့်ပါ။ <xliff:g id="NUMBER_1">%d</xliff:g> ကြိမ် စမ်းသပ်ခွင့်ရှိပါသေးသည်။</item>
<item quantity="one">ဆင်းမ်ကဒ် ပင်နံပါတ် ထည့်ပါ။ သင့်စက်ကို လော့ခ်ဖွင့်ပေးရန်အတွက် ဝန်ဆောင်မှုပေးသူသို့ မဆက်သွယ်မီ <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် စမ်းသပ်ခွင့်ရှိပါသေးသည်။</item>
diff --git a/packages/SystemUI/res-keyguard/values-nb/strings.xml b/packages/SystemUI/res-keyguard/values-nb/strings.xml
index 4573596..125ffb0 100644
--- a/packages/SystemUI/res-keyguard/values-nb/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nb/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Enheten har ikke blitt låst opp de siste <xliff:g id="NUMBER_1">%d</xliff:g> timene. Bekreft passordet.</item>
<item quantity="one">Enheten har ikke blitt låst opp på <xliff:g id="NUMBER_0">%d</xliff:g> time. Bekreft passordet.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Ikke gjenkjent"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Ikke gjenkjent"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Ikke gjenkjent"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">Skriv inn PIN-koden for SIM-kortet. Du har <xliff:g id="NUMBER_1">%d</xliff:g> forsøk igjen.</item>
<item quantity="one">Skriv inn PIN-koden for SIM-kortet. Du har <xliff:g id="NUMBER_0">%d</xliff:g> forsøk igjen før du må kontakte operatøren din for å låse opp enheten.</item>
diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml
index 3f6b749..ccb78d1 100644
--- a/packages/SystemUI/res-keyguard/values-ne/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml
@@ -140,7 +140,10 @@
<item quantity="other">यन्त्र <xliff:g id="NUMBER_1">%d</xliff:g> घन्टा देखि अनलक भएको छैन। पासवर्ड पुष्टि गर्नुहोस्।</item>
<item quantity="one">यन्त्र <xliff:g id="NUMBER_0">%d</xliff:g> घन्टा देखि अनलक भएको छैन। पासवर्ड पुष्टि गर्नुहोस्।</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"पहिचान भएन"</string>
+ <!-- no translation found for kg_fingerprint_not_recognized (7854413849848459418) -->
+ <skip />
+ <!-- no translation found for kg_face_not_recognized (6382535088345875294) -->
+ <skip />
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">SIM को PIN प्रविष्ट गर्नुहोस्। तपाईंसँग <xliff:g id="NUMBER_1">%d</xliff:g> प्रयासहरू बाँकी छन्।</item>
<item quantity="one">SIM को PIN प्रविष्ट गर्नुहोस्। तपाईंसँग <xliff:g id="NUMBER_0">%d</xliff:g> प्रयास बाँकी छ, त्यसपछि भने आफ्नो यन्त्र अनलक गर्नका लागि तपाईंले अनिवार्य रूपमा आफ्नो सेवा प्रदायकलाई सम्पर्क गर्नु पर्ने हुन्छ।</item>
diff --git a/packages/SystemUI/res-keyguard/values-nl/strings.xml b/packages/SystemUI/res-keyguard/values-nl/strings.xml
index e2f5806..cf0cff2 100644
--- a/packages/SystemUI/res-keyguard/values-nl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nl/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Apparaat is al <xliff:g id="NUMBER_1">%d</xliff:g> uur niet ontgrendeld. Bevestig het wachtwoord.</item>
<item quantity="one">Apparaat is al <xliff:g id="NUMBER_0">%d</xliff:g> uur niet ontgrendeld. Bevestig het wachtwoord.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Niet herkend"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Niet herkend"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Niet herkend"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">Geef de pincode van de simkaart op. Je hebt nog <xliff:g id="NUMBER_1">%d</xliff:g> pogingen over.</item>
<item quantity="one">Geef de pincode van de simkaart op. Je hebt nog <xliff:g id="NUMBER_0">%d</xliff:g> poging over voordat je contact met je provider moet opnemen om het apparaat te ontgrendelen.</item>
diff --git a/packages/SystemUI/res-keyguard/values-or/strings.xml b/packages/SystemUI/res-keyguard/values-or/strings.xml
index 1ffce78..6d94626 100644
--- a/packages/SystemUI/res-keyguard/values-or/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-or/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> ଘଣ୍ଟା ପାଇଁ ଡିଭାଇସ୍ ଅନଲକ୍ କରାଯାଇ ନାହିଁ। ପାସୱର୍ଡ ସୁନିଶ୍ଚିତ କରନ୍ତୁ</item>
<item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> ଘଣ୍ଟା ପାଇଁ ଡିଭାଇସ୍ ଅନଲକ୍ କରାଯାଇ ନାହିଁ। ପାସୱର୍ଡ ସୁନିଶ୍ଚିତ କରନ୍ତୁ</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"ଚିହ୍ନଟ ହେଲାନାହିଁ"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"ଚିହ୍ନଟ ହେଲାନାହିଁ"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"ଚିହ୍ନଟ ହେଲାନାହିଁ"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">SIM PIN ପ୍ରବେଶ କରନ୍ତୁ। ଆପଣଙ୍କ ପାଇଁ <xliff:g id="NUMBER_1">%d</xliff:g>ଟି ପ୍ରୟାସ ବଳକା ଅଛି।</item>
<item quantity="one">SIM PIN ପ୍ରବେଶ କରନ୍ତୁ। ଆପଣଙ୍କ ଡିଭାଇସ୍କୁ ଅନଲକ୍ କରିବା ପାଇଁ ପାଖରେ ବଳକା ଥିବା <xliff:g id="NUMBER_0">%d</xliff:g>ଟି ପ୍ରୟାସର ବ୍ୟବହାର କରିବା ପୂର୍ବରୁ ନିଜର କେରିଅର୍ଙ୍କୁ ସମ୍ପର୍କ କରନ୍ତୁ।</item>
diff --git a/packages/SystemUI/res-keyguard/values-pa/strings.xml b/packages/SystemUI/res-keyguard/values-pa/strings.xml
index e1379f6..498151c 100644
--- a/packages/SystemUI/res-keyguard/values-pa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pa/strings.xml
@@ -140,7 +140,10 @@
<item quantity="one">ਡੀਵਾਈਸ <xliff:g id="NUMBER_1">%d</xliff:g> ਘੰਟੇ ਤੋਂ ਅਣਲਾਕ ਨਹੀਂ ਕੀਤਾ ਗਿਆ ਹੈ। ਪਾਸਵਰਡ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ</item>
<item quantity="other">ਡੀਵਾਈਸ <xliff:g id="NUMBER_1">%d</xliff:g> ਘੰਟਿਆਂ ਤੋਂ ਅਣਲਾਕ ਨਹੀਂ ਕੀਤਾ ਗਿਆ ਹੈ। ਪਾਸਵਰਡ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"ਪਛਾਣ ਨਹੀਂ ਹੋਈ"</string>
+ <!-- no translation found for kg_fingerprint_not_recognized (7854413849848459418) -->
+ <skip />
+ <!-- no translation found for kg_face_not_recognized (6382535088345875294) -->
+ <skip />
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">ਸਿਮ ਪਿੰਨ ਦਾਖਲ ਕਰੋ। ਤੁਹਾਡੇ ਕੋਲ <xliff:g id="NUMBER_1">%d</xliff:g> ਕੋਸ਼ਿਸ਼ ਬਾਕੀ ਹੈ।</item>
<item quantity="other">ਸਿਮ ਪਿੰਨ ਦਾਖਲ ਕਰੋ। ਤੁਹਾਡੇ ਕੋਲ <xliff:g id="NUMBER_1">%d</xliff:g> ਕੋਸ਼ਿਸ਼ਾਂ ਬਾਕੀ ਹਨ।</item>
diff --git a/packages/SystemUI/res-keyguard/values-pl/strings.xml b/packages/SystemUI/res-keyguard/values-pl/strings.xml
index 8376a36..538135f 100644
--- a/packages/SystemUI/res-keyguard/values-pl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pl/strings.xml
@@ -152,7 +152,8 @@
<item quantity="other">Urządzenie nie zostało odblokowane od <xliff:g id="NUMBER_1">%d</xliff:g> godziny. Potwierdź hasło.</item>
<item quantity="one">Urządzenie nie zostało odblokowane od <xliff:g id="NUMBER_0">%d</xliff:g> godziny. Potwierdź hasło.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Nie rozpoznano"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Nie rozpoznano"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Nie rozpoznano"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="few">Wpisz kod PIN karty SIM. Masz jeszcze <xliff:g id="NUMBER_1">%d</xliff:g> próby.</item>
<item quantity="many">Wpisz kod PIN karty SIM. Masz jeszcze <xliff:g id="NUMBER_1">%d</xliff:g> prób.</item>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
index 8970560..13508b7 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
@@ -140,7 +140,8 @@
<item quantity="one">O dispositivo não é desbloqueado há <xliff:g id="NUMBER_1">%d</xliff:g> hora. Confirme a senha.</item>
<item quantity="other">O dispositivo não é desbloqueado há <xliff:g id="NUMBER_1">%d</xliff:g> horas. Confirme a senha.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Não reconhecido"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Não reconhecido"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Não reconhecido"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">Informe o PIN do SIM. Você tem <xliff:g id="NUMBER_1">%d</xliff:g> tentativa restante.</item>
<item quantity="other">Informe o PIN do SIM. Você tem <xliff:g id="NUMBER_1">%d</xliff:g> tentativas restantes.</item>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
index a2f8aea..c87799a 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">O dispositivo não é desbloqueado há <xliff:g id="NUMBER_1">%d</xliff:g> horas. Confirme a palavra-passe.</item>
<item quantity="one">O dispositivo não é desbloqueado há <xliff:g id="NUMBER_0">%d</xliff:g> hora. Confirme a palavra-passe.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Não reconhecido"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Não reconhecido."</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Não reconhecido."</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">Introduza o PIN do cartão SIM. Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas.</item>
<item quantity="one">Introduza o PIN do cartão SIM. Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de ser necessário contactar o operador para desbloquear o dispositivo.</item>
diff --git a/packages/SystemUI/res-keyguard/values-pt/strings.xml b/packages/SystemUI/res-keyguard/values-pt/strings.xml
index 8970560..13508b7 100644
--- a/packages/SystemUI/res-keyguard/values-pt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt/strings.xml
@@ -140,7 +140,8 @@
<item quantity="one">O dispositivo não é desbloqueado há <xliff:g id="NUMBER_1">%d</xliff:g> hora. Confirme a senha.</item>
<item quantity="other">O dispositivo não é desbloqueado há <xliff:g id="NUMBER_1">%d</xliff:g> horas. Confirme a senha.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Não reconhecido"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Não reconhecido"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Não reconhecido"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">Informe o PIN do SIM. Você tem <xliff:g id="NUMBER_1">%d</xliff:g> tentativa restante.</item>
<item quantity="other">Informe o PIN do SIM. Você tem <xliff:g id="NUMBER_1">%d</xliff:g> tentativas restantes.</item>
diff --git a/packages/SystemUI/res-keyguard/values-ro/strings.xml b/packages/SystemUI/res-keyguard/values-ro/strings.xml
index 148772b..3741157 100644
--- a/packages/SystemUI/res-keyguard/values-ro/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ro/strings.xml
@@ -146,7 +146,8 @@
<item quantity="other">Dispozitivul nu a fost deblocat de <xliff:g id="NUMBER_1">%d</xliff:g> de ore. Confirmați parola.</item>
<item quantity="one">Dispozitivul nu a fost deblocat de <xliff:g id="NUMBER_0">%d</xliff:g> oră. Confirmați parola.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Nu este recunoscută"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Nu este recunoscută"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Nu este recunoscut"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="few">Introduceți codul PIN pentru cardul SIM. V-au mai rămas <xliff:g id="NUMBER_1">%d</xliff:g> încercări.</item>
<item quantity="other">Introduceți codul PIN pentru cardul SIM. V-au mai rămas <xliff:g id="NUMBER_1">%d</xliff:g> de încercări.</item>
diff --git a/packages/SystemUI/res-keyguard/values-ru/strings.xml b/packages/SystemUI/res-keyguard/values-ru/strings.xml
index c6d06aa..5fc9af7 100644
--- a/packages/SystemUI/res-keyguard/values-ru/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ru/strings.xml
@@ -152,7 +152,8 @@
<item quantity="many">Устройство не разблокировалось в течение <xliff:g id="NUMBER_1">%d</xliff:g> часов. Введите пароль ещё раз.</item>
<item quantity="other">Устройство не разблокировалось в течение <xliff:g id="NUMBER_1">%d</xliff:g> часа. Введите пароль ещё раз.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Не распознано"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Не распознано"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Не распознано"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">Введите PIN-код. Осталась <xliff:g id="NUMBER_1">%d</xliff:g> попытка.</item>
<item quantity="few">Введите PIN-код. Осталось <xliff:g id="NUMBER_1">%d</xliff:g> попытки.</item>
diff --git a/packages/SystemUI/res-keyguard/values-si/strings.xml b/packages/SystemUI/res-keyguard/values-si/strings.xml
index 7e3b635..dd99e8b 100644
--- a/packages/SystemUI/res-keyguard/values-si/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-si/strings.xml
@@ -140,7 +140,8 @@
<item quantity="one">උපාංගය පැය <xliff:g id="NUMBER_1">%d</xliff:g>ක් අගුලු හැර නැත. මුරපදය තහවුරු කරන්න.</item>
<item quantity="other">උපාංගය පැය <xliff:g id="NUMBER_1">%d</xliff:g>ක් අගුලු හැර නැත. මුරපදය තහවුරු කරන්න.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"හඳුනා නොගන්නා ලදී"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"හඳුනා නොගන්නා ලදී"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"හඳුනා නොගන්නා ලදී"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">SIM PIN ඇතුළු කරන්න, ඔබ සතුව උත්සාහයන් <xliff:g id="NUMBER_1">%d</xliff:g>ක් ඉතිරිව ඇත.</item>
<item quantity="other">SIM PIN ඇතුළු කරන්න, ඔබ සතුව උත්සාහයන් <xliff:g id="NUMBER_1">%d</xliff:g>ක් ඉතිරිව ඇත.</item>
diff --git a/packages/SystemUI/res-keyguard/values-sk/strings.xml b/packages/SystemUI/res-keyguard/values-sk/strings.xml
index a0cd7a5..868e0f6 100644
--- a/packages/SystemUI/res-keyguard/values-sk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sk/strings.xml
@@ -152,7 +152,8 @@
<item quantity="other">Zariadenie nebolo odomknuté <xliff:g id="NUMBER_1">%d</xliff:g> hodín. Potvrďte heslo.</item>
<item quantity="one">Zariadenie nebolo odomknuté <xliff:g id="NUMBER_0">%d</xliff:g> hodinu. Potvrďte heslo.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Nerozpoznané"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Nerozpoznané"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Nerozpoznané"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="few">Zadajte kód PIN SIM karty. Zostávajú vám <xliff:g id="NUMBER_1">%d</xliff:g> pokusy.</item>
<item quantity="many">Enter SIM PIN. You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
diff --git a/packages/SystemUI/res-keyguard/values-sl/strings.xml b/packages/SystemUI/res-keyguard/values-sl/strings.xml
index 6bcae3e..9be4dbd 100644
--- a/packages/SystemUI/res-keyguard/values-sl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sl/strings.xml
@@ -152,7 +152,8 @@
<item quantity="few">Naprava ni bila odklenjena <xliff:g id="NUMBER_1">%d</xliff:g> ure. Potrdite geslo.</item>
<item quantity="other">Naprava ni bila odklenjena <xliff:g id="NUMBER_1">%d</xliff:g> ur. Potrdite geslo.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Ni prepoznano"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Ni prepoznano"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Ni prepoznano"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">Vnesite kodo PIN kartice SIM. Na voljo imate še <xliff:g id="NUMBER_1">%d</xliff:g> poskus.</item>
<item quantity="two">Vnesite kodo PIN kartice SIM. Na voljo imate še <xliff:g id="NUMBER_1">%d</xliff:g> poskusa.</item>
diff --git a/packages/SystemUI/res-keyguard/values-sq/strings.xml b/packages/SystemUI/res-keyguard/values-sq/strings.xml
index dca23885..e92b9b6 100644
--- a/packages/SystemUI/res-keyguard/values-sq/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sq/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Pajisja nuk është shkyçur për <xliff:g id="NUMBER_1">%d</xliff:g> orë. Konfirmo fjalëkalimin.</item>
<item quantity="one">Pajisja nuk është shkyçur për <xliff:g id="NUMBER_0">%d</xliff:g> orë. Konfirmo fjalëkalimin.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Nuk njihet"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Nuk njihet"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Nuk njihet"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">Fut kodin PIN të kartës SIM. Të kanë mbetur edhe <xliff:g id="NUMBER_1">%d</xliff:g> tentativa.</item>
<item quantity="one">Fut kodin PIN të kartës SIM. Të ka mbetur edhe <xliff:g id="NUMBER_0">%d</xliff:g> tentativë para se të duhet të kontaktosh me operatorin tënd celular për ta shkyçur pajisjen.</item>
diff --git a/packages/SystemUI/res-keyguard/values-sr/strings.xml b/packages/SystemUI/res-keyguard/values-sr/strings.xml
index 6882333..b146603 100644
--- a/packages/SystemUI/res-keyguard/values-sr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sr/strings.xml
@@ -146,7 +146,8 @@
<item quantity="few">Нисте откључали уређај <xliff:g id="NUMBER_1">%d</xliff:g> сата. Потврдите лозинку.</item>
<item quantity="other">Нисте откључали уређај <xliff:g id="NUMBER_1">%d</xliff:g> сати. Потврдите лозинку.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Није препознат"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Није препознат"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Није препознат"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">Унесите PIN за SIM. Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушај.</item>
<item quantity="few">Унесите PIN за SIM. Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушаја.</item>
diff --git a/packages/SystemUI/res-keyguard/values-sv/strings.xml b/packages/SystemUI/res-keyguard/values-sv/strings.xml
index e8fd26e..ba5c346 100644
--- a/packages/SystemUI/res-keyguard/values-sv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sv/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Enheten har inte låsts upp på <xliff:g id="NUMBER_1">%d</xliff:g> timmar. Bekräfta lösenordet.</item>
<item quantity="one">Enheten har inte låsts upp på <xliff:g id="NUMBER_0">%d</xliff:g> timme. Bekräfta lösenordet.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Identifierades inte"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Identifierades inte"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Identifierades inte"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">Ange pinkod för SIM-kortet. <xliff:g id="NUMBER_1">%d</xliff:g> försök återstår.</item>
<item quantity="one">Ange pinkod för SIM-kortet. <xliff:g id="NUMBER_0">%d</xliff:g> försök återstår innan du måste kontakta operatören för att låsa upp enheten.</item>
diff --git a/packages/SystemUI/res-keyguard/values-sw/strings.xml b/packages/SystemUI/res-keyguard/values-sw/strings.xml
index 3dc496a..6376b61 100644
--- a/packages/SystemUI/res-keyguard/values-sw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sw/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Hujafungua kifaa kwa saa <xliff:g id="NUMBER_1">%d</xliff:g>. Thibitisha nenosiri.</item>
<item quantity="one">Hujafungua kifaa kwa saa <xliff:g id="NUMBER_0">%d</xliff:g>. Thibitisha nenosiri.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Haikutambua alama ya kidole"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Haikutambua alama ya kidole"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Haitambuliwi"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">Weka PIN ya SIM. Zimesalia mara <xliff:g id="NUMBER_1">%d</xliff:g> za kujaribu.</item>
<item quantity="one">Weka PIN ya SIM. Ukijaribu tena mara <xliff:g id="NUMBER_0">%d</xliff:g> bila kufaulu, kifaa chako kitafungwa na utalazimika uwasiliane na mtoa huduma wako ili akifungue.</item>
diff --git a/packages/SystemUI/res-keyguard/values-ta/strings.xml b/packages/SystemUI/res-keyguard/values-ta/strings.xml
index ae05463..44968c3 100644
--- a/packages/SystemUI/res-keyguard/values-ta/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ta/strings.xml
@@ -140,7 +140,10 @@
<item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> மணிநேரமாகச் சாதனம் திறக்கப்படவில்லை. கடவுச்சொல்லை உறுதிப்படுத்தவும்.</item>
<item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> மணிநேரமாகச் சாதனம் திறக்கப்படவில்லை. கடவுச்சொல்லை உறுதிப்படுத்தவும்.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"அடையாளங்காண முடியவில்லை"</string>
+ <!-- no translation found for kg_fingerprint_not_recognized (7854413849848459418) -->
+ <skip />
+ <!-- no translation found for kg_face_not_recognized (6382535088345875294) -->
+ <skip />
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">சிம் பின்னை உள்ளிடவும். மேலும், <xliff:g id="NUMBER_1">%d</xliff:g> வாய்ப்புகள் மீதமுள்ளன.</item>
<item quantity="one">சிம் பின்னை உள்ளிடவும். மீதமுள்ள <xliff:g id="NUMBER_0">%d</xliff:g> வாய்ப்பில் தவறுதலான பின் உள்ளிடப்பட்டால், உங்கள் தொலைத்தொடர்பு நிறுவனத்தைத் தொடர்பு கொண்டு மட்டுமே சாதனத்தைத் திறக்க முடியும்.</item>
diff --git a/packages/SystemUI/res-keyguard/values-te/strings.xml b/packages/SystemUI/res-keyguard/values-te/strings.xml
index 2f0377f..2597a55 100644
--- a/packages/SystemUI/res-keyguard/values-te/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-te/strings.xml
@@ -140,7 +140,10 @@
<item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> గంటల పాటు పరికరాన్ని అన్లాక్ చేయలేదు. పాస్వర్డ్ని నమోదు చేయండి.</item>
<item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> గంట పాటు పరికరాన్ని అన్లాక్ చేయలేదు. పాస్వర్డ్ని నమోదు చేయండి.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"గుర్తించలేదు"</string>
+ <!-- no translation found for kg_fingerprint_not_recognized (7854413849848459418) -->
+ <skip />
+ <!-- no translation found for kg_face_not_recognized (6382535088345875294) -->
+ <skip />
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">SIM పిన్ని నమోదు చేయండి. మీకు <xliff:g id="NUMBER_1">%d</xliff:g> ప్రయత్నలు మిగిలి ఉన్నాయి.</item>
<item quantity="one">SIM పిన్ని నమోదు చేయండి, మీరు మీ పరికరాన్ని అన్లాక్ చేయడానికి తప్పనిసరిగా మీ క్యారియర్ను సంప్రదించడానికి ముందు మీకు <xliff:g id="NUMBER_0">%d</xliff:g> ప్రయత్నం మిగిలి ఉంది.</item>
diff --git a/packages/SystemUI/res-keyguard/values-th/strings.xml b/packages/SystemUI/res-keyguard/values-th/strings.xml
index 92a5a08..52d7f1f 100644
--- a/packages/SystemUI/res-keyguard/values-th/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-th/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">ไม่มีการปลดล็อกอุปกรณ์มา <xliff:g id="NUMBER_1">%d</xliff:g> ชั่วโมงแล้ว ยืนยันรหัสผ่าน</item>
<item quantity="one">ไม่มีการปลดล็อกอุปกรณ์มา <xliff:g id="NUMBER_0">%d</xliff:g> ชั่วโมงแล้ว ยืนยันรหัสผ่าน</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"ไม่รู้จัก"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"ไม่รู้จัก"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"ไม่รู้จัก"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">โปรดป้อน PIN ของซิม คุณพยายามได้อีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง</item>
<item quantity="one">โปรดป้อน PIN ของซิม คุณพยายามได้อีก <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งก่อนที่จะต้องติดต่อผู้ให้บริการเพื่อปลดล็อกอุปกรณ์</item>
diff --git a/packages/SystemUI/res-keyguard/values-tl/strings.xml b/packages/SystemUI/res-keyguard/values-tl/strings.xml
index b993167..eb4f2ca 100644
--- a/packages/SystemUI/res-keyguard/values-tl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-tl/strings.xml
@@ -140,7 +140,8 @@
<item quantity="one">Hindi na-unlock ang device sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> oras. Kumpirmahin ang password.</item>
<item quantity="other">Hindi na-unlock ang device sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> na oras. Kumpirmahin ang password.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Hindi nakilala"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Hindi nakilala"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Hindi nakilala"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">Ilagay ang PIN ng SIM. Mayroon kang <xliff:g id="NUMBER_1">%d</xliff:g> natitirang pagsubok.</item>
<item quantity="other">Ilagay ang PIN ng SIM. Mayroon kang <xliff:g id="NUMBER_1">%d</xliff:g> na natitirang pagsubok.</item>
diff --git a/packages/SystemUI/res-keyguard/values-tr/strings.xml b/packages/SystemUI/res-keyguard/values-tr/strings.xml
index 399134a..a7d870a 100644
--- a/packages/SystemUI/res-keyguard/values-tr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-tr/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Cihazın kilidi son <xliff:g id="NUMBER_1">%d</xliff:g> saattir açılmadı. Şifreyi doğrulayın.</item>
<item quantity="one">Cihazın kilidi son <xliff:g id="NUMBER_0">%d</xliff:g> saattir açılmadı. Şifreyi doğrulayın.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Tanınmadı"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Tanınmadı"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Tanınmadı"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">SIM PIN\'inizi girin. <xliff:g id="NUMBER_1">%d</xliff:g> deneme hakkınız kaldı.</item>
<item quantity="one">SIM PIN\'inizi girin. Cihazınızın kilidini açmak için operatörünüzle bağlantı kurmak zorunda kalmadan önce <xliff:g id="NUMBER_0">%d</xliff:g> deneme hakkınız kaldı.</item>
diff --git a/packages/SystemUI/res-keyguard/values-uk/strings.xml b/packages/SystemUI/res-keyguard/values-uk/strings.xml
index 821257e..5f5bfc3 100644
--- a/packages/SystemUI/res-keyguard/values-uk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uk/strings.xml
@@ -152,7 +152,8 @@
<item quantity="many">Ви не розблоковували пристрій <xliff:g id="NUMBER_1">%d</xliff:g> годин. Підтвердьте пароль.</item>
<item quantity="other">Ви не розблоковували пристрій <xliff:g id="NUMBER_1">%d</xliff:g> години. Підтвердьте пароль.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Не розпізнано"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Не розпізнано"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Не розпізнано"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">Введіть PIN-код SIM-карти. Залишилася <xliff:g id="NUMBER_1">%d</xliff:g> спроба.</item>
<item quantity="few">Введіть PIN-код SIM-карти. Залишилося <xliff:g id="NUMBER_1">%d</xliff:g> спроби.</item>
diff --git a/packages/SystemUI/res-keyguard/values-ur/strings.xml b/packages/SystemUI/res-keyguard/values-ur/strings.xml
index bfbc70f..3e7aaee 100644
--- a/packages/SystemUI/res-keyguard/values-ur/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ur/strings.xml
@@ -140,7 +140,10 @@
<item quantity="other">آلہ <xliff:g id="NUMBER_1">%d</xliff:g> گھنٹوں سے غیر مقفل نہیں کیا گيا۔ پاسورڈ کی توثیق کریں۔</item>
<item quantity="one">آلہ <xliff:g id="NUMBER_0">%d</xliff:g> گھنٹہ سے غیر مقفل نہیں کیا گیا۔ پاسورڈ کی توثیق کریں۔</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"تسلیم شدہ نہیں ہے"</string>
+ <!-- no translation found for kg_fingerprint_not_recognized (7854413849848459418) -->
+ <skip />
+ <!-- no translation found for kg_face_not_recognized (6382535088345875294) -->
+ <skip />
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">SIM کا PIN درج کریں، آپ کے پاس <xliff:g id="NUMBER_1">%d</xliff:g> کوششیں بچی ہیں۔</item>
<item quantity="one">SIM کا PIN درج کریں، آپ کے پاس <xliff:g id="NUMBER_0">%d</xliff:g> کوشش بچی ہے، اس کے بعد آپ کو اپنا آلہ غیر مقفل کرنے کے لیے اپنے کیریئر سے رابطہ کرنا ہوگا۔</item>
diff --git a/packages/SystemUI/res-keyguard/values-uz/strings.xml b/packages/SystemUI/res-keyguard/values-uz/strings.xml
index ad7a0dc..277fa8b 100644
--- a/packages/SystemUI/res-keyguard/values-uz/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uz/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Qurilma <xliff:g id="NUMBER_1">%d</xliff:g> soatdan beri qulfdan chiqarilgani yo‘q. Parolni yana bir marta kiriting.</item>
<item quantity="one">Qurilma <xliff:g id="NUMBER_0">%d</xliff:g> soatdan beri qulfdan chiqarilgani yo‘q. Parolni yana bir marta kiriting.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Barmoq izi aniqlanmadi"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Aniqlanmadi"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Aniqlanmadi"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">SIM PIN kodini kiriting, sizda <xliff:g id="NUMBER_1">%d</xliff:g> ta urinish bor.</item>
<item quantity="one">SIM PIN kodini kiriting, qurilmani qulfdan chiqarish uchun sizda <xliff:g id="NUMBER_0">%d</xliff:g> ta urinish bor.</item>
diff --git a/packages/SystemUI/res-keyguard/values-vi/strings.xml b/packages/SystemUI/res-keyguard/values-vi/strings.xml
index 1a2d6b4..d851ceb 100644
--- a/packages/SystemUI/res-keyguard/values-vi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-vi/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">Thiết bị đã không được mở khóa trong <xliff:g id="NUMBER_1">%d</xliff:g> giờ. Xác nhận mật khẩu.</item>
<item quantity="one">Thiết bị đã không được mở khóa trong <xliff:g id="NUMBER_0">%d</xliff:g> giờ. Xác nhận mật khẩu.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Không nhận dạng được"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Không nhận dạng được"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Không nhận dạng được"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">Hãy nhập mã PIN của SIM. Bạn còn <xliff:g id="NUMBER_1">%d</xliff:g> lần thử.</item>
<item quantity="one">Hãy nhập mã PIN của SIM. Bạn còn <xliff:g id="NUMBER_0">%d</xliff:g> lần thử trước khi phải liên hệ với nhà mạng để mở khóa thiết bị của mình.</item>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
index f6576b3..693a31b 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
@@ -140,7 +140,10 @@
<item quantity="other">设备已保持锁定状态达 <xliff:g id="NUMBER_1">%d</xliff:g> 小时。请确认密码。</item>
<item quantity="one">设备已保持锁定状态达 <xliff:g id="NUMBER_0">%d</xliff:g> 小时。请确认密码。</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"无法识别"</string>
+ <!-- no translation found for kg_fingerprint_not_recognized (7854413849848459418) -->
+ <skip />
+ <!-- no translation found for kg_face_not_recognized (6382535088345875294) -->
+ <skip />
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">请输入 SIM 卡 PIN 码,您还可以尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次。</item>
<item quantity="one">请输入 SIM 卡 PIN 码,您还可以尝试 <xliff:g id="NUMBER_0">%d</xliff:g> 次。如果仍不正确,则需要联系运营商帮您解锁设备。</item>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
index af238dd..539bb92 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">裝置在過去 <xliff:g id="NUMBER_1">%d</xliff:g> 小時內未有解鎖,請確認密碼。</item>
<item quantity="one">裝置在過去 <xliff:g id="NUMBER_0">%d</xliff:g> 小時內未有解鎖,請確認密碼。</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"未能識別"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"未能識別"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"未能識別"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">輸入 SIM 卡的 PIN,您還可以再試 <xliff:g id="NUMBER_1">%d</xliff:g> 次。</item>
<item quantity="one">輸入 SIM 卡的 PIN,您還可以再試 <xliff:g id="NUMBER_0">%d</xliff:g> 次。如果仍然輸入錯誤,您必須聯絡流動網絡供應商解鎖您的裝置。</item>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
index b8cdfc3..6e5e984 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
@@ -140,7 +140,8 @@
<item quantity="other">裝置已有 <xliff:g id="NUMBER_1">%d</xliff:g> 小時未解鎖。請確認密碼。</item>
<item quantity="one">裝置已有 <xliff:g id="NUMBER_0">%d</xliff:g> 小時未解鎖。請確認密碼。</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"無法識別"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"無法識別"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"無法識別"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="other">請輸入 SIM 卡的 PIN 碼,你還可以再試 <xliff:g id="NUMBER_1">%d</xliff:g> 次。</item>
<item quantity="one">請輸入 SIM 卡的 PIN 碼,你還可以再試 <xliff:g id="NUMBER_0">%d</xliff:g> 次。如果仍然失敗,就必須請電信業者為裝置解鎖。</item>
diff --git a/packages/SystemUI/res-keyguard/values-zu/strings.xml b/packages/SystemUI/res-keyguard/values-zu/strings.xml
index 5409638..78bb66c 100644
--- a/packages/SystemUI/res-keyguard/values-zu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zu/strings.xml
@@ -140,7 +140,8 @@
<item quantity="one">Idivayisi ayikavulwa ngamahora angu-<xliff:g id="NUMBER_1">%d</xliff:g>. Qinisekisa iphasiwedi.</item>
<item quantity="other">Idivayisi ayikavulwa ngamahora angu-<xliff:g id="NUMBER_1">%d</xliff:g>. Qinisekisa iphasiwedi.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="348813995267914625">"Akubonwa"</string>
+ <string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Akwaziwa"</string>
+ <string name="kg_face_not_recognized" msgid="6382535088345875294">"Akwaziwa"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
<item quantity="one">Faka i-PIN ye-SIM, unemizamo engu-<xliff:g id="NUMBER_1">%d</xliff:g> esele.</item>
<item quantity="other">Faka i-PIN ye-SIM, unemizamo engu-<xliff:g id="NUMBER_1">%d</xliff:g> esele.</item>
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 513d848..6bc0965 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -381,7 +381,10 @@
</plurals>
<!-- Fingerprint hint message when finger was not recognized.-->
- <string name="fingerprint_not_recognized">Not recognized</string>
+ <string name="kg_fingerprint_not_recognized">Not recognized</string>
+
+ <!-- Face hint message when finger was not recognized. [CHAR LIMIT=20] -->
+ <string name="kg_face_not_recognized">Not recognized</string>
<!-- Instructions telling the user remaining times when enter SIM PIN view. -->
<plurals name="kg_password_default_pin_message">
diff --git a/packages/SystemUI/res/drawable-hdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-hdpi/qs_scrubber_track.9.png
deleted file mode 100644
index 0899d35..0000000
--- a/packages/SystemUI/res/drawable-hdpi/qs_scrubber_track.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-mdpi/qs_scrubber_track.9.png
deleted file mode 100644
index 2266449..0000000
--- a/packages/SystemUI/res/drawable-mdpi/qs_scrubber_track.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-xhdpi/qs_scrubber_track.9.png
deleted file mode 100644
index 3328add..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/qs_scrubber_track.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-xxhdpi/qs_scrubber_track.9.png
deleted file mode 100644
index ed651da..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/qs_scrubber_track.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-xxxhdpi/qs_scrubber_track.9.png
deleted file mode 100644
index 06e1202..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/qs_scrubber_track.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/faster_emergency_icon.xml b/packages/SystemUI/res/drawable/faster_emergency_icon.xml
new file mode 100644
index 0000000..208ff41
--- /dev/null
+++ b/packages/SystemUI/res/drawable/faster_emergency_icon.xml
@@ -0,0 +1,30 @@
+<!--
+Copyright (C) 2018 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.
+-->
+<!-- TODO: For demo only, will change content after UI team provide new faster emergency icon. -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="#D93025"
+ android:pathData="M0,0h24v24H0z" />
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M19,3H5c-1.1,0-1.99,0.9,-1.99,2L3,19c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5c0-1.1-0.9-2-2-2zm-1,11h-4v4h-4v-4H6v-4h4V6h4v4h4v4z" />
+
+</vector>
diff --git a/packages/SystemUI/res/layout/global_actions_wrapped.xml b/packages/SystemUI/res/layout/global_actions_wrapped.xml
index b715def..7f4e0d2 100644
--- a/packages/SystemUI/res/layout/global_actions_wrapped.xml
+++ b/packages/SystemUI/res/layout/global_actions_wrapped.xml
@@ -3,7 +3,9 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:layout_gravity="top|right"
android:layout_marginBottom="0dp"
+ android:orientation="vertical"
android:paddingTop="@dimen/global_actions_top_padding"
android:clipToPadding="false"
android:theme="@style/qs_theme"
@@ -17,7 +19,19 @@
android:layout_gravity="top|right"
android:gravity="center"
android:orientation="vertical"
- android:padding="12dp"
- android:translationZ="9dp" />
+ android:padding="@dimen/global_actions_padding"
+ android:translationZ="@dimen/global_actions_translate" />
+
+ <!-- For separated button-->
+ <FrameLayout
+ android:id="@+id/separated_button"
+ android:layout_width="@dimen/global_actions_panel_width"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|right"
+ android:layout_marginTop="6dp"
+ android:gravity="center"
+ android:orientation="vertical"
+ android:padding="@dimen/global_actions_padding"
+ android:translationZ="@dimen/global_actions_translate" />
</com.android.systemui.HardwareUiLayout>
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 88d19f4..28466fd 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -161,30 +161,31 @@
style="@style/TextAppearance.NotificationInfo.Button"/>
</LinearLayout>
</LinearLayout>
- <RelativeLayout
+ <com.android.systemui.statusbar.NotificationUndoLayout
android:id="@+id/confirmation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/notification_guts_button_spacing"
- android:layout_marginTop="@dimen/notification_guts_button_spacing"
- android:layout_marginStart="@dimen/notification_guts_button_side_margin"
- android:layout_marginEnd="@dimen/notification_guts_button_side_margin"
android:visibility="gone"
android:orientation="horizontal" >
<TextView
android:id="@+id/confirmation_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_centerVertical="true"
+ android:layout_gravity="start|center_vertical"
+ android:layout_marginStart="@*android:dimen/notification_content_margin_start"
+ android:layout_marginEnd="@*android:dimen/notification_content_margin_start"
android:text="@string/notification_channel_disabled"
style="@style/TextAppearance.NotificationInfo.Confirmation"/>
<TextView
android:id="@+id/undo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_alignParentEnd="true"
- android:layout_centerVertical="true"
+ android:layout_marginTop="@dimen/notification_guts_button_spacing"
+ android:layout_marginBottom="@dimen/notification_guts_button_spacing"
+ android:layout_marginStart="@dimen/notification_guts_button_side_margin"
+ android:layout_marginEnd="@dimen/notification_guts_button_side_margin"
+ android:layout_gravity="end|center_vertical"
android:text="@string/inline_undo"
style="@style/TextAppearance.NotificationInfo.Button"/>
- </RelativeLayout>
+ </com.android.systemui.statusbar.NotificationUndoLayout>
</com.android.systemui.statusbar.NotificationInfo>
diff --git a/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml b/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml
index 25b117f..f13f019 100644
--- a/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml
+++ b/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml
@@ -43,7 +43,7 @@
android:layout_weight="0"
android:paddingStart="@dimen/screen_pinning_request_frame_padding"
android:paddingEnd="@dimen/screen_pinning_request_frame_padding"
- android:theme="@*android:style/ThemeOverlay.DeviceDefault.Accent">
+ android:theme="@style/ScreenPinningRequestTheme">
<ImageView
android:id="@+id/screen_pinning_back_bg_light"
@@ -86,7 +86,7 @@
android:layout_weight="0"
android:paddingStart="@dimen/screen_pinning_request_frame_padding"
android:paddingEnd="@dimen/screen_pinning_request_frame_padding"
- android:theme="@*android:style/ThemeOverlay.DeviceDefault.Accent">
+ android:theme="@style/ScreenPinningRequestTheme">
<ImageView
android:id="@+id/screen_pinning_home_bg_light"
@@ -129,7 +129,7 @@
android:layout_weight="0"
android:paddingStart="@dimen/screen_pinning_request_frame_padding"
android:paddingEnd="@dimen/screen_pinning_request_frame_padding"
- android:theme="@*android:style/ThemeOverlay.DeviceDefault.Accent">
+ android:theme="@style/ScreenPinningRequestTheme">
<ImageView
android:id="@+id/screen_pinning_recents_bg_light"
diff --git a/packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml b/packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml
index 367c13c..420b072 100644
--- a/packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml
+++ b/packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml
@@ -39,7 +39,7 @@
android:layout_height="@dimen/screen_pinning_request_button_width"
android:layout_width="@dimen/screen_pinning_request_button_height"
android:layout_weight="0"
- android:theme="@*android:style/ThemeOverlay.DeviceDefault.Accent">
+ android:theme="@style/ScreenPinningRequestTheme">
<ImageView
android:id="@+id/screen_pinning_recents_bg_light"
@@ -79,7 +79,7 @@
android:layout_height="@dimen/screen_pinning_request_button_width"
android:layout_width="@dimen/screen_pinning_request_button_height"
android:layout_weight="0"
- android:theme="@*android:style/ThemeOverlay.DeviceDefault.Accent">
+ android:theme="@style/ScreenPinningRequestTheme">
<ImageView
android:id="@+id/screen_pinning_home_bg_light"
@@ -120,7 +120,7 @@
android:layout_height="@dimen/screen_pinning_request_button_width"
android:layout_width="@dimen/screen_pinning_request_button_height"
android:layout_weight="0"
- android:theme="@*android:style/ThemeOverlay.DeviceDefault.Accent">
+ android:theme="@style/ScreenPinningRequestTheme">
<ImageView
android:id="@+id/screen_pinning_back_bg_light"
diff --git a/packages/SystemUI/res/layout/screen_pinning_request_buttons_sea.xml b/packages/SystemUI/res/layout/screen_pinning_request_buttons_sea.xml
index bac02aa..f9308cd 100644
--- a/packages/SystemUI/res/layout/screen_pinning_request_buttons_sea.xml
+++ b/packages/SystemUI/res/layout/screen_pinning_request_buttons_sea.xml
@@ -39,7 +39,7 @@
android:layout_height="@dimen/screen_pinning_request_button_width"
android:layout_width="@dimen/screen_pinning_request_button_height"
android:layout_weight="0"
- android:theme="@*android:style/ThemeOverlay.DeviceDefault.Accent">
+ android:theme="@style/ScreenPinningRequestTheme">
<ImageView
android:id="@+id/screen_pinning_back_bg_light"
@@ -82,7 +82,7 @@
android:layout_height="@dimen/screen_pinning_request_button_width"
android:layout_width="@dimen/screen_pinning_request_button_height"
android:layout_weight="0"
- android:theme="@*android:style/ThemeOverlay.DeviceDefault.Accent" >
+ android:theme="@style/ScreenPinningRequestTheme" >
<ImageView
android:id="@+id/screen_pinning_home_bg_light"
@@ -125,7 +125,7 @@
android:layout_height="@dimen/screen_pinning_request_button_width"
android:layout_width="@dimen/screen_pinning_request_button_height"
android:layout_weight="0"
- android:theme="@*android:style/ThemeOverlay.DeviceDefault.Accent">
+ android:theme="@style/ScreenPinningRequestTheme">
<ImageView
android:id="@+id/screen_pinning_recents_bg_light"
diff --git a/packages/SystemUI/res/layout/status_bar_no_notifications.xml b/packages/SystemUI/res/layout/status_bar_no_notifications.xml
index 1e00e52..28b5a40 100644
--- a/packages/SystemUI/res/layout/status_bar_no_notifications.xml
+++ b/packages/SystemUI/res/layout/status_bar_no_notifications.xml
@@ -26,9 +26,9 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="64dp"
- android:paddingTop="28dp"
+ android:paddingTop="12dp"
+ android:textAppearance="?android:attr/textAppearanceButton"
android:gravity="top|center_horizontal"
android:textColor="?attr/wallpaperTextColor"
- android:textSize="16sp"
android:text="@string/empty_shade_text"/>
</com.android.systemui.statusbar.EmptyShadeView>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 09cf5c0..fb9b5df 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Versteek <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Dit sal verskyn die volgende keer wanneer jy dit in instellings aanskakel."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Versteek"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Jy gebruik tans jou werkprofiel"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Bel"</string>
<string name="stream_system" msgid="7493299064422163147">"Stelsel"</string>
<string name="stream_ring" msgid="8213049469184048338">"Lui"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index dfcd419..305082f 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ይደበቅ?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"በቅንብሮች ውስጥ በሚቀጥለው ጊዜ እንዲበራ በሚያደርጉበት ጊዜ ዳግመኛ ብቅ ይላል።"</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"ደብቅ"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"የስራ መገለጫዎን እየተጠቀሙ ነው"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"ጥሪ"</string>
<string name="stream_system" msgid="7493299064422163147">"ሥርዓት"</string>
<string name="stream_ring" msgid="8213049469184048338">"ጥሪ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 4160b3b..8f197e8 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -534,7 +534,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"هل تريد إخفاء <xliff:g id="TILE_LABEL">%1$s</xliff:g>؟"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"سيظهر مرة أخرى عند تمكينه في الإعدادات المرة التالية."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"إخفاء"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"أنت تستخدم ملفك الشخصي للعمل"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"الاتصال"</string>
<string name="stream_system" msgid="7493299064422163147">"النظام"</string>
<string name="stream_ring" msgid="8213049469184048338">"الرنين"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index a310683..c20b5bc 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -95,8 +95,7 @@
<string name="accessibility_unlock_button" msgid="128158454631118828">"আনলক কৰক"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="4808860050517462885">"ফিংগাৰপ্ৰিণ্টৰ বাবে ৰৈ থকা হৈছে"</string>
<string name="accessibility_unlock_without_fingerprint" msgid="7541705575183694446">"ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ নকৰাকৈ আনলক কৰক"</string>
- <!-- no translation found for accessibility_scanning_face (769545173211758586) -->
- <skip />
+ <string name="accessibility_scanning_face" msgid="769545173211758586">"চেহেৰা স্কেন কৰি থকা হৈছে"</string>
<string name="accessibility_send_smart_reply" msgid="7766727839703044493">"পঠিয়াওক"</string>
<string name="unlock_label" msgid="8779712358041029439">"আনলক কৰক"</string>
<string name="phone_label" msgid="2320074140205331708">"ফ\'ন খোলক"</string>
@@ -523,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> লুকুৱাবনে?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"আপুনি ইয়াক পৰৱৰ্তী সময়ত ছেটিংসমূহত অন কৰিলে ই পুনৰ প্ৰকট হ\'ব।"</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"লুকুৱাওক"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"আপুনি আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইল ব্যৱহাৰ কৰি আছে"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"কল"</string>
<string name="stream_system" msgid="7493299064422163147">"ছিষ্টেম"</string>
<string name="stream_ring" msgid="8213049469184048338">"ৰিং"</string>
@@ -854,6 +852,5 @@
<string name="auto_saver_enabled_text" msgid="874711029884777579">"বেটাৰি চ্চাৰ্জৰ স্তৰ <xliff:g id="PERCENTAGE">%d</xliff:g>%%তকৈ কম হোৱাৰ লগে লগে বেটাৰি সঞ্চয়কাৰী স্বয়ংক্ৰিয়ভাৱে অন হ’ব।"</string>
<string name="open_saver_setting_action" msgid="8314624730997322529">"ছেটিংবোৰ"</string>
<string name="auto_saver_okay_action" msgid="2701221740227683650">"বুজি পালোঁ"</string>
- <!-- no translation found for heap_dump_tile_name (9141031328971226374) -->
- <skip />
+ <string name="heap_dump_tile_name" msgid="9141031328971226374">"SysUI হীপ ডাম্প কৰক"</string>
</resources>
diff --git a/packages/SystemUI/res/values-as/strings_car.xml b/packages/SystemUI/res/values-as/strings_car.xml
index e8cb6e3..1c4d7944 100644
--- a/packages/SystemUI/res/values-as/strings_car.xml
+++ b/packages/SystemUI/res/values-as/strings_car.xml
@@ -22,8 +22,6 @@
<string name="car_guest" msgid="3738772168718508650">"অতিথি"</string>
<string name="car_add_user" msgid="5245196248349230898">"ব্যৱহাৰকাৰী যোগ কৰক"</string>
<string name="car_new_user" msgid="8142927244990323906">"নতুন ব্যৱহাৰকাৰী"</string>
- <!-- no translation found for user_add_user_message_setup (1791011504259527329) -->
- <skip />
- <!-- no translation found for user_add_user_message_update (3383320289232716179) -->
- <skip />
+ <string name="user_add_user_message_setup" msgid="1791011504259527329">"আপুনি কোনো নতুন ব্য়ৱহাৰকাৰীক যোগ কৰিলে তেখেতে নিজৰ বাবে খালী ঠাই ছেট আপ কৰিব লাগে।"</string>
+ <string name="user_add_user_message_update" msgid="3383320289232716179">"সকলো ব্য়ৱহাৰকাৰীয়ে অইন ব্য়ৱহাৰকাৰীৰ বাবে এপসমূহ আপডেট কৰিব পাৰে।"</string>
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index ea511c1..239dc20 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> gizlədilsin?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Ayarlarda onu aktivləşdirəcəyiniz vaxta qədər o, yenidən görünəcək."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Gizlədin"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"İş profilinizi istifadə edirsiniz"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Zəng"</string>
<string name="stream_system" msgid="7493299064422163147">"Sistem"</string>
<string name="stream_ring" msgid="8213049469184048338">"Zəng Edin"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 400302f..47eb266 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -525,7 +525,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Želite li da sakrijete <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Ovo će se ponovo pojaviti kada ga sledeći put budete uključili u podešavanjima."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Sakrij"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Koristite profil za Work"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Poziv"</string>
<string name="stream_system" msgid="7493299064422163147">"Sistem"</string>
<string name="stream_ring" msgid="8213049469184048338">"Zvono"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index ecf32b0..2db91e8 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -530,7 +530,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Схаваць <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Гэта паведамленне з\'явіцца зноў у наступны раз, калі вы ўключыце яго ў наладах."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Схаваць"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Вы выкарыстоўваеце свой працоўны профіль"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Выклік"</string>
<string name="stream_system" msgid="7493299064422163147">"Сістэма"</string>
<string name="stream_ring" msgid="8213049469184048338">"Званок"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 0833a7a7..850977d 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Да се скрие ли „<xliff:g id="TILE_LABEL">%1$s</xliff:g>“?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Бързите настройки ще се покажат отново следващия път, когато ги включите от „Настройки“."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Скриване"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Използвате служебния си потребителски профил"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Обаждане"</string>
<string name="stream_system" msgid="7493299064422163147">"Система"</string>
<string name="stream_ring" msgid="8213049469184048338">"Позвъняване"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 47ad590..eacf30c 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -472,8 +472,8 @@
<string name="monitoring_description_managed_profile_ca_certificate" msgid="4683248196789897964">"আপনার প্রতিষ্ঠান আপনার অফিস প্রোফাইলে একটি সার্টিফিকেট কর্তৃপক্ষ ইনস্টল করেছে। আপনার নিরাপদ নেটওয়ার্ক ট্রাফিকে নজর রাখা হতে পারে বা তাতে পরিবর্তন করা হতে পারে।"</string>
<string name="monitoring_description_ca_certificate" msgid="7886985418413598352">"এই ডিভাইসে একটি সার্টিফিকেট কর্তৃপক্ষ ইনস্টল করা আছে। আপনার নিরাপদ নেটওয়ার্ক ট্রাফিকে নজর রাখা হতে পারে বা তাতে পরিবর্তন করা হতে পারে।"</string>
<string name="monitoring_description_management_network_logging" msgid="7184005419733060736">"আপনার প্রশাসক নেটওয়ার্ক লগিং চালু করেছেন, যা আপনার ডিভাইসের ট্রাফিকের উপরে নজর রাখে।"</string>
- <string name="monitoring_description_named_vpn" msgid="7403457334088909254">"আপনি <xliff:g id="VPN_APP">%1$s</xliff:g> এ সংযুক্ত রয়েছেন, যা আপনার ইমেল, অ্যাপ, এবং ওয়েবসাইট সহ আপনার নেটওয়ার্ক কার্যকলাপের উপর নজর রাখতে পারে।"</string>
- <string name="monitoring_description_two_named_vpns" msgid="4198511413729213802">"আপনি <xliff:g id="VPN_APP_0">%1$s</xliff:g> এবং <xliff:g id="VPN_APP_1">%2$s</xliff:g> এর সাথে সংযুক্ত রয়েছেন, যেগুলি আপনার ইমেল, অ্যাপ, এবং ওয়েবসাইট সহ আপনার নেটওয়ার্ক কার্যকলাপের উপর নজর রাখতে পারে।"</string>
+ <string name="monitoring_description_named_vpn" msgid="7403457334088909254">"আপনি <xliff:g id="VPN_APP">%1$s</xliff:g> এ সংযুক্ত রয়েছেন, যা আপনার ইমেল, অ্যাপ, এবং ওয়েবসাইট সহ আপনার নেটওয়ার্ক অ্যাক্টিভিটির উপর নজর রাখতে পারে।"</string>
+ <string name="monitoring_description_two_named_vpns" msgid="4198511413729213802">"আপনি <xliff:g id="VPN_APP_0">%1$s</xliff:g> এবং <xliff:g id="VPN_APP_1">%2$s</xliff:g> এর সাথে সংযুক্ত রয়েছেন, যেগুলি আপনার ইমেল, অ্যাপ, এবং ওয়েবসাইট সহ আপনার নেটওয়ার্ক অ্যাক্টিভিটির উপর নজর রাখতে পারে।"</string>
<string name="monitoring_description_managed_profile_named_vpn" msgid="1427905889862420559">"আপনার কর্মস্থলের প্রোফাইল <xliff:g id="VPN_APP">%1$s</xliff:g> এর সাথে সংযুক্ত রয়েছে, যেটি ইমেল, অ্যাপ, এবং ওয়েবসাইট সহ আপনার নেটওয়ার্ক কার্যকলাপে নজর রাখতে পারে।"</string>
<string name="monitoring_description_personal_profile_named_vpn" msgid="3133980926929069283">"আপনার ব্যক্তিগত প্রোফাইল <xliff:g id="VPN_APP">%1$s</xliff:g> এর সাথে সংযুক্ত রয়েছে, যেটি ইমেল, অ্যাপ, এবং ওয়েবসাইট সহ আপনার নেটওয়ার্ক কার্যকলাপে নজর রাখতে পারে৷"</string>
<string name="monitoring_description_do_header_generic" msgid="96588491028288691">"আপনার ডিভাইসটি <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> এর দ্বারা পরিচালিত৷"</string>
@@ -481,20 +481,20 @@
<string name="monitoring_description_do_body" msgid="3639594537660975895">"আপনার প্রশাসক আপনার ডিভাইসের লোকেশন তথ্য সহ এই ডিভাইসের সেটিংস, কর্পোরেট অ্যাক্সেস, অ্যাপ্স, ডেটা নিরীক্ষণ ও পরিচালনা করতে পারেন।"</string>
<string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"আরও জানুন"</string>
- <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"আপনি <xliff:g id="VPN_APP">%1$s</xliff:g> এ সংযুক্ত হয়েছেন, যা ইমেল, অ্যাপ এবং ওয়েবসাইটগুলি সহ আপনার নেটওয়ার্ক কার্যকলাপ নিরীক্ষণ করবে৷"</string>
+ <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"আপনি <xliff:g id="VPN_APP">%1$s</xliff:g> এ সংযুক্ত হয়েছেন, যা ইমেল, অ্যাপ এবং ওয়েবসাইটগুলি সহ আপনার নেটওয়ার্ক অ্যাক্টিভিটি নিরীক্ষণ করবে৷"</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<string name="monitoring_description_vpn_settings" msgid="6434859242636063861">"VPN সেটিংস খুলুন"</string>
<string name="monitoring_description_ca_cert_settings_separator" msgid="4987350385906393626">" "</string>
<string name="monitoring_description_ca_cert_settings" msgid="5489969458872997092">"বিশ্বস্ত শংসাপত্রগুলি খুলুন"</string>
<string name="monitoring_description_network_logging" msgid="7223505523384076027">"আপনার প্রশাসক নেটওয়ার্ক লগিং চালু করেছেন, যা আপনার ডিভাইসের ট্রাফিক নিরীক্ষণ করে।\n\nআরও তথ্যের জন্য আপনার প্রশাসকের সাথে যোগাযোগ করুন।"</string>
- <string name="monitoring_description_vpn" msgid="4445150119515393526">"আপনি VPN সংযোগ সেট আপ করার জন্য একটি অ্যাপ্লিকেশানকে অনুমতি দিন৷\n\nএই অ্যাপ্লিকেশানটি ইমেল, অ্যাপ্লিকেশান ও ওয়েবসাইটগুলি সহ আপনার ডিভাইস এবং নেটওয়ার্কের কার্যকলাপ নিরীক্ষণ করতে পারে।"</string>
- <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"আপনার কর্মস্থলের প্রোফাইলটি <xliff:g id="ORGANIZATION">%1$s</xliff:g> দ্বারা পরিচালিত হয়।\n\nআপনার প্রশাসক আপনার ইমেল, অ্যাপ্স ও ওয়েবসাইট সহ কর্মস্থলের নেটওয়ার্ক কার্যকলাপ নিরীক্ষণ করতে পারেন।\n\nআরও তথ্যের জন্য আপনার প্রশাসকের সঙ্গে যোগাযোগ করুন।\n\nএছাড়া আপনি একটি VPN এর সাথেও সংযুক্ত যা আপনার নেটওয়ার্ক কার্যকলাপ নিরীক্ষণ করতে পারে।"</string>
+ <string name="monitoring_description_vpn" msgid="4445150119515393526">"আপনি VPN সংযোগ সেট আপ করার জন্য একটি অ্যাপ্লিকেশানকে অনুমতি দিন৷\n\nএই অ্যাপ্লিকেশানটি ইমেল, অ্যাপ্লিকেশান ও ওয়েবসাইটগুলি সহ আপনার ডিভাইস এবং নেটওয়ার্কের অ্যাক্টিভিটি নিরীক্ষণ করতে পারে।"</string>
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"আপনার কর্মস্থলের প্রোফাইলটি <xliff:g id="ORGANIZATION">%1$s</xliff:g> দ্বারা পরিচালিত হয়।\n\nআপনার প্রশাসক আপনার ইমেল, অ্যাপ্স ও ওয়েবসাইট সহ কর্মস্থলের নেটওয়ার্ক অ্যাক্টিভিটি নিরীক্ষণ করতে পারেন।\n\nআরও তথ্যের জন্য আপনার প্রশাসকের সঙ্গে যোগাযোগ করুন।\n\nএছাড়া আপনি একটি VPN এর সাথেও সংযুক্ত যা আপনার নেটওয়ার্ক অ্যাক্টিভিটি নিরীক্ষণ করতে পারে।"</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="1828472472674709532">"আপনি <xliff:g id="APPLICATION">%1$s</xliff:g> এর সাথে সংযুক্ত রয়েছেন, যেটি ইমেল, অ্যাপ, এবং ওয়েবসাইট সহ আপনার নেটওয়ার্ক কার্যকলাপে নজর রাখতে পারে৷"</string>
- <string name="monitoring_description_app_personal" msgid="484599052118316268">"আপনি <xliff:g id="APPLICATION">%1$s</xliff:g> -এ সংযুক্ত হয়েছেন, যা ইমেল, অ্যাপ্লিকেশান এবং ওয়েবসাইটগুলি সমেত আপনার ব্যক্তিগত নেটওয়ার্ক কার্যকলাপ নিরীক্ষণ করতে পারে৷"</string>
- <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"আপনি <xliff:g id="APPLICATION">%1$s</xliff:g> এর সাথে সংযুক্ত হয়েছেন, যা ইমেল, অ্যাপ এবং ওয়েবসাইটগুলি সহ আপনার ব্যক্তিগত নেটওয়ার্কের কার্যকলাপ নিরীক্ষণ করবে৷"</string>
- <string name="monitoring_description_app_work" msgid="4612997849787922906">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> আপনার কর্মস্থলের প্রোফাইল পরিচালনা করে। প্রোফাইলটি <xliff:g id="APPLICATION">%2$s</xliff:g> এর সাথে সংযুক্ত, যেটি ইমেল, অ্যাপ, ও ওয়েবসাইট সহ আপনার কর্মস্থলের নেটওয়ার্ক কার্যকলাপের উপরে নজর রাখতে পারে।\n\nআরও তথ্যের জন্য প্রশাসকের সাথে যোগাযোগ করুন।"</string>
- <string name="monitoring_description_app_personal_work" msgid="5664165460056859391">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> আপনার কর্মস্থলের প্রোফাইল পরিচালনা করে। প্রোফাইলটি <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> এর সাথে সংযুক্ত, যেটি ইমেল অ্যাপ, ও ওয়েবসাইট সহ আপনার কর্মস্থলের নেটওয়ার্ক কার্যকলাপের উপরে নজর রাখতে পারে।\n\n এ ছাড়াও আপনি <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> এর সাথে সংযুক্ত, যেটি আপনার ব্যক্তিগত নেটওয়ার্কে নজর রাখে।"</string>
+ <string name="monitoring_description_app_personal" msgid="484599052118316268">"আপনি <xliff:g id="APPLICATION">%1$s</xliff:g> -এ সংযুক্ত হয়েছেন, যা ইমেল, অ্যাপ্লিকেশান এবং ওয়েবসাইটগুলি সমেত আপনার ব্যক্তিগত নেটওয়ার্ক অ্যাক্টিভিটি নিরীক্ষণ করতে পারে৷"</string>
+ <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"আপনি <xliff:g id="APPLICATION">%1$s</xliff:g> এর সাথে সংযুক্ত হয়েছেন, যা ইমেল, অ্যাপ এবং ওয়েবসাইটগুলি সহ আপনার ব্যক্তিগত নেটওয়ার্কের অ্যাক্টিভিটি নিরীক্ষণ করবে৷"</string>
+ <string name="monitoring_description_app_work" msgid="4612997849787922906">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> আপনার কর্মস্থলের প্রোফাইল পরিচালনা করে। প্রোফাইলটি <xliff:g id="APPLICATION">%2$s</xliff:g> এর সাথে সংযুক্ত, যেটি ইমেল, অ্যাপ, ও ওয়েবসাইট সহ আপনার কর্মস্থলের নেটওয়ার্ক অ্যাক্টিভিটির উপরে নজর রাখতে পারে।\n\nআরও তথ্যের জন্য প্রশাসকের সাথে যোগাযোগ করুন।"</string>
+ <string name="monitoring_description_app_personal_work" msgid="5664165460056859391">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> আপনার কর্মস্থলের প্রোফাইল পরিচালনা করে। প্রোফাইলটি <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> এর সাথে সংযুক্ত, যেটি ইমেল অ্যাপ, ও ওয়েবসাইট সহ আপনার কর্মস্থলের নেটওয়ার্ক অ্যাক্টিভিটির উপরে নজর রাখতে পারে।\n\n এ ছাড়াও আপনি <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> এর সাথে সংযুক্ত, যেটি আপনার ব্যক্তিগত নেটওয়ার্কে নজর রাখে।"</string>
<string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"<xliff:g id="USER_NAME">%1$s</xliff:g> এর জন্য আনলক করা হয়েছে"</string>
<string name="keyguard_indication_trust_managed" msgid="8319646760022357585">"<xliff:g id="TRUST_AGENT">%1$s</xliff:g> চালু আছে"</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"আপনি নিজে আনলক না করা পর্যন্ত ডিভাইসটি লক হয়ে থাকবে"</string>
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> লুকাবেন?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"আপনি পরের বার সেটিংস-এ এটি চালু করলে এটি উপস্থিত হবে"</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"লুকান"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"আপনি আপনার কাজের প্রোফাইল ব্যবহার করছেন"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"কল"</string>
<string name="stream_system" msgid="7493299064422163147">"সিস্টেম"</string>
<string name="stream_ring" msgid="8213049469184048338">"রিং"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 65d9071..0303ffd 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -525,7 +525,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Želite li sakriti <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Pojavit će se sljedeći put kada opciju uključite u postavkama."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Sakrij"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Koristite svoj profil za posao"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Poziv"</string>
<string name="stream_system" msgid="7493299064422163147">"Sistem"</string>
<string name="stream_ring" msgid="8213049469184048338">"Zvono"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index ad7e546..171fd1a 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vols amagar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Tornarà a mostrar-se la propera vegada que l\'activis a la configuració."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Amaga"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Estàs utilitzant el perfil professional"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Trucada"</string>
<string name="stream_system" msgid="7493299064422163147">"Sistema"</string>
<string name="stream_ring" msgid="8213049469184048338">"To de trucada"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index bc84f59..d72b1d1 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -530,7 +530,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Skrýt <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Tato položka se znovu zobrazí, až ji v nastavení znovu zapnete."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Skrýt"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Používáte pracovní profil"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Hovor"</string>
<string name="stream_system" msgid="7493299064422163147">"Systém"</string>
<string name="stream_ring" msgid="8213049469184048338">"Vyzvánění"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index c7e856a..fff619b 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vil du skjule <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Den vises igen, næste gang du aktiverer den i indstillingerne."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Skjul"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Du bruger din arbejdsprofil"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Ring op"</string>
<string name="stream_system" msgid="7493299064422163147">"System"</string>
<string name="stream_ring" msgid="8213049469184048338">"Ring"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 42d98e4..d3d9458 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -526,7 +526,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ausblenden?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Sie wird wieder eingeblendet, wenn du sie in den Einstellungen erneut aktivierst."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ausblenden"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Du verwendest dein Arbeitsprofil."</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Anruf"</string>
<string name="stream_system" msgid="7493299064422163147">"System"</string>
<string name="stream_ring" msgid="8213049469184048338">"Klingelton"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 67afd93..45e1b1b 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Απόκρυψη <xliff:g id="TILE_LABEL">%1$s</xliff:g>;"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Θα εμφανιστεί ξανά την επόμενη φορά που θα το ενεργοποιήσετε στις ρυθμίσεις."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Απόκρυψη"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Χρησιμοποιείτε το προφίλ εργασίας σας"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Κλήση"</string>
<string name="stream_system" msgid="7493299064422163147">"Σύστημα"</string>
<string name="stream_ring" msgid="8213049469184048338">"Κλήση"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 01cd5b0..561601d 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Hide <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"It will reappear the next time you turn it on in settings."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Hide"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"You\'re using your work profile"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Call"</string>
<string name="stream_system" msgid="7493299064422163147">"System"</string>
<string name="stream_ring" msgid="8213049469184048338">"Ring"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index d8c89d3..efa8ad2 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Hide <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"It will reappear the next time you turn it on in settings."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Hide"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"You\'re using your work profile"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Call"</string>
<string name="stream_system" msgid="7493299064422163147">"System"</string>
<string name="stream_ring" msgid="8213049469184048338">"Ring"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 01cd5b0..561601d 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Hide <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"It will reappear the next time you turn it on in settings."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Hide"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"You\'re using your work profile"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Call"</string>
<string name="stream_system" msgid="7493299064422163147">"System"</string>
<string name="stream_ring" msgid="8213049469184048338">"Ring"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 01cd5b0..561601d 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Hide <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"It will reappear the next time you turn it on in settings."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Hide"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"You\'re using your work profile"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Call"</string>
<string name="stream_system" msgid="7493299064422163147">"System"</string>
<string name="stream_ring" msgid="8213049469184048338">"Ring"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 2e6999a..881ee90 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Hide <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"It will reappear the next time you turn it on in settings."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Hide"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"You\'re using your work profile"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Call"</string>
<string name="stream_system" msgid="7493299064422163147">"System"</string>
<string name="stream_ring" msgid="8213049469184048338">"Ring"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 1f6dd16..6681dbb 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -524,7 +524,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"¿Ocultar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Volverá a aparecer la próxima vez que se active en la configuración."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ocultar"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Estás usando tu perfil de trabajo"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Llamada"</string>
<string name="stream_system" msgid="7493299064422163147">"Sistema"</string>
<string name="stream_ring" msgid="8213049469184048338">"Hacer sonar"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 7ca5991..27daa5c 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -524,7 +524,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"¿Ocultar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Volverá a aparecer la próxima vez que actives esta opción en Ajustes."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ocultar"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Estás usando tu perfil de trabajo"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Llamada"</string>
<string name="stream_system" msgid="7493299064422163147">"Sistema"</string>
<string name="stream_ring" msgid="8213049469184048338">"Tono"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 3ef21be..c309294 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -524,7 +524,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Kas peita <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"See kuvatakse uuesti järgmisel korral, kui selle seadetes sisse lülitate."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Peida"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Kasutate oma tööprofiili"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Kõne"</string>
<string name="stream_system" msgid="7493299064422163147">"Süsteem"</string>
<string name="stream_ring" msgid="8213049469184048338">"Helin"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 432bfc4..d2dbc79 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -524,7 +524,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ezkutatu nahi duzu?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Ezarpenetan aktibatzen duzun hurrengoan agertuko da berriro."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ezkutatu"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Work profila erabiltzen ari zara"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Deia"</string>
<string name="stream_system" msgid="7493299064422163147">"Sistema"</string>
<string name="stream_ring" msgid="8213049469184048338">"Jo tonua"</string>
@@ -564,8 +563,8 @@
<string name="status_bar" msgid="4877645476959324760">"Egoera-barra"</string>
<string name="overview" msgid="4018602013895926956">"Ikuspegi orokorra"</string>
<string name="demo_mode" msgid="2532177350215638026">"Sistemaren erabiltzaile-interfazearen demo modua"</string>
- <string name="enable_demo_mode" msgid="4844205668718636518">"Gaitu proba modua"</string>
- <string name="show_demo_mode" msgid="2018336697782464029">"Erakutsi proba modua"</string>
+ <string name="enable_demo_mode" msgid="4844205668718636518">"Gaitu demo modua"</string>
+ <string name="show_demo_mode" msgid="2018336697782464029">"Erakutsi demo modua"</string>
<string name="status_bar_ethernet" msgid="5044290963549500128">"Ethernet"</string>
<string name="status_bar_alarm" msgid="8536256753575881818">"Alarma"</string>
<string name="status_bar_work" msgid="6022553324802866373">"Work profila"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 79dc007..34ab46f 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> مخفی شود؟"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"دفعه بعد که آن را روشن کنید، در تنظیمات نشان داده میشود."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"پنهان کردن"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"درحال استفاده از نمایه کاریتان هستید"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"تماس"</string>
<string name="stream_system" msgid="7493299064422163147">"سیستم"</string>
<string name="stream_ring" msgid="8213049469184048338">"زنگ زدن"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index fbccf86..baa7822 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Piilotetaanko <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Se tulee takaisin näkyviin, kun seuraavan kerran otat sen käyttöön asetuksissa."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Piilota"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Käytät työprofiilia."</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Puhelu"</string>
<string name="stream_system" msgid="7493299064422163147">"Järjestelmä"</string>
<string name="stream_ring" msgid="8213049469184048338">"Soittoääni"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index fb1e675..bb4cdfb 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -524,7 +524,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Masquer <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Cet élément réapparaîtra la prochaine fois que vous l\'activerez dans les paramètres."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Masquer"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Vous utilisez votre profil professionnel."</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Appeler"</string>
<string name="stream_system" msgid="7493299064422163147">"Système"</string>
<string name="stream_ring" msgid="8213049469184048338">"Sonnerie"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index d13e9ff..e38e83c 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -524,7 +524,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Masquer <xliff:g id="TILE_LABEL">%1$s</xliff:g> ?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Cet élément réapparaîtra la prochaine fois que vous l\'activerez dans les paramètres."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Masquer"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Vous utilisez votre profil professionnel."</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Appel"</string>
<string name="stream_system" msgid="7493299064422163147">"Système"</string>
<string name="stream_ring" msgid="8213049469184048338">"Sonnerie"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 6b5e0c3..0e8b093 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -524,7 +524,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Queres ocultar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Volverá aparecer a próxima vez que se active na configuración."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ocultar"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Estás usando o perfil de traballo"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Chamada"</string>
<string name="stream_system" msgid="7493299064422163147">"Sistema"</string>
<string name="stream_ring" msgid="8213049469184048338">"Ton"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index a982341..a730f01 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ને છુપાવીએ?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"તે સેટિંગ્સમાં તમે તેને ચાલુ કરશો ત્યારે આગલી વખતે ફરીથી દેખાશે."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"છુપાવો"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"તમે તમારી કાર્ય પ્રોફાઇલનો ઉપયોગ કરી રહ્યાં છો"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"કૉલ કરો"</string>
<string name="stream_system" msgid="7493299064422163147">"સિસ્ટમ"</string>
<string name="stream_ring" msgid="8213049469184048338">"રિંગ વગાડો"</string>
diff --git a/packages/SystemUI/res/values-hi-ldrtl/strings.xml b/packages/SystemUI/res/values-hi-ldrtl/strings.xml
index 6200b8d..df86c57 100644
--- a/packages/SystemUI/res/values-hi-ldrtl/strings.xml
+++ b/packages/SystemUI/res/values-hi-ldrtl/strings.xml
@@ -19,5 +19,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recents_quick_scrub_onboarding" msgid="3449337212132057178">"ऐप्लिकेशन को तेज़ी से स्विच करने के लिए उसे बाईं ओर खींचें और छोड़ें"</string>
+ <string name="recents_quick_scrub_onboarding" msgid="3449337212132057178">"ऐप्लिकेशन को तेज़ी से बदलने के लिए उसे बाईं ओर खींचें और छोड़ें"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 3eb7e97..7049044 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -409,7 +409,7 @@
<string name="user_add_user" msgid="5110251524486079492">"उपयोगकर्ता जोड़ें"</string>
<string name="user_new_user_name" msgid="426540612051178753">"नया उपयोगकर्ता"</string>
<string name="guest_nickname" msgid="8059989128963789678">"मेहमान"</string>
- <string name="guest_new_guest" msgid="600537543078847803">"अतिथि जोड़ें"</string>
+ <string name="guest_new_guest" msgid="600537543078847803">"मेहमान जोड़ें"</string>
<string name="guest_exit_guest" msgid="7187359342030096885">"अतिथि को निकालें"</string>
<string name="guest_exit_guest_dialog_title" msgid="8480693520521766688">"अतिथि को निकालें?"</string>
<string name="guest_exit_guest_dialog_message" msgid="4155503224769676625">"इस सत्र के सभी ऐप्स और डेटा को हटा दिया जाएगा."</string>
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> को छिपाएं?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"जब आप उसे अगली बार सेटिंग में चालू करेंगे तो वह फिर से दिखाई देगी."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"छिपाएं"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"आप अपनी कार्य प्रोफ़ाइल का उपयोग कर रहे हैं"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"कॉल करें"</string>
<string name="stream_system" msgid="7493299064422163147">"सिस्टम"</string>
<string name="stream_ring" msgid="8213049469184048338">"घंटी बजाएं"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index d784ac4..a77b7ff 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -525,7 +525,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Želite li sakriti pločicu <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Ponovo će se pojaviti kada je sljedeći put uključite u postavkama."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Sakrij"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Upotrebljavate radni profil"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Nazovi"</string>
<string name="stream_system" msgid="7493299064422163147">"Sustav"</string>
<string name="stream_ring" msgid="8213049469184048338">"Zvoni"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index c9d83e6..d6e2cb6 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Elrejti ezt: <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Újból megjelenik majd, amikor ismét engedélyezi a beállítások között."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Elrejtés"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"A munkaprofilt használja"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Telefonhívás"</string>
<string name="stream_system" msgid="7493299064422163147">"Rendszer"</string>
<string name="stream_ring" msgid="8213049469184048338">"Csörgetés"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 96952f8..2e8c9be 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -69,14 +69,14 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Ընթացիկ հաշվի օգտատերը չի կարող միացնել USB վրիպազերծումը: Այս գործառույթը միացնելու համար մուտք գործեք հիմնական օգտատիրոջ հաշվով:"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Խոշորացնել` էկրանը լցնելու համար"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Ձգել` էկրանը լցնելու համար"</string>
- <string name="global_action_screenshot" msgid="8329831278085426283">"Էկրանի պատկեր"</string>
- <string name="screenshot_saving_ticker" msgid="7403652894056693515">"Էկրանի պատկերը պահվում է…"</string>
- <string name="screenshot_saving_title" msgid="8242282144535555697">"Էկրանի պատկերը պահվում է..."</string>
- <string name="screenshot_saved_title" msgid="5637073968117370753">"Էկրանի պատկերը պահվեց"</string>
- <string name="screenshot_saved_text" msgid="7574667448002050363">"Հպեք՝ էկրանի պատկերը տեսնելու համար"</string>
- <string name="screenshot_failed_title" msgid="7612509838919089748">"Չհաջողվեց պահել էկրանի պատկերը"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Սքրինշոթ"</string>
+ <string name="screenshot_saving_ticker" msgid="7403652894056693515">"Սքրինշոթը պահվում է…"</string>
+ <string name="screenshot_saving_title" msgid="8242282144535555697">"Սքրինշոթը պահվում է..."</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Սքրինշոթը պահվեց"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Հպեք՝ սքրինշոթը տեսնելու համար"</string>
+ <string name="screenshot_failed_title" msgid="7612509838919089748">"Չհաջողվեց պահել սքրինշոթը"</string>
<string name="screenshot_failed_to_save_unknown_text" msgid="3637758096565605541">"Փորձեք նորից"</string>
- <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Չհաջողվեց պահել էկրանի պատկերը անբավարար հիշողության պատճառով"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Չհաջողվեց պահել սքրինշոթը անբավարար հիշողության պատճառով"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Հավելվածը կամ ձեր կազմակերպությունը չի թույլատրում էկրանի պատկերի ստացումը"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB ֆայլերի փոխանցման ընտրանքներ"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Միացնել որպես մեդիա նվագարկիչ (MTP)"</string>
@@ -292,8 +292,8 @@
<string name="accessibility_quick_settings_rotation" msgid="4231661040698488779">"Ավտոմատ պտտել էկրանը"</string>
<string name="accessibility_quick_settings_rotation_value" msgid="8187398200140760213">"<xliff:g id="ID_1">%s</xliff:g> ռեժիմ"</string>
<string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Պտտումը կողպված է"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Դիմանկար"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Լանդշաֆտ"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Ուղղաձիգ"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Հորիզոնական"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Մուտքագրման եղանակը"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Տեղորոշում"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Անջատել տեղադրությունը"</string>
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Թաքցնե՞լ <xliff:g id="TILE_LABEL">%1$s</xliff:g>-ը:"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Այն դարձյալ կհայտնվի, երբ նորից միացնեք կարգավորումներում:"</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Թաքցնել"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Դուք օգտագործում եք ձեր աշխատանքային պրոֆիլը"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Զանգ"</string>
<string name="stream_system" msgid="7493299064422163147">"Համակարգ"</string>
<string name="stream_ring" msgid="8213049469184048338">"Զանգ"</string>
@@ -815,7 +814,7 @@
<string name="tuner_app" msgid="3507057938640108777">"<xliff:g id="APP">%1$s</xliff:g> հավելված"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Ծանուցումներ"</string>
<string name="notification_channel_battery" msgid="5786118169182888462">"Մարտկոց"</string>
- <string name="notification_channel_screenshot" msgid="6314080179230000938">"Էկրանի պատկերներ"</string>
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"Սքրինշոթներ"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Ընդհանուր հաղորդագրություններ"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Տարածք"</string>
<string name="notification_channel_hints" msgid="7323870212489152689">"Հուշումներ"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 1a042fc..d75d121 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Sembunyikan <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Ini akan muncul kembali saat Anda mengaktifkannya dalam setelan."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Sembunyikan"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Anda menggunakan profil kerja"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Telepon"</string>
<string name="stream_system" msgid="7493299064422163147">"Sistem"</string>
<string name="stream_ring" msgid="8213049469184048338">"Dering"</string>
@@ -580,7 +579,7 @@
<string name="tuner_warning_title" msgid="7094689930793031682">"Tidak semua orang menganggapnya baik"</string>
<string name="tuner_warning" msgid="8730648121973575701">"Penyetel Antarmuka Pengguna Sistem memberikan cara tambahan untuk mengubah dan menyesuaikan antarmuka pengguna Android. Fitur eksperimental ini dapat berubah, rusak, atau menghilang dalam rilis di masa mendatang. Lanjutkan dengan hati-hati."</string>
<string name="tuner_persistent_warning" msgid="8597333795565621795">"Fitur eksperimental ini dapat berubah, rusak, atau menghilang dalam rilis di masa mendatang. Lanjutkan dengan hati-hati."</string>
- <string name="got_it" msgid="2239653834387972602">"Mengerti"</string>
+ <string name="got_it" msgid="2239653834387972602">"Oke"</string>
<string name="tuner_toast" msgid="603429811084428439">"Selamat! Penyetel Antarmuka Pengguna Sistem telah ditambahkan ke Setelan"</string>
<string name="remove_from_settings" msgid="8389591916603406378">"Hapus dari Setelan"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"Hapus Penyetel Antarmuka Pengguna Sistem dari Setelan dan berhenti menggunakan semua fiturnya?"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 61596f5..eaad622 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Fela <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Þetta birtist aftur næst þegar þú kveikir á því í stillingunum."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Fela"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Þú ert að nota vinnusniðið"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Símtal"</string>
<string name="stream_system" msgid="7493299064422163147">"Kerfi"</string>
<string name="stream_ring" msgid="8213049469184048338">"Hringing"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 65add2a..7bd52d4 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -524,7 +524,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Nascondere <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Verranno visualizzate di nuovo quando le riattiverai nelle impostazioni."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Nascondi"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Stai utilizzando il profilo di lavoro"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Chiamata"</string>
<string name="stream_system" msgid="7493299064422163147">"Sistema"</string>
<string name="stream_ring" msgid="8213049469184048338">"Suoneria"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 06b20a7..cac6d31 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -528,7 +528,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"להסתיר<xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"יופיע מחדש בפעם הבאה שתפעיל את האפשרות בהגדרות."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"הסתר"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"אתה משתמש בפרופיל העבודה שלך"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"שיחה"</string>
<string name="stream_system" msgid="7493299064422163147">"מערכת"</string>
<string name="stream_ring" msgid="8213049469184048338">"צלצול"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 4b3621a..10e9568 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -524,7 +524,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>を非表示にしますか?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"次回、設定でONにすると再表示されます。"</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"非表示"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"仕事用プロファイルを使用しています"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"発信"</string>
<string name="stream_system" msgid="7493299064422163147">"システム"</string>
<string name="stream_ring" msgid="8213049469184048338">"着信音"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 8a57d62..c28fab7 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"დაიმალოს <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"ის კვლავ გამოჩნდება, როდესაც პარამეტრებში ჩართავთ"</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"დამალვა"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"თქვენ სამსახურის პროფილს იყენებთ"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"დარეკვა"</string>
<string name="stream_system" msgid="7493299064422163147">"სისტემა"</string>
<string name="stream_ring" msgid="8213049469184048338">"დარეკვა"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index e63a9d3..f256d33 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> жасыру керек пе?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Ол сіз оны параметрлерде келесі қосқанда қайта пайда болады."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Жасыру"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Сіз жұмыс профиліңізді пайдаланып жатырсыз"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Қоңырау шалу"</string>
<string name="stream_system" msgid="7493299064422163147">"Жүйе"</string>
<string name="stream_ring" msgid="8213049469184048338">"Шылдырлау"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 922d9c2..2c9a554 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"លាក់ <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"វានឹងបង្ហាញពេលក្រោយ ពេលដែលអ្នកបើកក្នុងការកំណត់។"</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"លាក់"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"អ្នកកំពុងប្រើប្រវត្តិរូបការងាររបស់អ្នក"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"ហៅ"</string>
<string name="stream_system" msgid="7493299064422163147">"ប្រព័ន្ធ"</string>
<string name="stream_ring" msgid="8213049469184048338">"រោទ៍"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index ec4c7ce..8760d00 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ಮರೆಮಾಡುವುದೇ?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"ನೀವು ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ ಅದನ್ನು ಆನ್ ಮಾಡಿದಾಗ ಅದು ಮರುಕಾಣಿಸಿಕೊಳ್ಳುತ್ತದೆ."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"ಮರೆಮಾಡಿ"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ನೀವು ಬಳಸುತ್ತಿರುವಿರಿ"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"ಕರೆಮಾಡಿ"</string>
<string name="stream_system" msgid="7493299064422163147">"ಸಿಸ್ಟಂ"</string>
<string name="stream_ring" msgid="8213049469184048338">"ರಿಂಗ್"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 3db09d5..7983966 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -524,7 +524,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>을(를) 숨기시겠습니까?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"다음번에 설정에서 사용 설정하면 다시 표시됩니다."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"숨기기"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"직장 프로필을 사용하고 있습니다."</string>
<string name="stream_voice_call" msgid="4410002696470423714">"전화걸기"</string>
<string name="stream_system" msgid="7493299064422163147">"시스템"</string>
<string name="stream_ring" msgid="8213049469184048338">"벨소리"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 5f4b485..5ee60c9 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> жашырылсынбы?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Бул кийинки жолу жөндөөлөрдөн күйгүзүлгөндө кайра көрүнөт."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Жашыруу"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Жумуш профилиңизди колдонуп жатасыз"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Чалуу"</string>
<string name="stream_system" msgid="7493299064422163147">"Тутум"</string>
<string name="stream_ring" msgid="8213049469184048338">"Шыңгыратуу"</string>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index c59dbdc..bb0c6f6 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -24,8 +24,6 @@
<dimen name="brightness_mirror_height">40dp</dimen>
- <!-- Width for the spacer, used between QS tiles. -->
- <dimen name="qs_quick_tile_space_width">38dp</dimen>
<dimen name="qs_tile_margin_top">2dp</dimen>
<dimen name="qs_header_tooltip_height">24dp</dimen>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 877b512..7e2375e 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"ເຊື່ອງ <xliff:g id="TILE_LABEL">%1$s</xliff:g> ຫຼືບໍ່?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"ມັນຈະສະແດງຄືນໃໝ່ເມື່ອທ່ານເປີດນຳໃຊ້ມັນໃນການຕັ້ງຄ່າຄັ້ງຕໍ່ໄປ."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"ເຊື່ອງ"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"ທ່ານກຳລັງໃຊ້ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຂອງທ່ານ"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"ໂທ"</string>
<string name="stream_system" msgid="7493299064422163147">"ລະບົບ"</string>
<string name="stream_ring" msgid="8213049469184048338">"ເຕືອນດ້ວຍສຽງ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index eb92531..d784ba6 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -528,7 +528,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Slėpti „<xliff:g id="TILE_LABEL">%1$s</xliff:g>“?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Tai bus vėl parodyta, kai kitą kartą įjungsite tai nustatymuose."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Slėpti"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Naudojate darbo profilį"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Skambutis"</string>
<string name="stream_system" msgid="7493299064422163147">"Sistema"</string>
<string name="stream_ring" msgid="8213049469184048338">"Skambutis"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 28014e4..86e2e4c 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -525,7 +525,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vai paslēpt vienumu <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Tas tiks atkārtoti parādīts, kad nākamreiz ieslēgsiet to iestatījumos."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Paslēpt"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Jūs izmantojat darba profilu."</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Zvans"</string>
<string name="stream_system" msgid="7493299064422163147">"Sistēma"</string>
<string name="stream_ring" msgid="8213049469184048338">"Zvans"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 5d4dd4d..88ea162 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Сокриј <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Ќе се појави повторно следниот пат кога ќе го вклучите во поставки."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Сокриј"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Го користите работниот профил"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Повик"</string>
<string name="stream_system" msgid="7493299064422163147">"Систем"</string>
<string name="stream_ring" msgid="8213049469184048338">"Ѕвони"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 9e6c239..9c18a22 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> എന്നത് മറയ്ക്കണോ?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"അടുത്ത തവണ നിങ്ങൾ അത് ക്രമീകരണങ്ങളിൽ ഓണാക്കുമ്പോൾ അത് വീണ്ടും ദൃശ്യമാകും."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"മറയ്ക്കുക"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"നിങ്ങൾ ഉപയോഗിക്കുന്നത് ഔദ്യോഗിക പ്രൊഫൈലാണ്"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"കോള്"</string>
<string name="stream_system" msgid="7493299064422163147">"സിസ്റ്റം"</string>
<string name="stream_ring" msgid="8213049469184048338">"റിംഗുചെയ്യുക"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index ba56386..fb26e81 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -520,7 +520,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>-ийг нуух уу?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Тохируулгын хэсэгт үүнийг асаахад энэ дахин харагдана."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Нуух"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Та өөрийн ажлын профайлыг ашиглаж байна"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Залгах"</string>
<string name="stream_system" msgid="7493299064422163147">"Систем"</string>
<string name="stream_ring" msgid="8213049469184048338">"Хонх"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 99b13f6..958a877 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> लपवायचे?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"तुम्ही सेटिंग्जमध्ये ते पुढील वेळी चालू कराल तेव्हा ते पुन्हा दिसेल."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"लपवा"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"तुम्ही तुमचे कार्य प्रोफाईल वापरत आहात"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"कॉल करा"</string>
<string name="stream_system" msgid="7493299064422163147">"सिस्टम"</string>
<string name="stream_ring" msgid="8213049469184048338">"रिंग करा"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index a1e8267..18007c2 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Sembunyikan <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Mesej itu akan terpapar semula pada kali seterusnya anda menghidupkan apl dalam tetapan."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Sembunyikan"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Anda sedang menggunakan profil kerja"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Panggil"</string>
<string name="stream_system" msgid="7493299064422163147">"Sistem"</string>
<string name="stream_ring" msgid="8213049469184048338">"Dering"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 15df61c..f1d48b9 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ဝှက်မည်လား?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"နောက်တစ်ကြိမ်သင် ချိန်ညှိချက်များဖွင့်လျှင် ၎င်းပေါ်လာပါမည်။"</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"ဖျောက်ထားမည်"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"သင်သည် အလုပ်ပရိုဖိုင်းအား သုံးနေသည်"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"ဖုန်းခေါ်ရန်"</string>
<string name="stream_system" msgid="7493299064422163147">"စနစ်"</string>
<string name="stream_ring" msgid="8213049469184048338">"အသံမြည်စေသည်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 5da9570..d8d6e47 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vil du skjule <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Den vises igjen neste gang du slår den på i innstillingene."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Skjul"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Du bruker jobbprofilen din"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Anrop"</string>
<string name="stream_system" msgid="7493299064422163147">"System"</string>
<string name="stream_ring" msgid="8213049469184048338">"Ring"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 6f37055..5cd4325 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"लुकाउनुहुन्छ <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"यो तपाईं सेटिङ् मा यो बारी अर्को समय देखापर्नेछ।"</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"लुकाउनुहोस्"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"तपाईँले कार्य प्रोफाइल प्रयोग गर्दै हुनुहुन्छ"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"कल"</string>
<string name="stream_system" msgid="7493299064422163147">"प्रणाली"</string>
<string name="stream_ring" msgid="8213049469184048338">"घन्टी"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index def7b19b..ac5b3e1 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> verbergen?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Deze wordt opnieuw weergegeven zodra u de instelling weer inschakelt."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Verbergen"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Je gebruikt je werkprofiel"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Bellen"</string>
<string name="stream_system" msgid="7493299064422163147">"Systeem"</string>
<string name="stream_ring" msgid="8213049469184048338">"Bellen"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 7dbd5ad..8ac9f5f 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -95,8 +95,7 @@
<string name="accessibility_unlock_button" msgid="128158454631118828">"ଅନଲକ୍ କରନ୍ତୁ"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="4808860050517462885">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ପାଇଁ ଅପେକ୍ଷା କରିଛି"</string>
<string name="accessibility_unlock_without_fingerprint" msgid="7541705575183694446">"ଆଙ୍ଗୁଠିଚିହ୍ନ ବ୍ୟବହାର ନକରି ଅନଲକ୍ କରନ୍ତୁ"</string>
- <!-- no translation found for accessibility_scanning_face (769545173211758586) -->
- <skip />
+ <string name="accessibility_scanning_face" msgid="769545173211758586">"ଫେସ୍ ସ୍କାନିଙ୍ଗ କରାଯାଉଛି"</string>
<string name="accessibility_send_smart_reply" msgid="7766727839703044493">"ପଠାନ୍ତୁ"</string>
<string name="unlock_label" msgid="8779712358041029439">"ଅନଲକ୍"</string>
<string name="phone_label" msgid="2320074140205331708">"ଫୋନ୍ ଖୋଲନ୍ତୁ"</string>
@@ -151,16 +150,13 @@
<string name="data_connection_gprs" msgid="7652872568358508452">"GPRS"</string>
<string name="data_connection_hspa" msgid="1499615426569473562">"HSPA"</string>
<string name="data_connection_3g" msgid="503045449315378373">"3G"</string>
- <!-- no translation found for data_connection_3_5g (3164370985817123144) -->
- <skip />
- <!-- no translation found for data_connection_3_5g_plus (4464630787664529264) -->
- <skip />
+ <string name="data_connection_3_5g" msgid="3164370985817123144">"H"</string>
+ <string name="data_connection_3_5g_plus" msgid="4464630787664529264">"H+"</string>
<string name="data_connection_4g" msgid="9139963475267449144">"4G"</string>
<string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
<string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
<string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
- <!-- no translation found for data_connection_cdma (8176597308239086780) -->
- <skip />
+ <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
<string name="data_connection_roaming" msgid="6037232010953697354">"ରୋମିଙ୍ଗ"</string>
<string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
<string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"ୱାଇ-ଫାଇ"</string>
@@ -526,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ଲୁଚାନ୍ତୁ?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"ଆଗକୁ ଆପଣ ଯେତେବେଳେ ଏହି ସେଟିଙ୍ଗକୁ ଚାଲୁ କରିବେ, ଏହା ପୁଣି ଦେଖାଦେବ।"</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"ଲୁଚାନ୍ତୁ"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"ଆପଣ ନିଜ ୱର୍କ ପ୍ରୋଫାଇଲ୍ ବ୍ୟବହାର କରୁଛନ୍ତି"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"କଲ୍ କରନ୍ତୁ"</string>
<string name="stream_system" msgid="7493299064422163147">"ସିଷ୍ଟମ୍"</string>
<string name="stream_ring" msgid="8213049469184048338">"ରିଙ୍ଗ"</string>
@@ -857,6 +852,5 @@
<string name="auto_saver_enabled_text" msgid="874711029884777579">"ଚାର୍ଜ <xliff:g id="PERCENTAGE">%d</xliff:g>%%ରୁ କମ୍ ହେଲେ ବ୍ୟାଟେରୀ ସେଭର୍ ଆପେ ଅନ୍ ହୋଇଯିବ।"</string>
<string name="open_saver_setting_action" msgid="8314624730997322529">"ସେଟିଙ୍ଗ"</string>
<string name="auto_saver_okay_action" msgid="2701221740227683650">"ବୁଝିଲି"</string>
- <!-- no translation found for heap_dump_tile_name (9141031328971226374) -->
- <skip />
+ <string name="heap_dump_tile_name" msgid="9141031328971226374">"SysUI ହିପ୍ ଡମ୍ପ୍ କରନ୍ତୁ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index a797fbc..f4be71c 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"ਕੀ <xliff:g id="TILE_LABEL">%1$s</xliff:g> ਨੂੰ ਲੁਕਾਉਣਾ ਹੈ?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"ਇਹ ਅਗਲੀ ਵਾਰ ਮੁੜ ਪ੍ਰਗਟ ਹੋਵੇਗਾ ਜਦੋਂ ਤੁਸੀਂ ਇਸਨੂੰ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਚਾਲੂ ਕਰਦੇ ਹੋ।"</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"ਲੁਕਾਓ"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"ਤੁਸੀਂ ਆਪਣੀ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਵਰਤ ਰਹੇ ਹੋ"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"ਕਾਲ ਕਰੋ"</string>
<string name="stream_system" msgid="7493299064422163147">"ਸਿਸਟਮ"</string>
<string name="stream_ring" msgid="8213049469184048338">"ਘੰਟੀ ਵਜਾਓ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 6f0c064..6e2f664 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -528,7 +528,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Ukryć <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Pojawi się ponownie, gdy następnym włączysz go w ustawieniach."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ukryj"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Używasz profilu do pracy"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Połączenie"</string>
<string name="stream_system" msgid="7493299064422163147">"System"</string>
<string name="stream_ring" msgid="8213049469184048338">"Dzwonek"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 895cab4..a4f46a0 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -524,7 +524,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Esconder <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Ela reaparecerá na próxima vez que você ativá-la nas configurações."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ocultar"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Você está usando seu perfil de trabalho"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Ligar"</string>
<string name="stream_system" msgid="7493299064422163147">"Sistema"</string>
<string name="stream_ring" msgid="8213049469184048338">"Tocar"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 8a6b170..58b0315 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Pretende ocultar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Reaparecerá da próxima vez que a funcionalidade for ativada nas definições."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ocultar"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Está a utilizar o seu perfil de trabalho"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Chamada"</string>
<string name="stream_system" msgid="7493299064422163147">"Sistema"</string>
<string name="stream_ring" msgid="8213049469184048338">"Toque"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 895cab4..a4f46a0 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -524,7 +524,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Esconder <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Ela reaparecerá na próxima vez que você ativá-la nas configurações."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ocultar"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Você está usando seu perfil de trabalho"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Ligar"</string>
<string name="stream_system" msgid="7493299064422163147">"Sistema"</string>
<string name="stream_ring" msgid="8213049469184048338">"Tocar"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 3d68c6f..34baa8a 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -527,7 +527,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Ascundeți <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Va reapărea la următoarea activare în setări."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ascundeți"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Acum folosiți profilul de serviciu"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Apel"</string>
<string name="stream_system" msgid="7493299064422163147">"Sistem"</string>
<string name="stream_ring" msgid="8213049469184048338">"Sonerie"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 18c6221..186baca 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -530,7 +530,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Скрыть параметр \"<xliff:g id="TILE_LABEL">%1$s</xliff:g>\"?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Этот параметр появится в следующий раз, когда вы включите его."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Скрыть"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Вы перешли в рабочий профиль"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Вызов"</string>
<string name="stream_system" msgid="7493299064422163147">"Система"</string>
<string name="stream_ring" msgid="8213049469184048338">"Звонок"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index b84082d..a34cd9d 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> සඟවන්නද?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"ඊළඟ අවස්ථාවේ සැකසීම් තුළ ඔබ එය සක්රිය කළ විට එය නැවත දිසිවේ."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"සඟවන්න"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"ඔබ ඔබේ කාර්යාල පැතිකඩ භාවිත කරමින් සිටී"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"අමතන්න"</string>
<string name="stream_system" msgid="7493299064422163147">"පද්ධතිය"</string>
<string name="stream_ring" msgid="8213049469184048338">"නාද කරන්න"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index e751dba..e2fa577 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -530,7 +530,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Skryť <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Táto položka sa znova zobrazí, keď ju v nastaveniach opätovne zapnete."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Skryť"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Používate svoj pracovný profil."</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Zavolať"</string>
<string name="stream_system" msgid="7493299064422163147">"Systém"</string>
<string name="stream_ring" msgid="8213049469184048338">"Zvonenie"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 2478309..3114f10 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -530,7 +530,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Želite skriti <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Znova se bo pojavila, ko jo naslednjič vklopite v nastavitvah."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Skrij"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Uporabljate delovni profil"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Klic"</string>
<string name="stream_system" msgid="7493299064422163147">"Sistem"</string>
<string name="stream_ring" msgid="8213049469184048338">"Sprožitev zvonjenja"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 290e812..7ad3fa3 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Të fshihet <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Do të rishfaqet herën tjetër kur ta aktivizoni te cilësimet."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Fshih"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Po përdor profilin tënd të punës"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Telefono"</string>
<string name="stream_system" msgid="7493299064422163147">"Sistemi"</string>
<string name="stream_ring" msgid="8213049469184048338">"Bjeri ziles"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 07e0245..da30392 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -525,7 +525,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Желите ли да сакријете <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Ово ће се поново појавити када га следећи пут будете укључили у подешавањима."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Сакриј"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Користите профил за Work"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Позив"</string>
<string name="stream_system" msgid="7493299064422163147">"Систем"</string>
<string name="stream_ring" msgid="8213049469184048338">"Звоно"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index de5c82a..0deb4b4 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vill du dölja <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Den visas på nytt nästa gång du aktiverar den i inställningarna."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Dölj"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Du använder din jobbprofil"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Samtal"</string>
<string name="stream_system" msgid="7493299064422163147">"System"</string>
<string name="stream_ring" msgid="8213049469184048338">"Ringsignal"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index a60c9a4..ef90f3e 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Ungependa kuficha <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Itaonekana tena wakati mwingine utakapoiwasha katika mipangilio."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ficha"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Unatumia wasifu wako wa kazini"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Piga simu"</string>
<string name="stream_system" msgid="7493299064422163147">"Mfumo"</string>
<string name="stream_ring" msgid="8213049469184048338">"Piga"</string>
@@ -706,7 +705,7 @@
<string name="nav_bar_layout" msgid="3664072994198772020">"Mpangilio"</string>
<string name="left_nav_bar_button_type" msgid="8555981238887546528">"Aina ya kitufe cha kushoto cha ziada"</string>
<string name="right_nav_bar_button_type" msgid="2481056627065649656">"Aina ya kitufe cha kulia cha ziada"</string>
- <string name="nav_bar_default" msgid="8587114043070993007">"(chaguo msingi)"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"(chaguomsingi)"</string>
<string-array name="nav_bar_buttons">
<item msgid="1545641631806817203">"Ubao wa kunakili"</item>
<item msgid="5742013440802239414">"Msimbo wa ufunguo"</item>
@@ -736,12 +735,12 @@
<string name="tuner_time" msgid="6572217313285536011">"Wakati"</string>
<string-array name="clock_options">
<item msgid="5965318737560463480">"Onyesha saa, dakika na sekunde"</item>
- <item msgid="1427801730816895300">"Onyesha saa na dakika (chaguo msingi)"</item>
+ <item msgid="1427801730816895300">"Onyesha saa na dakika (chaguomsingi)"</item>
<item msgid="3830170141562534721">"Usionyeshe aikoni hii"</item>
</string-array>
<string-array name="battery_options">
<item msgid="3160236755818672034">"Onyesha asilimia kila wakati"</item>
- <item msgid="2139628951880142927">"Onyesha asilimia wakati inachaji (chaguo msingi)"</item>
+ <item msgid="2139628951880142927">"Onyesha asilimia wakati inachaji (chaguomsingi)"</item>
<item msgid="3327323682209964956">"Usionyeshe aikoni hii"</item>
</string-array>
<string name="other" msgid="4060683095962566764">"Nyingine"</string>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 74acfa2..eb5c180 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -19,9 +19,6 @@
<!-- Standard notification width + gravity -->
<dimen name="notification_panel_width">416dp</dimen>
- <!-- Width for the spacer, used between QS tiles depend on notification_panel_width -->
- <dimen name="qs_quick_tile_space_width">0dp</dimen>
-
<!-- Diameter of outer shape drawable shown in navbar search-->
<dimen name="navbar_search_outerring_diameter">430dip</dimen>
diff --git a/packages/SystemUI/res/values-sw900dp-land/dimen.xml b/packages/SystemUI/res/values-sw900dp-land/dimen.xml
index 55f23dd..ac7e6b8 100644
--- a/packages/SystemUI/res/values-sw900dp-land/dimen.xml
+++ b/packages/SystemUI/res/values-sw900dp-land/dimen.xml
@@ -18,4 +18,9 @@
<resources>
<!-- Standard notification width + gravity for tablet large screen device -->
<dimen name="notification_panel_width">544dp</dimen>
-</resources>
\ No newline at end of file
+
+ <!-- Maximum width of quick quick settings panel. -->
+ <dimen name="qs_quick_layout_width">478dp</dimen>
+
+</resources>
+
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 31eae85..b1eeb41 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>ஐ மறைக்கவா?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"அடுத்த முறை அமைப்புகளில் மீண்டும் இயக்கும்போது, இது மீண்டும் தோன்றும்."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"மறை"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"பணி சுயவிவரத்தைப் பயன்படுத்துகிறீர்கள்"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"அழைப்பு"</string>
<string name="stream_system" msgid="7493299064422163147">"சிஸ்டம்"</string>
<string name="stream_ring" msgid="8213049469184048338">"ரிங் செய்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index b1ed350..20a146e 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>ని దాచాలా?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"మీరు సెట్టింగ్ల్లో దీన్ని ఆన్ చేసిన తదుపరిసారి ఇది కనిపిస్తుంది."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"దాచు"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"మీరు మీ కార్యాలయ ప్రొఫైల్ను ఉపయోగిస్తున్నారు"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"కాల్"</string>
<string name="stream_system" msgid="7493299064422163147">"సిస్టమ్"</string>
<string name="stream_ring" msgid="8213049469184048338">"రింగ్"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index e7a98b6..76fae4e 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"ซ่อน <xliff:g id="TILE_LABEL">%1$s</xliff:g> ไหม"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"จะปรากฏอีกครั้งเมื่อคุณเปิดใช้ในการตั้งค่าครั้งถัดไป"</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"ซ่อน"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"คุณกำลังใช้โปรไฟล์งานของคุณ"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"การโทร"</string>
<string name="stream_system" msgid="7493299064422163147">"ระบบ"</string>
<string name="stream_ring" msgid="8213049469184048338">"เสียงเรียกเข้า"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 7fdee62..0c1b8a5 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Itago ang <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Lalabas itong muli sa susunod na pagkakataon na i-on mo ito sa mga setting."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Itago"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Ginagamit mo ang iyong profile sa trabaho"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Tumawag"</string>
<string name="stream_system" msgid="7493299064422163147">"System"</string>
<string name="stream_ring" msgid="8213049469184048338">"Ipa-ring"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index d537a09..7abf64f 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> gizlensin mi?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Ayarlardan etkinleştirdiğiniz bir sonraki sefer tekrar görünür."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Gizle"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"İş profilinizi kullanıyorsunuz"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Çağrı"</string>
<string name="stream_system" msgid="7493299064422163147">"Sistem"</string>
<string name="stream_ring" msgid="8213049469184048338">"Zili çaldır"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 14ff120..f9f5ce8 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -530,7 +530,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Сховати <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"З’явиться знову, коли ви ввімкнете його в налаштуваннях."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Сховати"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Ви в робочому профілі"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Виклик"</string>
<string name="stream_system" msgid="7493299064422163147">"Система"</string>
<string name="stream_ring" msgid="8213049469184048338">"Дзвінок"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index b4aa388..0566022 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> کو چھپائیں؟"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"اگلی بار جب آپ اسے ترتیبات میں آن کریں گے تو یہ ظاہر ہوگی۔"</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"چھپائیں"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"آپ اپنا دفتری پروفائل استعمال کر رہے ہیں۔"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"کال"</string>
<string name="stream_system" msgid="7493299064422163147">"سسٹم"</string>
<string name="stream_ring" msgid="8213049469184048338">"رِنگ"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 328faa5..5ce50a3 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -524,7 +524,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> berkitilsinmi?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Keyingi safar sozlamalardan yoqilgan paydo bo‘ladi."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Berkitish"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Siz ishchi profildan foydalanmoqdasiz"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Chaqiruv"</string>
<string name="stream_system" msgid="7493299064422163147">"Tizim"</string>
<string name="stream_ring" msgid="8213049469184048338">"Jiringlatish"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index d6e9b0a..3f0091f 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Ẩn <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Thông báo này sẽ xuất hiện lại vào lần tiếp theo bạn bật thông báo trong cài đặt."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ẩn"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Bạn đang sử dụng hồ sơ công việc của mình"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Gọi"</string>
<string name="stream_system" msgid="7493299064422163147">"Hệ thống"</string>
<string name="stream_ring" msgid="8213049469184048338">"Chuông"</string>
diff --git a/packages/SystemUI/res/values-w550dp-land/dimens.xml b/packages/SystemUI/res/values-w550dp-land/dimens.xml
index eaca9d7..2c66454 100644
--- a/packages/SystemUI/res/values-w550dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-w550dp-land/dimens.xml
@@ -18,4 +18,7 @@
<resources>
<!-- Standard notification width + gravity -->
<dimen name="notification_panel_width">544dp</dimen>
+
+ <!-- Maximum width of quick quick settings panel. -->
+ <dimen name="qs_quick_layout_width">478dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 7d40962..12675b0 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"要隐藏“<xliff:g id="TILE_LABEL">%1$s</xliff:g>”吗?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"下次在设置中将其开启后,此快捷设置条目将会重新显示。"</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"隐藏"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"您当前正在使用工作资料"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"通话"</string>
<string name="stream_system" msgid="7493299064422163147">"系统"</string>
<string name="stream_ring" msgid="8213049469184048338">"铃声"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 3ea0272..8f9b33f 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -524,7 +524,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"隱藏 <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"下一次您在設定開啟它時,它將再次出現。"</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"隱藏"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"您正在使用工作設定檔"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"通話"</string>
<string name="stream_system" msgid="7493299064422163147">"系統"</string>
<string name="stream_ring" msgid="8213049469184048338">"鈴聲"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 6b74a2a..2672138 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"隱藏<xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"只要在設定頁面中重新啟用,就能再次看到快捷設定選項。"</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"隱藏"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"你正在使用工作資料夾"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"通話"</string>
<string name="stream_system" msgid="7493299064422163147">"系統"</string>
<string name="stream_ring" msgid="8213049469184048338">"鈴響"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 1835d82..099cbfe 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -522,7 +522,6 @@
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Fihla i-<xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Izovela ngesikhathi esilandelayo uma uvule lesi silungiselelo."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Fihla"</string>
- <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Usebenzisa iphrofayela yakho yomsebenzi"</string>
<string name="stream_voice_call" msgid="4410002696470423714">"Shaya"</string>
<string name="stream_system" msgid="7493299064422163147">"Isistimu"</string>
<string name="stream_ring" msgid="8213049469184048338">"Khalisa"</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 975055c..07f1ee0 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -137,8 +137,10 @@
<color name="remote_input_accent">#eeeeee</color>
- <color name="quick_step_track_background_dark">#61000000</color>
- <color name="quick_step_track_background_light">#33FFFFFF</color>
+ <color name="quick_step_track_background_background_dark">#1F000000</color>
+ <color name="quick_step_track_background_background_light">#33FFFFFF</color>
+ <color name="quick_step_track_background_foreground_dark">#38000000</color>
+ <color name="quick_step_track_background_foreground_light">#59FFFFFF</color>
<!-- Keyboard shortcuts colors -->
<color name="ksh_application_group_color">#fff44336</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index eed1df0..786edf2 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -348,8 +348,8 @@
<dimen name="qs_tile_margin_top_bottom">12dp</dimen>
<dimen name="qs_tile_margin_top">18dp</dimen>
<dimen name="qs_quick_tile_size">48dp</dimen>
- <!-- Width for the spacer, used between QS tiles. -->
- <dimen name="qs_quick_tile_space_width">0dp</dimen>
+ <!-- Maximum width of quick quick settings panel. Defaults to MATCH_PARENT-->
+ <dimen name="qs_quick_layout_width">-1px</dimen>
<dimen name="qs_quick_tile_padding">12dp</dimen>
<dimen name="qs_header_gear_translation">16dp</dimen>
<dimen name="qs_header_tile_margin_horizontal">0dp</dimen>
@@ -763,9 +763,6 @@
<dimen name="volume_expander_margin_end">2dp</dimen>
<dimen name="volume_expander_margin_top">6dp</dimen>
- <!-- Padding between icon and text for managed profile toast -->
- <dimen name="managed_profile_toast_padding">4dp</dimen>
-
<!-- Thickness of the assist disclosure beams -->
<dimen name="assist_disclosure_thickness">2.5dp</dimen>
@@ -921,6 +918,10 @@
<dimen name="global_actions_top_padding">120dp</dimen>
+ <dimen name="global_actions_padding">12dp</dimen>
+
+ <dimen name="global_actions_translate">9dp</dimen>
+
<!-- the maximum offset in either direction that elements are moved horizontally to prevent
burn-in on AOD -->
<dimen name="burn_in_prevention_offset_x">8dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 84a76bc..915fc6e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1326,9 +1326,6 @@
<!-- Hide quick settings tile confirmation button -->
<string name="quick_settings_reset_confirmation_button">Hide</string>
- <!-- Toast shown when user unlocks screen and managed profile activity is in the foreground -->
- <string name="managed_profile_foreground_toast">You\'re using your work profile</string>
-
<!-- volume stream names. All nouns. -->
<string name="stream_voice_call">Call</string> <!-- STREAM_VOICE_CALL -->
<string name="stream_system">System</string> <!-- STREAM_SYSTEM -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index e4f5989..988a516 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -403,6 +403,9 @@
<item name="fillColor">?android:attr/textColorPrimary</item>
<item name="singleToneColor">?android:attr/textColorPrimary</item>
</style>
+ <style name="ScreenPinningRequestTheme" parent="@*android:style/ThemeOverlay.DeviceDefault.Accent">
+ <item name="singleToneColor">@color/light_mode_icon_color_single_tone</item>
+ </style>
<style name="TextAppearance.Volume">
<item name="android:textStyle">normal</item>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
index cd831d1..d38cc0f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
@@ -54,6 +54,7 @@
public static final int HIT_TARGET_HOME = 2;
public static final int HIT_TARGET_OVERVIEW = 3;
public static final int HIT_TARGET_ROTATION = 4;
+ public static final int HIT_TARGET_DEAD_ZONE = 5;
@Retention(RetentionPolicy.SOURCE)
@IntDef({FLAG_DISABLE_SWIPE_UP,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardConstants.java b/packages/SystemUI/src/com/android/keyguard/KeyguardConstants.java
index 62b8e7c..0340904 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardConstants.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardConstants.java
@@ -27,5 +27,5 @@
*/
public static final boolean DEBUG = false;
public static final boolean DEBUG_SIM_STATES = true;
- public static final boolean DEBUG_FP_WAKELOCK = true;
+ public static final boolean DEBUG_BIOMETRIC_WAKELOCK = true;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 075faa1..fa7e814 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -39,6 +39,7 @@
import android.app.UserSwitchObserver;
import android.app.admin.DevicePolicyManager;
import android.app.trust.TrustManager;
+import android.hardware.biometrics.BiometricSourceType;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -48,6 +49,7 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.ContentObserver;
+import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
@@ -72,7 +74,6 @@
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.telephony.TelephonyManager;
import android.util.Log;
-import android.util.Slog;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
@@ -145,26 +146,26 @@
private static final int MSG_DREAMING_STATE_CHANGED = 333;
private static final int MSG_USER_UNLOCKED = 334;
private static final int MSG_ASSISTANT_STACK_CHANGED = 335;
- private static final int MSG_FINGERPRINT_AUTHENTICATION_CONTINUE = 336;
+ private static final int MSG_BIOMETRIC_AUTHENTICATION_CONTINUE = 336;
private static final int MSG_DEVICE_POLICY_MANAGER_STATE_CHANGED = 337;
- /** Fingerprint state: Not listening to fingerprint. */
- private static final int FINGERPRINT_STATE_STOPPED = 0;
+ /** Biometric authentication state: Not listening. */
+ private static final int BIOMETRIC_STATE_STOPPED = 0;
- /** Fingerprint state: Listening. */
- private static final int FINGERPRINT_STATE_RUNNING = 1;
+ /** Biometric authentication state: Listening. */
+ private static final int BIOMETRIC_STATE_RUNNING = 1;
/**
- * Fingerprint state: Cancelling and waiting for the confirmation from FingerprintService to
+ * Biometric authentication: Cancelling and waiting for the relevant biometric service to
* send us the confirmation that cancellation has happened.
*/
- private static final int FINGERPRINT_STATE_CANCELLING = 2;
+ private static final int BIOMETRIC_STATE_CANCELLING = 2;
/**
- * Fingerprint state: During cancelling we got another request to start listening, so when we
+ * Biometric state: During cancelling we got another request to start listening, so when we
* receive the cancellation done signal, we should start listening again.
*/
- private static final int FINGERPRINT_STATE_CANCELLING_RESTARTING = 3;
+ private static final int BIOMETRIC_STATE_CANCELLING_RESTARTING = 3;
private static final int DEFAULT_CHARGING_VOLTAGE_MICRO_VOLT = 5000000;
@@ -227,7 +228,8 @@
private List<SubscriptionInfo> mSubscriptionInfo;
private TrustManager mTrustManager;
private UserManager mUserManager;
- private int mFingerprintRunningState = FINGERPRINT_STATE_STOPPED;
+ private int mFingerprintRunningState = BIOMETRIC_STATE_STOPPED;
+ private int mFaceRunningState = BIOMETRIC_STATE_STOPPED;
private LockPatternUtils mLockPatternUtils;
private final IDreamManager mDreamManager;
private boolean mIsDreaming;
@@ -235,14 +237,15 @@
private boolean mLogoutEnabled;
/**
- * Short delay before restarting fingerprint authentication after a successful try
- * This should be slightly longer than the time between onFingerprintAuthenticated and
- * setKeyguardGoingAway(true).
+ * Short delay before restarting biometric authentication after a successful try
+ * This should be slightly longer than the time between on<biometric>Authenticated
+ * (e.g. onFingerprintAuthenticated) and setKeyguardGoingAway(true).
*/
- private static final int FINGERPRINT_CONTINUE_DELAY_MS = 500;
+ private static final int BIOMETRIC_CONTINUE_DELAY_MS = 500;
// If FP daemon dies, keyguard should retry after a short delay
- private int mHardwareUnavailableRetryCount = 0;
+ private int mHardwareFingerprintUnavailableRetryCount = 0;
+ private int mHardwareFaceUnavailableRetryCount = 0;
private static final int HW_UNAVAILABLE_TIMEOUT = 3000; // ms
private static final int HW_UNAVAILABLE_RETRY_MAX = 3;
@@ -333,10 +336,10 @@
break;
case MSG_ASSISTANT_STACK_CHANGED:
mAssistantVisible = (boolean)msg.obj;
- updateFingerprintListeningState();
+ updateBiometricListeningState();
break;
- case MSG_FINGERPRINT_AUTHENTICATION_CONTINUE:
- updateFingerprintListeningState();
+ case MSG_BIOMETRIC_AUTHENTICATION_CONTINUE:
+ updateBiometricListeningState();
break;
case MSG_DEVICE_POLICY_MANAGER_STATE_CHANGED:
updateLogoutEnabled();
@@ -359,10 +362,11 @@
private SparseBooleanArray mUserHasTrust = new SparseBooleanArray();
private SparseBooleanArray mUserTrustIsManaged = new SparseBooleanArray();
private SparseBooleanArray mUserFingerprintAuthenticated = new SparseBooleanArray();
+ private SparseBooleanArray mUserFaceAuthenticated = new SparseBooleanArray();
private SparseBooleanArray mUserFaceUnlockRunning = new SparseBooleanArray();
private static int sCurrentUser;
- private Runnable mUpdateFingerprintListeningState = this::updateFingerprintListeningState;
+ private Runnable mUpdateBiometricListeningState = this::updateBiometricListeningState;
private static boolean sDisableHandlerCheckForTesting;
public synchronized static void setCurrentUser(int currentUser) {
@@ -487,7 +491,7 @@
*/
public void setKeyguardOccluded(boolean occluded) {
mKeyguardOccluded = occluded;
- updateFingerprintListeningState();
+ updateBiometricListeningState();
}
/**
@@ -515,19 +519,19 @@
mUserFingerprintAuthenticated.put(userId, true);
// Update/refresh trust state only if user can skip bouncer
if (getUserCanSkipBouncer(userId)) {
- mTrustManager.unlockedByFingerprintForUser(userId);
+ mTrustManager.unlockedByBiometricForUser(userId, BiometricSourceType.FINGERPRINT);
}
// Don't send cancel if authentication succeeds
mFingerprintCancelSignal = null;
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
- cb.onFingerprintAuthenticated(userId);
+ cb.onBiometricAuthenticated(userId, BiometricSourceType.FINGERPRINT);
}
}
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_FINGERPRINT_AUTHENTICATION_CONTINUE),
- FINGERPRINT_CONTINUE_DELAY_MS);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE),
+ BIOMETRIC_CONTINUE_DELAY_MS);
// Only authenticate fingerprint once when assistant is visible
mAssistantVisible = false;
@@ -539,10 +543,10 @@
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
- cb.onFingerprintAuthFailed();
+ cb.onBiometricAuthFailed(BiometricSourceType.FINGERPRINT);
}
}
- handleFingerprintHelp(-1, mContext.getString(R.string.fingerprint_not_recognized));
+ handleFingerprintHelp(-1, mContext.getString(R.string.kg_fingerprint_not_recognized));
}
private void handleFingerprintAcquired(int acquireInfo) {
@@ -552,7 +556,7 @@
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
- cb.onFingerprintAcquired();
+ cb.onBiometricAcquired(BiometricSourceType.FINGERPRINT);
}
}
}
@@ -577,7 +581,7 @@
}
onFingerprintAuthenticated(userId);
} finally {
- setFingerprintRunningState(FINGERPRINT_STATE_STOPPED);
+ setFingerprintRunningState(BIOMETRIC_STATE_STOPPED);
}
Trace.endSection();
}
@@ -586,7 +590,7 @@
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
- cb.onFingerprintHelp(msgId, helpString);
+ cb.onBiometricHelp(msgId, helpString, BiometricSourceType.FINGERPRINT);
}
}
}
@@ -595,23 +599,23 @@
@Override
public void run() {
Log.w(TAG, "Retrying fingerprint after HW unavailable, attempt " +
- mHardwareUnavailableRetryCount);
+ mHardwareFingerprintUnavailableRetryCount);
updateFingerprintListeningState();
}
};
private void handleFingerprintError(int msgId, String errString) {
if (msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED
- && mFingerprintRunningState == FINGERPRINT_STATE_CANCELLING_RESTARTING) {
- setFingerprintRunningState(FINGERPRINT_STATE_STOPPED);
+ && mFingerprintRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) {
+ setFingerprintRunningState(BIOMETRIC_STATE_STOPPED);
startListeningForFingerprint();
} else {
- setFingerprintRunningState(FINGERPRINT_STATE_STOPPED);
+ setFingerprintRunningState(BIOMETRIC_STATE_STOPPED);
}
if (msgId == FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE) {
- if (mHardwareUnavailableRetryCount < HW_UNAVAILABLE_RETRY_MAX) {
- mHardwareUnavailableRetryCount++;
+ if (mHardwareFingerprintUnavailableRetryCount < HW_UNAVAILABLE_RETRY_MAX) {
+ mHardwareFingerprintUnavailableRetryCount++;
mHandler.removeCallbacks(mRetryFingerprintAuthentication);
mHandler.postDelayed(mRetryFingerprintAuthentication, HW_UNAVAILABLE_TIMEOUT);
}
@@ -626,7 +630,7 @@
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
- cb.onFingerprintError(msgId, errString);
+ cb.onBiometricError(msgId, errString, BiometricSourceType.FINGERPRINT);
}
}
}
@@ -636,8 +640,8 @@
}
private void setFingerprintRunningState(int fingerprintRunningState) {
- boolean wasRunning = mFingerprintRunningState == FINGERPRINT_STATE_RUNNING;
- boolean isRunning = fingerprintRunningState == FINGERPRINT_STATE_RUNNING;
+ boolean wasRunning = mFingerprintRunningState == BIOMETRIC_STATE_RUNNING;
+ boolean isRunning = fingerprintRunningState == BIOMETRIC_STATE_RUNNING;
mFingerprintRunningState = fingerprintRunningState;
// Clients of KeyguardUpdateMonitor don't care about the internal state about the
@@ -653,10 +657,162 @@
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
- cb.onFingerprintRunningStateChanged(isFingerprintDetectionRunning());
+ cb.onBiometricRunningStateChanged(isFingerprintDetectionRunning(),
+ BiometricSourceType.FINGERPRINT);
}
}
}
+
+ private void onFaceAuthenticated(int userId) {
+ Trace.beginSection("KeyGuardUpdateMonitor#onFaceAuthenticated");
+ mUserFaceAuthenticated.put(userId, true);
+ // Update/refresh trust state only if user can skip bouncer
+ if (getUserCanSkipBouncer(userId)) {
+ mTrustManager.unlockedByBiometricForUser(userId, BiometricSourceType.FACE);
+ }
+ // Don't send cancel if authentication succeeds
+ mFaceCancelSignal = null;
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onBiometricAuthenticated(userId,
+ BiometricSourceType.FACE);
+ }
+ }
+
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE),
+ BIOMETRIC_CONTINUE_DELAY_MS);
+
+ // Only authenticate face once when assistant is visible
+ mAssistantVisible = false;
+
+ Trace.endSection();
+ }
+
+ private void handleFaceAuthFailed() {
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onBiometricAuthFailed(BiometricSourceType.FACE);
+ }
+ }
+ handleFaceHelp(-1, mContext.getString(R.string.kg_face_not_recognized));
+ }
+
+ private void handleFaceAcquired(int acquireInfo) {
+ if (acquireInfo != FaceManager.FACE_ACQUIRED_GOOD) {
+ return;
+ }
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onBiometricAcquired(BiometricSourceType.FACE);
+ }
+ }
+ }
+
+ private void handleFaceAuthenticated(int authUserId) {
+ Trace.beginSection("KeyGuardUpdateMonitor#handlerFaceAuthenticated");
+ try {
+ final int userId;
+ try {
+ userId = ActivityManager.getService().getCurrentUser().id;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to get current user id: ", e);
+ return;
+ }
+ if (userId != authUserId) {
+ Log.d(TAG, "Face authenticated for wrong user: " + authUserId);
+ return;
+ }
+ if (isFaceDisabled(userId)) {
+ Log.d(TAG, "Face authentication disabled by DPM for userId: " + userId);
+ return;
+ }
+ onFaceAuthenticated(userId);
+ } finally {
+ setFaceRunningState(BIOMETRIC_STATE_STOPPED);
+ }
+ Trace.endSection();
+ }
+
+ private void handleFaceHelp(int msgId, String helpString) {
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onBiometricHelp(msgId, helpString, BiometricSourceType.FACE);
+ }
+ }
+ }
+
+ private Runnable mRetryFaceAuthentication = new Runnable() {
+ @Override
+ public void run() {
+ Log.w(TAG, "Retrying face after HW unavailable, attempt " +
+ mHardwareFaceUnavailableRetryCount);
+ updateFaceListeningState();
+ }
+ };
+
+ private void handleFaceError(int msgId, String errString) {
+ if (msgId == FaceManager.FACE_ERROR_CANCELED
+ && mFaceRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) {
+ setFaceRunningState(BIOMETRIC_STATE_STOPPED);
+ startListeningForFace();
+ } else {
+ setFaceRunningState(BIOMETRIC_STATE_STOPPED);
+ }
+
+ if (msgId == FaceManager.FACE_ERROR_HW_UNAVAILABLE) {
+ if (mHardwareFaceUnavailableRetryCount < HW_UNAVAILABLE_RETRY_MAX) {
+ mHardwareFaceUnavailableRetryCount++;
+ mHandler.removeCallbacks(mRetryFaceAuthentication);
+ mHandler.postDelayed(mRetryFaceAuthentication, HW_UNAVAILABLE_TIMEOUT);
+ }
+ }
+
+ if (msgId == FaceManager.FACE_ERROR_LOCKOUT_PERMANENT) {
+ mLockPatternUtils.requireStrongAuth(
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT,
+ getCurrentUser());
+ }
+
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onBiometricError(msgId, errString,
+ BiometricSourceType.FACE);
+ }
+ }
+ }
+
+ private void handleFaceLockoutReset() {
+ updateFaceListeningState();
+ }
+
+ private void setFaceRunningState(int faceRunningState) {
+ boolean wasRunning = mFaceRunningState == BIOMETRIC_STATE_RUNNING;
+ boolean isRunning = faceRunningState == BIOMETRIC_STATE_RUNNING;
+ mFaceRunningState = faceRunningState;
+
+ // Clients of KeyguardUpdateMonitor don't care about the internal state or about the
+ // asynchronousness of the cancel cycle. So only notify them if the actualy running state
+ // has changed.
+ if (wasRunning != isRunning) {
+ notifyFaceRunningStateChanged();
+ }
+ }
+
+ private void notifyFaceRunningStateChanged() {
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onBiometricRunningStateChanged(isFaceDetectionRunning(),
+ BiometricSourceType.FACE);
+ }
+ }
+ }
+
private void handleFaceUnlockStateChanged(boolean running, int userId) {
checkIsHandlerThread();
mUserFaceUnlockRunning.put(userId, running);
@@ -673,7 +829,11 @@
}
public boolean isFingerprintDetectionRunning() {
- return mFingerprintRunningState == FINGERPRINT_STATE_RUNNING;
+ return mFingerprintRunningState == BIOMETRIC_STATE_RUNNING;
+ }
+
+ public boolean isFaceDetectionRunning() {
+ return mFaceRunningState == BIOMETRIC_STATE_RUNNING;
}
private boolean isTrustDisabled(int userId) {
@@ -692,9 +852,18 @@
|| isSimPinSecure();
}
+ private boolean isFaceDisabled(int userId) {
+ final DevicePolicyManager dpm =
+ (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ return dpm != null && (dpm.getKeyguardDisabledFeatures(null, userId)
+ & DevicePolicyManager.KEYGUARD_DISABLE_FACE) != 0
+ || isSimPinSecure();
+ }
+
+
public boolean getUserCanSkipBouncer(int userId) {
return getUserHasTrust(userId) || (mUserFingerprintAuthenticated.get(userId)
- && isUnlockingWithFingerprintAllowed());
+ && isUnlockingWithBiometricAllowed());
}
public boolean getUserHasTrust(int userId) {
@@ -705,8 +874,8 @@
return mUserTrustIsManaged.get(userId) && !isTrustDisabled(userId);
}
- public boolean isUnlockingWithFingerprintAllowed() {
- return mStrongAuthTracker.isUnlockingWithFingerprintAllowed();
+ public boolean isUnlockingWithBiometricAllowed() {
+ return mStrongAuthTracker.isUnlockingWithBiometricAllowed();
}
public boolean isUserInLockdown(int userId) {
@@ -862,7 +1031,7 @@
}
};
- private final FingerprintManager.LockoutResetCallback mLockoutResetCallback
+ private final FingerprintManager.LockoutResetCallback mFingerprintLockoutResetCallback
= new FingerprintManager.LockoutResetCallback() {
@Override
public void onLockoutReset() {
@@ -870,13 +1039,21 @@
}
};
- private FingerprintManager.AuthenticationCallback mAuthenticationCallback
+ private final FaceManager.LockoutResetCallback mFaceLockoutResetCallback
+ = new FaceManager.LockoutResetCallback() {
+ @Override
+ public void onLockoutReset() {
+ handleFaceLockoutReset();
+ }
+ };
+
+ private FingerprintManager.AuthenticationCallback mFingerprintAuthenticationCallback
= new AuthenticationCallback() {
@Override
public void onAuthenticationFailed() {
handleFingerprintAuthFailed();
- };
+ }
@Override
public void onAuthenticationSucceeded(AuthenticationResult result) {
@@ -900,8 +1077,42 @@
handleFingerprintAcquired(acquireInfo);
}
};
+
+ private FaceManager.AuthenticationCallback mFaceAuthenticationCallback
+ = new FaceManager.AuthenticationCallback() {
+
+ @Override
+ public void onAuthenticationFailed() {
+ handleFaceAuthFailed();
+ }
+
+ @Override
+ public void onAuthenticationSucceeded(FaceManager.AuthenticationResult result) {
+ Trace.beginSection("KeyguardUpdateMonitor#onAuthenticationSucceeded");
+ handleFaceAuthenticated(result.getUserId());
+ Trace.endSection();
+ }
+
+ @Override
+ public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
+ handleFaceHelp(helpMsgId, helpString.toString());
+ }
+
+ @Override
+ public void onAuthenticationError(int errMsgId, CharSequence errString) {
+ handleFaceError(errMsgId, errString.toString());
+ }
+
+ @Override
+ public void onAuthenticationAcquired(int acquireInfo) {
+ handleFaceAcquired(acquireInfo);
+ }
+ };
+
private CancellationSignal mFingerprintCancelSignal;
+ private CancellationSignal mFaceCancelSignal;
private FingerprintManager mFpm;
+ private FaceManager mFaceAuthenticationManager;
/**
* When we receive a
@@ -1049,9 +1260,9 @@
super(context);
}
- public boolean isUnlockingWithFingerprintAllowed() {
+ public boolean isUnlockingWithBiometricAllowed() {
int userId = getCurrentUser();
- return isFingerprintAllowedForUser(userId);
+ return isBiometricAllowedForUser(userId);
}
public boolean hasUserAuthenticatedSinceBoot() {
@@ -1075,7 +1286,7 @@
protected void handleStartedWakingUp() {
Trace.beginSection("KeyguardUpdateMonitor#handleStartedWakingUp");
- updateFingerprintListeningState();
+ updateBiometricListeningState();
final int count = mCallbacks.size();
for (int i = 0; i < count; i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
@@ -1087,7 +1298,7 @@
}
protected void handleStartedGoingToSleep(int arg1) {
- clearFingerprintRecognized();
+ clearBiometricRecognized();
final int count = mCallbacks.size();
for (int i = 0; i < count; i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
@@ -1096,7 +1307,7 @@
}
}
mGoingToSleep = true;
- updateFingerprintListeningState();
+ updateBiometricListeningState();
}
protected void handleFinishedGoingToSleep(int arg1) {
@@ -1108,7 +1319,7 @@
cb.onFinishedGoingToSleep(arg1);
}
}
- updateFingerprintListeningState();
+ updateBiometricListeningState();
}
private void handleScreenTurnedOn() {
@@ -1122,7 +1333,8 @@
}
private void handleScreenTurnedOff() {
- mHardwareUnavailableRetryCount = 0;
+ mHardwareFingerprintUnavailableRetryCount = 0;
+ mHardwareFaceUnavailableRetryCount = 0;
final int count = mCallbacks.size();
for (int i = 0; i < count; i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
@@ -1141,7 +1353,7 @@
cb.onDreamingStateChanged(mIsDreaming);
}
}
- updateFingerprintListeningState();
+ updateBiometricListeningState();
}
private void handleUserInfoChanged(int userId) {
@@ -1238,9 +1450,17 @@
if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
mFpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
}
- updateFingerprintListeningState();
+
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) {
+ mFaceAuthenticationManager =
+ (FaceManager) context.getSystemService(Context.FACE_SERVICE);
+ }
+ updateBiometricListeningState();
if (mFpm != null) {
- mFpm.addLockoutResetCallback(mLockoutResetCallback);
+ mFpm.addLockoutResetCallback(mFingerprintLockoutResetCallback);
+ }
+ if (mFaceAuthenticationManager != null) {
+ mFaceAuthenticationManager.addLockoutResetCallback(mFaceLockoutResetCallback);
}
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
@@ -1249,28 +1469,55 @@
mLogoutEnabled = mDevicePolicyManager.isLogoutEnabled();
}
+ private void updateBiometricListeningState() {
+ updateFingerprintListeningState();
+ updateFaceListeningState();
+ }
+
private void updateFingerprintListeningState() {
// If this message exists, we should not authenticate again until this message is
// consumed by the handler
- if (mHandler.hasMessages(MSG_FINGERPRINT_AUTHENTICATION_CONTINUE)) {
+ if (mHandler.hasMessages(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE)) {
return;
}
mHandler.removeCallbacks(mRetryFingerprintAuthentication);
boolean shouldListenForFingerprint = shouldListenForFingerprint();
- if (mFingerprintRunningState == FINGERPRINT_STATE_RUNNING && !shouldListenForFingerprint) {
+ if (mFingerprintRunningState == BIOMETRIC_STATE_RUNNING && !shouldListenForFingerprint) {
stopListeningForFingerprint();
- } else if (mFingerprintRunningState != FINGERPRINT_STATE_RUNNING
+ } else if (mFingerprintRunningState != BIOMETRIC_STATE_RUNNING
&& shouldListenForFingerprint) {
startListeningForFingerprint();
}
}
+ private void updateFaceListeningState() {
+ // If this message exists, we should not authenticate again until this message is
+ // consumed by the handler
+ if (mHandler.hasMessages(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE)) {
+ return;
+ }
+ mHandler.removeCallbacks(mRetryFaceAuthentication);
+ boolean shouldListenForFace = shouldListenForFace();
+ if (mFaceRunningState == BIOMETRIC_STATE_RUNNING && !shouldListenForFace) {
+ stopListeningForFace();
+ } else if (mFaceRunningState != BIOMETRIC_STATE_RUNNING
+ && shouldListenForFace) {
+ startListeningForFace();
+ }
+ }
+
private boolean shouldListenForFingerprintAssistant() {
return mAssistantVisible && mKeyguardOccluded
&& !mUserFingerprintAuthenticated.get(getCurrentUser(), false)
&& !mUserHasTrust.get(getCurrentUser(), false);
}
+ private boolean shouldListenForFaceAssistant() {
+ return mAssistantVisible && mKeyguardOccluded
+ && !mUserFaceAuthenticated.get(getCurrentUser(), false)
+ && !mUserHasTrust.get(getCurrentUser(), false);
+ }
+
private boolean shouldListenForFingerprint() {
return (mKeyguardIsVisible || !mDeviceInteractive ||
(mBouncer && !mKeyguardGoingAway) || mGoingToSleep ||
@@ -1279,9 +1526,18 @@
&& !mKeyguardGoingAway;
}
+ private boolean shouldListenForFace() {
+ return (mKeyguardIsVisible || !mDeviceInteractive ||
+ (mBouncer && !mKeyguardGoingAway) || mGoingToSleep ||
+ shouldListenForFaceAssistant() || (mKeyguardOccluded && mIsDreaming))
+ && !mSwitchingUser && !isFaceDisabled(getCurrentUser())
+ && !mKeyguardGoingAway;
+ }
+
+
private void startListeningForFingerprint() {
- if (mFingerprintRunningState == FINGERPRINT_STATE_CANCELLING) {
- setFingerprintRunningState(FINGERPRINT_STATE_CANCELLING_RESTARTING);
+ if (mFingerprintRunningState == BIOMETRIC_STATE_CANCELLING) {
+ setFingerprintRunningState(BIOMETRIC_STATE_CANCELLING_RESTARTING);
return;
}
if (DEBUG) Log.v(TAG, "startListeningForFingerprint()");
@@ -1291,9 +1547,27 @@
mFingerprintCancelSignal.cancel();
}
mFingerprintCancelSignal = new CancellationSignal();
- mFpm.authenticate(null, mFingerprintCancelSignal, 0, mAuthenticationCallback, null,
- userId);
- setFingerprintRunningState(FINGERPRINT_STATE_RUNNING);
+ mFpm.authenticate(null, mFingerprintCancelSignal, 0, mFingerprintAuthenticationCallback,
+ null, userId);
+ setFingerprintRunningState(BIOMETRIC_STATE_RUNNING);
+ }
+ }
+
+ private void startListeningForFace() {
+ if (mFaceRunningState == BIOMETRIC_STATE_CANCELLING) {
+ setFaceRunningState(BIOMETRIC_STATE_CANCELLING_RESTARTING);
+ return;
+ }
+ if (DEBUG) Log.v(TAG, "startListeningForFace()");
+ int userId = ActivityManager.getCurrentUser();
+ if (isUnlockWithFacePossible(userId)) {
+ if (mFaceCancelSignal != null) {
+ mFaceCancelSignal.cancel();
+ }
+ mFaceCancelSignal = new CancellationSignal();
+ mFaceAuthenticationManager.authenticate(null, mFaceCancelSignal, 0,
+ mFaceAuthenticationCallback, null);
+ setFaceRunningState(BIOMETRIC_STATE_RUNNING);
}
}
@@ -1302,17 +1576,37 @@
&& mFpm.getEnrolledFingerprints(userId).size() > 0;
}
+ public boolean isUnlockWithFacePossible(int userId) {
+ return mFaceAuthenticationManager != null && mFaceAuthenticationManager.isHardwareDetected()
+ && !isFaceDisabled(userId)
+ && mFaceAuthenticationManager.hasEnrolledFaces(userId);
+ }
+
private void stopListeningForFingerprint() {
if (DEBUG) Log.v(TAG, "stopListeningForFingerprint()");
- if (mFingerprintRunningState == FINGERPRINT_STATE_RUNNING) {
+ if (mFingerprintRunningState == BIOMETRIC_STATE_RUNNING) {
if (mFingerprintCancelSignal != null) {
mFingerprintCancelSignal.cancel();
mFingerprintCancelSignal = null;
}
- setFingerprintRunningState(FINGERPRINT_STATE_CANCELLING);
+ setFingerprintRunningState(BIOMETRIC_STATE_CANCELLING);
}
- if (mFingerprintRunningState == FINGERPRINT_STATE_CANCELLING_RESTARTING) {
- setFingerprintRunningState(FINGERPRINT_STATE_CANCELLING);
+ if (mFingerprintRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) {
+ setFingerprintRunningState(BIOMETRIC_STATE_CANCELLING);
+ }
+ }
+
+ private void stopListeningForFace() {
+ if (DEBUG) Log.v(TAG, "stopListeningForFace()");
+ if (mFaceRunningState == BIOMETRIC_STATE_RUNNING) {
+ if (mFaceCancelSignal != null) {
+ mFaceCancelSignal.cancel();
+ mFaceCancelSignal = null;
+ }
+ setFaceRunningState(BIOMETRIC_STATE_CANCELLING);
+ }
+ if (mFaceRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) {
+ setFaceRunningState(BIOMETRIC_STATE_CANCELLING);
}
}
@@ -1609,7 +1903,7 @@
cb.onKeyguardVisibilityChangedRaw(showing);
}
}
- updateFingerprintListeningState();
+ updateBiometricListeningState();
}
/**
@@ -1617,7 +1911,7 @@
*/
private void handleKeyguardReset() {
if (DEBUG) Log.d(TAG, "handleKeyguardReset");
- updateFingerprintListeningState();
+ updateBiometricListeningState();
mNeedsSlowUnlockTransition = resolveNeedsSlowUnlockTransition();
}
@@ -1646,7 +1940,7 @@
cb.onKeyguardBouncerChanged(isBouncer);
}
}
- updateFingerprintListeningState();
+ updateBiometricListeningState();
}
/**
@@ -1729,7 +2023,7 @@
public void setSwitchingUser(boolean switching) {
mSwitchingUser = switching;
// Since this comes in on a binder thread, we need to post if first
- mHandler.post(mUpdateFingerprintListeningState);
+ mHandler.post(mUpdateBiometricListeningState);
}
private void sendUpdates(KeyguardUpdateMonitorCallback callback) {
@@ -1817,9 +2111,11 @@
mFailedAttempts.put(userId, getFailedUnlockAttempts(userId) + 1);
}
- public void clearFingerprintRecognized() {
+ public void clearBiometricRecognized() {
mUserFingerprintAuthenticated.clear();
- mTrustManager.clearAllFingerprints();
+ mUserFaceAuthenticated.clear();
+ mTrustManager.clearAllBiometricRecognized(BiometricSourceType.FINGERPRINT);
+ mTrustManager.clearAllBiometricRecognized(BiometricSourceType.FACE);
}
public boolean isSimPinVoiceSecure() {
@@ -2054,7 +2350,7 @@
final int userId = ActivityManager.getCurrentUser();
final int strongAuthFlags = mStrongAuthTracker.getStrongAuthForUser(userId);
pw.println(" Fingerprint state (user=" + userId + ")");
- pw.println(" allowed=" + isUnlockingWithFingerprintAllowed());
+ pw.println(" allowed=" + isUnlockingWithBiometricAllowed());
pw.println(" auth'd=" + mUserFingerprintAuthenticated.get(userId));
pw.println(" authSinceBoot="
+ getStrongAuthTracker().hasUserAuthenticatedSinceBoot());
@@ -2063,5 +2359,18 @@
pw.println(" strongAuthFlags=" + Integer.toHexString(strongAuthFlags));
pw.println(" trustManaged=" + getUserTrustIsManaged(userId));
}
+ if (mFaceAuthenticationManager != null && mFaceAuthenticationManager.isHardwareDetected()) {
+ final int userId = ActivityManager.getCurrentUser();
+ final int strongAuthFlags = mStrongAuthTracker.getStrongAuthForUser(userId);
+ pw.println(" Face authentication state (user=" + userId + ")");
+ pw.println(" allowed=" + isUnlockingWithBiometricAllowed());
+ pw.println(" auth'd=" + mUserFaceAuthenticated.get(userId));
+ pw.println(" authSinceBoot="
+ + getStrongAuthTracker().hasUserAuthenticatedSinceBoot());
+ pw.println(" disabled(DPM)=" + isFaceDisabled(userId));
+ pw.println(" possible=" + isUnlockWithFacePossible(userId));
+ pw.println(" strongAuthFlags=" + Integer.toHexString(strongAuthFlags));
+ pw.println(" trustManaged=" + getUserTrustIsManaged(userId));
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 67571bb..8135ac5 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -17,7 +17,7 @@
import android.app.admin.DevicePolicyManager;
import android.graphics.Bitmap;
-import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.biometrics.BiometricSourceType;
import android.media.AudioManager;
import android.os.SystemClock;
import android.telephony.TelephonyManager;
@@ -213,38 +213,46 @@
public void onTrustGrantedWithFlags(int flags, int userId) { }
/**
- * Called when a finger has been acquired.
+ * Called when a biometric has been acquired.
* <p>
- * It is guaranteed that either {@link #onFingerprintAuthenticated} or
- * {@link #onFingerprintAuthFailed()} is called after this method eventually.
+ * It is guaranteed that either {@link #onBiometricAuthenticated} or
+ * {@link #onBiometricAuthFailed(BiometricSourceType)} is called after this method eventually.
+ * @param biometricSourceType
*/
- public void onFingerprintAcquired() { }
+ public void onBiometricAcquired(BiometricSourceType biometricSourceType) { }
/**
- * Called when a fingerprint couldn't be authenticated.
+ * Called when a biometric couldn't be authenticated.
+ * @param biometricSourceType
*/
- public void onFingerprintAuthFailed() { }
+ public void onBiometricAuthFailed(BiometricSourceType biometricSourceType) { }
/**
- * Called when a fingerprint is recognized.
- * @param userId the user id for which the fingerprint was authenticated
+ * Called when a biometric is recognized.
+ * @param userId the user id for which the biometric sample was authenticated
+ * @param biometricSourceType
*/
- public void onFingerprintAuthenticated(int userId) { }
+ public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType) { }
/**
- * Called when fingerprint provides help string (e.g. "Try again")
+ * Called when biometric authentication provides help string (e.g. "Try again")
* @param msgId
* @param helpString
+ * @param biometricSourceType
*/
- public void onFingerprintHelp(int msgId, String helpString) { }
+ public void onBiometricHelp(int msgId, String helpString,
+ BiometricSourceType biometricSourceType) { }
/**
- * Called when fingerprint provides an semi-permanent error message
- * (e.g. "Hardware not available").
- * @param msgId one of the error messages listed in {@link FingerprintManager}
+ * Called when biometric authentication method provides a semi-permanent
+ * error message (e.g. "Hardware not available").
+ * @param msgId one of the error messages listed in
+ * {@link android.hardware.biometrics.BiometricConstants}
* @param errString
+ * @param biometricSourceType
*/
- public void onFingerprintError(int msgId, String errString) { }
+ public void onBiometricError(int msgId, String errString,
+ BiometricSourceType biometricSourceType) { }
/**
* Called when the state of face unlock changed.
@@ -252,9 +260,10 @@
public void onFaceUnlockStateChanged(boolean running, int userId) { }
/**
- * Called when the fingerprint running state changed.
+ * Called when biometric running state changed.
*/
- public void onFingerprintRunningStateChanged(boolean running) { }
+ public void onBiometricRunningStateChanged(boolean running,
+ BiometricSourceType biometricSourceType) { }
/**
* Called when the state that the user hasn't used strong authentication since quite some time
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 61784fa..3ac6705 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -55,6 +55,7 @@
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
import com.android.systemui.util.Utils.DisableStateTracker;
+import com.android.systemui.R;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -74,6 +75,7 @@
private int mTextColor;
private int mLevel;
private boolean mForceShowPercent;
+ private boolean mShowPercentAvailable;
private int mDarkModeBackgroundColor;
private int mDarkModeFillColor;
@@ -113,6 +115,9 @@
atts.recycle();
mSettingObserver = new SettingObserver(new Handler(context.getMainLooper()));
+ mShowPercentAvailable = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_battery_percentage_setting_available);
+
addOnAttachStateChangeListener(
new DisableStateTracker(DISABLE_NONE, DISABLE2_SYSTEM_ICONS));
@@ -264,8 +269,11 @@
private void updateShowPercent() {
final boolean showing = mBatteryPercentView != null;
- if (0 != Settings.System.getIntForUser(getContext().getContentResolver(),
- SHOW_BATTERY_PERCENT, 0, mUser) || mForceShowPercent) {
+ final boolean systemSetting = 0 != Settings.System
+ .getIntForUser(getContext().getContentResolver(),
+ SHOW_BATTERY_PERCENT, 0, mUser);
+
+ if ((mShowPercentAvailable && systemSetting) || mForceShowPercent) {
if (!showing) {
mBatteryPercentView = loadPercentView();
if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor);
diff --git a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
index 98dc321..7742c55 100644
--- a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
@@ -27,24 +27,22 @@
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver;
-import android.widget.FrameLayout;
import android.widget.LinearLayout;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
import com.android.systemui.util.leak.RotationUtils;
-import java.util.ArrayList;
-
import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE;
import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE;
import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE;
-public class HardwareUiLayout extends FrameLayout implements Tunable {
+public class HardwareUiLayout extends LinearLayout implements Tunable {
private static final String EDGE_BLEED = "sysui_hwui_edge_bleed";
private static final String ROUNDED_DIVIDER = "sysui_hwui_rounded_divider";
private final int[] mTmp2 = new int[2];
private View mChild;
+ private View mSeparatedView;
private int mOldHeight;
private boolean mAnimating;
private AnimatorSet mAnimation;
@@ -53,6 +51,7 @@
private HardwareBgDrawable mBackground;
private Animator mAnimator;
private boolean mCollapse;
+ private boolean mHasSeparatedButton;
private int mEndPoint;
private boolean mEdgeBleed;
private boolean mRoundedDivider;
@@ -94,6 +93,7 @@
mBackground = new HardwareBgDrawable(mRoundedDivider, !mEdgeBleed, getContext());
if (mChild != null) {
mChild.setBackground(mBackground);
+ mSeparatedView.setBackground(mBackground);
requestLayout();
}
}
@@ -110,6 +110,18 @@
}
mChild.setLayoutParams(params);
}
+
+ if (mSeparatedView != null) {
+ MarginLayoutParams params = (MarginLayoutParams) mSeparatedView.getLayoutParams();
+ if (mRotation == ROTATION_LANDSCAPE) {
+ params.topMargin = edge;
+ } else if (mRotation == ROTATION_SEASCAPE) {
+ params.bottomMargin = edge;
+ } else {
+ params.rightMargin = edge;
+ }
+ mSeparatedView.setLayoutParams(params);
+ }
}
private int getEdgePadding() {
@@ -123,6 +135,8 @@
if (getChildCount() != 0) {
mChild = getChildAt(0);
mChild.setBackground(mBackground);
+ mSeparatedView = getChildAt(1);
+ mSeparatedView.setBackground(mBackground);
updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding());
mOldHeight = mChild.getMeasuredHeight();
mChild.addOnLayoutChangeListener(
@@ -170,6 +184,17 @@
} else {
rotateLeft();
}
+ if (mHasSeparatedButton) {
+ if (from == ROTATION_SEASCAPE || to == ROTATION_SEASCAPE) {
+ // Separated view has top margin, so seascape separated view need special rotation,
+ // not a full left or right rotation.
+ swapLeftAndTop(mSeparatedView);
+ } else if (from == ROTATION_LANDSCAPE) {
+ rotateRight(mSeparatedView);
+ } else {
+ rotateLeft(mSeparatedView);
+ }
+ }
if (to != ROTATION_NONE) {
if (mChild instanceof LinearLayout) {
mRotatedBackground = true;
@@ -177,8 +202,10 @@
LinearLayout linearLayout = (LinearLayout) mChild;
if (mSwapOrientation) {
linearLayout.setOrientation(LinearLayout.HORIZONTAL);
+ setOrientation(LinearLayout.HORIZONTAL);
}
- swapDimens(this.mChild);
+ swapDimens(mChild);
+ swapDimens(mSeparatedView);
}
} else {
if (mChild instanceof LinearLayout) {
@@ -187,8 +214,10 @@
LinearLayout linearLayout = (LinearLayout) mChild;
if (mSwapOrientation) {
linearLayout.setOrientation(LinearLayout.VERTICAL);
+ setOrientation(LinearLayout.VERTICAL);
}
swapDimens(mChild);
+ swapDimens(mSeparatedView);
}
}
}
@@ -201,6 +230,12 @@
LayoutParams p = (LayoutParams) mChild.getLayoutParams();
p.gravity = rotateGravityRight(p.gravity);
mChild.setLayoutParams(p);
+
+ LayoutParams separatedViewLayoutParams = (LayoutParams) mSeparatedView.getLayoutParams();
+ separatedViewLayoutParams.gravity = rotateGravityRight(separatedViewLayoutParams.gravity);
+ mSeparatedView.setLayoutParams(separatedViewLayoutParams);
+
+ setGravity(p.gravity);
}
private void swapDimens(View v) {
@@ -253,6 +288,12 @@
LayoutParams p = (LayoutParams) mChild.getLayoutParams();
p.gravity = rotateGravityLeft(p.gravity);
mChild.setLayoutParams(p);
+
+ LayoutParams separatedViewLayoutParams = (LayoutParams) mSeparatedView.getLayoutParams();
+ separatedViewLayoutParams.gravity = rotateGravityLeft(separatedViewLayoutParams.gravity);
+ mSeparatedView.setLayoutParams(separatedViewLayoutParams);
+
+ setGravity(p.gravity);
}
private int rotateGravityLeft(int gravity) {
@@ -310,6 +351,15 @@
v.setLayoutParams(params);
}
+ private void swapLeftAndTop(View v) {
+ v.setPadding(v.getPaddingTop(), v.getPaddingLeft(), v.getPaddingBottom(),
+ v.getPaddingRight());
+ MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();
+ params.setMargins(params.topMargin, params.leftMargin, params.bottomMargin,
+ params.rightMargin);
+ v.setLayoutParams(params);
+ }
+
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
@@ -351,6 +401,9 @@
private void updatePosition() {
if (mChild == null) return;
+ // If got separated button, setRotatedBackground to false,
+ // all items won't get white background.
+ mBackground.setRotatedBackground(mHasSeparatedButton);
if (mDivision != null && mDivision.getVisibility() == VISIBLE) {
int index = mRotatedBackground ? 0 : 1;
mDivision.getLocationOnScreen(mTmp2);
@@ -404,6 +457,10 @@
mCollapse = true;
}
+ public void setHasSeparatedButton(boolean hasSeparatedButton) {
+ mHasSeparatedButton = hasSeparatedButton;
+ }
+
public static HardwareUiLayout get(View v) {
if (v instanceof HardwareUiLayout) return (HardwareUiLayout) v;
if (v.getParent() instanceof View) {
diff --git a/packages/SystemUI/src/com/android/systemui/LatencyTester.java b/packages/SystemUI/src/com/android/systemui/LatencyTester.java
index cbb69ee..1e458fa 100644
--- a/packages/SystemUI/src/com/android/systemui/LatencyTester.java
+++ b/packages/SystemUI/src/com/android/systemui/LatencyTester.java
@@ -16,6 +16,7 @@
package com.android.systemui;
+import android.hardware.biometrics.BiometricSourceType;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -26,7 +27,7 @@
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.internal.util.LatencyTracker;
-import com.android.systemui.statusbar.phone.FingerprintUnlockController;
+import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.StatusBar;
/**
@@ -72,10 +73,10 @@
}
private void fakeWakeAndUnlock() {
- FingerprintUnlockController fingerprintUnlockController = getComponent(StatusBar.class)
- .getFingerprintUnlockController();
- fingerprintUnlockController.onFingerprintAcquired();
- fingerprintUnlockController.onFingerprintAuthenticated(
- KeyguardUpdateMonitor.getCurrentUser());
+ BiometricUnlockController biometricUnlockController = getComponent(StatusBar.class)
+ .getBiometricUnlockController();
+ biometricUnlockController.onBiometricAcquired(BiometricSourceType.FINGERPRINT);
+ biometricUnlockController.onBiometricAuthenticated(
+ KeyguardUpdateMonitor.getCurrentUser(), BiometricSourceType.FINGERPRINT);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index 9fc71c8..1e5b77e 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -65,7 +65,7 @@
public static final String TAG_OPS = "OverviewProxyService";
public static final boolean DEBUG_OVERVIEW_PROXY = false;
- private static final long BACKOFF_MILLIS = 5000;
+ private static final long BACKOFF_MILLIS = 1000;
private static final long DEFERRED_CALLBACK_MILLIS = 5000;
private final Context mContext;
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 92674d4..532fa034a 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -28,12 +28,10 @@
import android.app.admin.DevicePolicyManager;
import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.ServiceConnection;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.graphics.Point;
@@ -42,9 +40,7 @@
import android.net.ConnectivityManager;
import android.os.Build;
import android.os.Handler;
-import android.os.IBinder;
import android.os.Message;
-import android.os.Messenger;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
@@ -68,9 +64,9 @@
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityEvent;
-import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.BaseAdapter;
+import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.LinearLayout;
@@ -150,6 +146,7 @@
private boolean mDeviceProvisioned = false;
private ToggleAction.State mAirplaneState = ToggleAction.State.Off;
private boolean mIsWaitingForEcmExit = false;
+ private boolean mHasFasterEmergencyButton;
private boolean mHasTelephony;
private boolean mHasVibrator;
private boolean mHasLogoutButton;
@@ -320,6 +317,7 @@
ArraySet<String> addedKeys = new ArraySet<String>();
mHasLogoutButton = false;
mHasLockdownButton = false;
+ mHasFasterEmergencyButton = false;
for (int i = 0; i < defaultActions.length; i++) {
String actionKey = defaultActions[i];
if (addedKeys.contains(actionKey)) {
@@ -363,6 +361,7 @@
Settings.Global.FASTER_EMERGENCY_PHONE_CALL_ENABLED, 0) != 0
&& !mEmergencyAffordanceManager.needsEmergencyAffordance()) {
mItems.add(new EmergencyAction());
+ mHasFasterEmergencyButton = true;
}
} else if (GLOBAL_ACTION_KEY_SCREENSHOT.equals(actionKey)) {
mItems.add(new ScreenshotAction());
@@ -393,7 +392,8 @@
}
return false;
};
- ActionsDialog dialog = new ActionsDialog(mContext, this, mAdapter, onItemLongClickListener);
+ ActionsDialog dialog = new ActionsDialog(mContext, this, mAdapter, onItemLongClickListener,
+ mHasFasterEmergencyButton);
dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
dialog.setKeyguardShowing(mKeyguardShowing);
@@ -453,7 +453,8 @@
"com.android.phone.EmergencyDialer.DIAL";
private EmergencyAction() {
- super(R.drawable.emergency_icon, R.string.global_action_emergency);
+ super(com.android.systemui.R.drawable.faster_emergency_icon,
+ R.string.global_action_emergency);
}
@Override
@@ -1387,15 +1388,17 @@
private final Context mContext;
private final MyAdapter mAdapter;
private final LinearLayout mListView;
+ private final FrameLayout mSeparatedView;
private final HardwareUiLayout mHardwareLayout;
private final OnClickListener mClickListener;
private final OnItemLongClickListener mLongClickListener;
private final GradientDrawable mGradientDrawable;
private final ColorExtractor mColorExtractor;
private boolean mKeyguardShowing;
+ private boolean mShouldDisplaySeparatedButton;
public ActionsDialog(Context context, OnClickListener clickListener, MyAdapter adapter,
- OnItemLongClickListener longClickListener) {
+ OnItemLongClickListener longClickListener, boolean shouldDisplaySeparatedButton) {
super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions);
mContext = context;
mAdapter = adapter;
@@ -1403,6 +1406,7 @@
mLongClickListener = longClickListener;
mGradientDrawable = new GradientDrawable(mContext);
mColorExtractor = Dependency.get(SysuiColorExtractor.class);
+ mShouldDisplaySeparatedButton = shouldDisplaySeparatedButton;
// Window initialization
Window window = getWindow();
@@ -1426,8 +1430,13 @@
setContentView(com.android.systemui.R.layout.global_actions_wrapped);
mListView = findViewById(android.R.id.list);
+ mSeparatedView = findViewById(com.android.systemui.R.id.separated_button);
+ if (!mShouldDisplaySeparatedButton) {
+ mSeparatedView.setVisibility(View.GONE);
+ }
mHardwareLayout = HardwareUiLayout.get(mListView);
mHardwareLayout.setOutsideTouchListener(view -> dismiss());
+ mHardwareLayout.setHasSeparatedButton(mShouldDisplaySeparatedButton);
setTitle(R.string.global_actions);
mListView.setAccessibilityDelegate(new View.AccessibilityDelegate() {
@Override
@@ -1442,13 +1451,16 @@
private void updateList() {
mListView.removeAllViews();
+ mSeparatedView.removeAllViews();
for (int i = 0; i < mAdapter.getCount(); i++) {
- View v = mAdapter.getView(i, null, mListView);
+ ViewGroup parentView = mShouldDisplaySeparatedButton && i == mAdapter.getCount() - 1
+ ? mSeparatedView : mListView;
+ View v = mAdapter.getView(i, null, parentView);
final int pos = i;
v.setOnClickListener(view -> mClickListener.onClick(this, pos));
v.setOnLongClickListener(view ->
mLongClickListener.onItemLongClick(null, v, pos, 0));
- mListView.addView(v);
+ parentView.addView(v);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index cf6f16a..b9d1021 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -30,6 +30,7 @@
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.StatusBarManager;
+import android.hardware.biometrics.BiometricSourceType;
import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -82,8 +83,8 @@
import com.android.systemui.SystemUIFactory;
import com.android.systemui.UiOffloadThread;
import com.android.systemui.classifier.FalsingManager;
-import com.android.systemui.statusbar.phone.FingerprintUnlockController;
import com.android.systemui.statusbar.phone.NotificationPanelView;
+import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -522,18 +523,18 @@
}
@Override
- public void onFingerprintAuthFailed() {
+ public void onBiometricAuthFailed(BiometricSourceType biometricSourceType) {
final int currentUser = KeyguardUpdateMonitor.getCurrentUser();
if (mLockPatternUtils.isSecure(currentUser)) {
- mLockPatternUtils.getDevicePolicyManager().reportFailedFingerprintAttempt(
+ mLockPatternUtils.getDevicePolicyManager().reportFailedBiometricAttempt(
currentUser);
}
}
@Override
- public void onFingerprintAuthenticated(int userId) {
+ public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType) {
if (mLockPatternUtils.isSecure(userId)) {
- mLockPatternUtils.getDevicePolicyManager().reportSuccessfulFingerprintAttempt(
+ mLockPatternUtils.getDevicePolicyManager().reportSuccessfulBiometricAttempt(
userId);
}
}
@@ -1645,7 +1646,7 @@
}
mUpdateMonitor.clearFailedUnlockAttempts();
- mUpdateMonitor.clearFingerprintRecognized();
+ mUpdateMonitor.clearBiometricRecognized();
if (mGoingToSleep) {
Log.i(TAG, "Device is going to sleep, aborting keyguardDone");
@@ -2051,9 +2052,9 @@
public StatusBarKeyguardViewManager registerStatusBar(StatusBar statusBar,
ViewGroup container, NotificationPanelView panelView,
- FingerprintUnlockController fingerprintUnlockController) {
+ BiometricUnlockController biometricUnlockController) {
mStatusBarKeyguardViewManager.registerStatusBar(statusBar, container, panelView,
- fingerprintUnlockController, mDismissCallbackRegistry);
+ biometricUnlockController, mDismissCallbackRegistry);
return mStatusBarKeyguardViewManager;
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index 615b29f..2dc531a 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -229,7 +229,9 @@
mSettingsButton = findViewById(R.id.settings);
mSettingsButton.setAlpha(0);
mSettingsButton.setOnClickListener((v) -> {
- showSettings();
+ if (v.getAlpha() != 0) {
+ showSettings();
+ }
});
mDismissButton = findViewById(R.id.dismiss);
mDismissButton.setAlpha(0);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 100751c..f13f489 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -189,8 +189,9 @@
// marquee. This will ensure that accessibility doesn't announce the TYPE_VIEW_SELECTED
// event on any of the children.
setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+ int currentItem = isLayoutRtl() ? mPages.size() - 1 - getCurrentItem() : getCurrentItem();
for (int i = 0; i < mPages.size(); i++) {
- mPages.get(i).setSelected(i == getCurrentItem() ? selected : false);
+ mPages.get(i).setSelected(i == currentItem ? selected : false);
}
setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 6dbe119..1c50f79 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -192,29 +192,21 @@
mTileDimensionSize = mContext.getResources().getDimensionPixelSize(
R.dimen.qs_quick_tile_size);
-
- setGravity(Gravity.CENTER);
- setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+ updateLayoutParams();
}
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
+ updateLayoutParams();
+ }
+ private void updateLayoutParams() {
setGravity(Gravity.CENTER);
- LayoutParams staticSpaceLayoutParams = generateSpaceLayoutParams(
- mContext.getResources().getDimensionPixelSize(
- R.dimen.qs_quick_tile_space_width));
-
- // Update space params since they fill any open space in portrait orientation and have
- // a static width in landscape orientation.
- final int childViewCount = getChildCount();
- for (int i = 0; i < childViewCount; i++) {
- View childView = getChildAt(i);
- if (childView instanceof Space) {
- childView.setLayoutParams(staticSpaceLayoutParams);
- }
- }
+ int width = getResources().getDimensionPixelSize(R.dimen.qs_quick_layout_width);
+ LayoutParams lp = new LayoutParams(width, LayoutParams.MATCH_PARENT);
+ lp.gravity = Gravity.CENTER_HORIZONTAL;
+ setLayoutParams(lp);
}
/**
@@ -222,11 +214,9 @@
* then we're going to have the space expand to take up as much space as possible. If the
* width is non-zero, we want the inter-tile spacers to be fixed.
*/
- private LayoutParams generateSpaceLayoutParams(int spaceWidth) {
- LayoutParams lp = new LayoutParams(spaceWidth, mTileDimensionSize);
- if (spaceWidth == 0) {
- lp.weight = 1;
- }
+ private LayoutParams generateSpaceLayoutParams() {
+ LayoutParams lp = new LayoutParams(0, mTileDimensionSize);
+ lp.weight = 1;
lp.gravity = Gravity.CENTER;
return lp;
}
@@ -243,13 +233,7 @@
@Override
public void addTile(TileRecord tile) {
if (getChildCount() != 0) {
- // Add a spacer between tiles. We want static-width spaces if we're in landscape to
- // keep the tiles close. For portrait, we stick with spaces that fill up any
- // available space.
- LayoutParams spaceLayoutParams = generateSpaceLayoutParams(
- mContext.getResources().getDimensionPixelSize(
- R.dimen.qs_quick_tile_space_width));
- addView(new Space(mContext), getChildCount(), spaceLayoutParams);
+ addView(new Space(mContext), getChildCount(), generateSpaceLayoutParams());
}
addView(tile.tileView, getChildCount(), generateTileLayoutParams());
@@ -305,6 +289,10 @@
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ if (hideOverflowingChildren(widthMeasureSpec)) {
+ return; // Rely on visibility change to trigger remeasure.
+ }
+
if (mRecords != null && mRecords.size() > 0) {
View previousView = this;
for (TileRecord record : mRecords) {
@@ -317,5 +305,32 @@
R.id.expand_indicator);
}
}
+
+ /**
+ * Hide child views that would otherwise be clipped.
+ * @return {@code true} if any child visibilities have changed.
+ */
+ private boolean hideOverflowingChildren(int widthMeasureSpec) {
+ if (getChildCount() == 0) {
+ return false;
+ }
+ boolean childVisibilityChanged = false;
+ int widthRemaining = MeasureSpec.getSize(widthMeasureSpec)
+ - getChildAt(0).getMeasuredWidth() - getPaddingStart() - getPaddingEnd();
+ for (int i = 2; i < getChildCount(); i += 2) {
+ View tileChild = getChildAt(i);
+ LayoutParams lp = (LayoutParams) tileChild.getLayoutParams();
+ // All Space views have 0 width; only tiles contribute to the total width.
+ widthRemaining = widthRemaining
+ - tileChild.getMeasuredWidth() - lp.getMarginEnd() - lp.getMarginStart();
+ int newVisibility = widthRemaining < 0 ? View.GONE : View.VISIBLE;
+ if (tileChild.getVisibility() != newVisibility) {
+ tileChild.setVisibility(newVisibility);
+ getChildAt(i - 1).setVisibility(newVisibility); // Hide spacer as well.
+ childVisibilityChanged = true;
+ }
+ }
+ return childVisibilityChanged;
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 8a0d7e3..64ccba8 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -60,6 +60,7 @@
import android.os.UserHandle;
import android.provider.MediaStore;
import android.util.DisplayMetrics;
+import android.util.Log;
import android.util.Slog;
import android.view.Display;
import android.view.LayoutInflater;
@@ -246,7 +247,10 @@
try {
// Create screenshot directory if it doesn't exist
- mScreenshotDir.mkdirs();
+ boolean madeDirs = mScreenshotDir.mkdirs();
+ if (madeDirs == false) {
+ Log.e(TAG, "Couldn't create screenshot directory: " + mScreenshotDir);
+ }
// media provider uses seconds for DATE_MODIFIED and DATE_ADDED, but milliseconds
// for DATE_TAKEN
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 35e1511..294e2f4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -19,6 +19,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.admin.DevicePolicyManager;
+import android.hardware.biometrics.BiometricSourceType;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -26,6 +27,7 @@
import android.content.res.Resources;
import android.content.res.ColorStateList;
import android.graphics.Color;
+import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.BatteryManager;
import android.os.BatteryStats;
@@ -70,8 +72,8 @@
private static final boolean DEBUG_CHARGING_SPEED = false;
private static final int MSG_HIDE_TRANSIENT = 1;
- private static final int MSG_CLEAR_FP_MSG = 2;
- private static final long TRANSIENT_FP_ERROR_TIMEOUT = 1300;
+ private static final int MSG_CLEAR_BIOMETRIC_MSG = 2;
+ private static final long TRANSIENT_BIOMETRIC_ERROR_TIMEOUT = 1300;
private final Context mContext;
private ViewGroup mIndicationArea;
@@ -461,7 +463,7 @@
public void handleMessage(Message msg) {
if (msg.what == MSG_HIDE_TRANSIENT) {
hideTransientIndication();
- } else if (msg.what == MSG_CLEAR_FP_MSG) {
+ } else if (msg.what == MSG_CLEAR_BIOMETRIC_MSG) {
mLockIcon.setTransientFpError(false);
}
}
@@ -526,9 +528,10 @@
}
@Override
- public void onFingerprintHelp(int msgId, String helpString) {
+ public void onBiometricHelp(int msgId, String helpString,
+ BiometricSourceType biometricSourceType) {
KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
- if (!updateMonitor.isUnlockingWithFingerprintAllowed()) {
+ if (!updateMonitor.isUnlockingWithBiometricAllowed()) {
return;
}
ColorStateList errorColorState = Utils.getColorError(mContext);
@@ -538,10 +541,10 @@
} else if (updateMonitor.isScreenOn()) {
mLockIcon.setTransientFpError(true);
showTransientIndication(helpString, errorColorState);
- hideTransientIndicationDelayed(TRANSIENT_FP_ERROR_TIMEOUT);
- mHandler.removeMessages(MSG_CLEAR_FP_MSG);
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CLEAR_FP_MSG),
- TRANSIENT_FP_ERROR_TIMEOUT);
+ hideTransientIndicationDelayed(TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
+ mHandler.removeMessages(MSG_CLEAR_BIOMETRIC_MSG);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CLEAR_BIOMETRIC_MSG),
+ TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
}
// Help messages indicate that there was actually a try since the last error, so those
// are not two successive error messages anymore.
@@ -549,16 +552,15 @@
}
@Override
- public void onFingerprintError(int msgId, String errString) {
+ public void onBiometricError(int msgId, String errString,
+ BiometricSourceType biometricSourceType) {
KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
- if ((!updateMonitor.isUnlockingWithFingerprintAllowed()
- && msgId != FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT)
- || msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
+ if (shouldSuppressBiometricError(msgId, biometricSourceType, updateMonitor)) {
return;
}
ColorStateList errorColorState = Utils.getColorError(mContext);
if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
- // When swiping up right after receiving a fingerprint error, the bouncer calls
+ // When swiping up right after receiving a biometric error, the bouncer calls
// authenticate leading to the same message being shown again on the bouncer.
// We want to avoid this, as it may confuse the user when the message is too
// generic.
@@ -576,6 +578,28 @@
mLastSuccessiveErrorMessage = msgId;
}
+ private boolean shouldSuppressBiometricError(int msgId,
+ BiometricSourceType biometricSourceType, KeyguardUpdateMonitor updateMonitor) {
+ if (biometricSourceType == BiometricSourceType.FINGERPRINT)
+ return shouldSuppressFingerprintError(msgId, updateMonitor);
+ if (biometricSourceType == BiometricSourceType.FACE)
+ return shouldSuppressFaceError(msgId, updateMonitor);
+ return false;
+ }
+
+ private boolean shouldSuppressFingerprintError(int msgId,
+ KeyguardUpdateMonitor updateMonitor) {
+ return ((!updateMonitor.isUnlockingWithBiometricAllowed()
+ && msgId != FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT)
+ || msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED);
+ }
+
+ private boolean shouldSuppressFaceError(int msgId, KeyguardUpdateMonitor updateMonitor) {
+ return ((!updateMonitor.isUnlockingWithBiometricAllowed()
+ && msgId != FaceManager.FACE_ERROR_LOCKOUT_PERMANENT)
+ || msgId == FaceManager.FACE_ERROR_CANCELED);
+ }
+
@Override
public void onTrustAgentErrorMessage(CharSequence message) {
showTransientIndication(message, Utils.getColorError(mContext));
@@ -592,21 +616,22 @@
}
@Override
- public void onFingerprintRunningStateChanged(boolean running) {
+ public void onBiometricRunningStateChanged(boolean running,
+ BiometricSourceType biometricSourceType) {
if (running) {
mMessageToShowOnScreenOn = null;
}
}
@Override
- public void onFingerprintAuthenticated(int userId) {
- super.onFingerprintAuthenticated(userId);
+ public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType) {
+ super.onBiometricAuthenticated(userId, biometricSourceType);
mLastSuccessiveErrorMessage = -1;
}
@Override
- public void onFingerprintAuthFailed() {
- super.onFingerprintAuthFailed();
+ public void onBiometricAuthFailed(BiometricSourceType biometricSourceType) {
+ super.onBiometricAuthFailed(biometricSourceType);
mLastSuccessiveErrorMessage = -1;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index 7e397e8..2f62d59 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -109,16 +109,6 @@
} else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
// Start the overview connection to the launcher service
Dependency.get(OverviewProxyService.class).startConnectionToCurrentUser();
- } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
- try {
- final int lastResumedActivityUserId =
- ActivityTaskManager.getService().getLastResumedActivityUserId();
- if (mUserManager.isManagedProfile(lastResumedActivityUserId)) {
- showForegroundManagedProfileActivityToast();
- }
- } catch (RemoteException e) {
- // Abandon hope activity manager not running.
- }
} else if (NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION.equals(action)) {
final IntentSender intentSender = intent.getParcelableExtra(Intent.EXTRA_INTENT);
final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
@@ -225,7 +215,6 @@
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_USER_ADDED);
- filter.addAction(Intent.ACTION_USER_PRESENT);
filter.addAction(Intent.ACTION_USER_UNLOCKED);
mContext.registerReceiver(mBaseBroadcastReceiver, filter);
@@ -238,19 +227,6 @@
mSettingsObserver.onChange(false); // set up
}
- private void showForegroundManagedProfileActivityToast() {
- Toast toast = Toast.makeText(mContext,
- R.string.managed_profile_foreground_toast,
- Toast.LENGTH_SHORT);
- TextView text = toast.getView().findViewById(android.R.id.message);
- text.setCompoundDrawablesRelativeWithIntrinsicBounds(
- R.drawable.stat_sys_managed_profile_status, 0, 0, 0);
- int paddingPx = mContext.getResources().getDimensionPixelSize(
- R.dimen.managed_profile_toast_padding);
- text.setCompoundDrawablePadding(paddingPx);
- toast.show();
- }
-
public boolean shouldShowLockscreenNotifications() {
return mShowLockscreenNotifications;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java
index d84d3dc..b3ab109 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java
@@ -256,10 +256,14 @@
int count = showInHours ? (minutes / 60) : minutes;
String description = res.getQuantityString(pluralResId, count, count);
String resultText = String.format(res.getString(R.string.snoozed_for_time), description);
+ AccessibilityAction action = new AccessibilityAction(accessibilityActionId, description);
+ final int index = resultText.indexOf(description);
+ if (index == -1) {
+ return new NotificationSnoozeOption(null, minutes, description, resultText, action);
+ }
SpannableString string = new SpannableString(resultText);
string.setSpan(new StyleSpan(Typeface.BOLD),
- resultText.length() - description.length(), resultText.length(), 0 /* flags */);
- AccessibilityAction action = new AccessibilityAction(accessibilityActionId, description);
+ index, index + description.length(), 0 /* flags */);
return new NotificationSnoozeOption(null, minutes, description, string,
action);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUndoLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUndoLayout.java
new file mode 100644
index 0000000..11a1c9b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUndoLayout.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2018 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;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import com.android.systemui.R;
+
+/**
+ * Custom view for the NotificationInfo confirmation views so that the confirmation text can
+ * occupy the full width of the notification and push the undo button down to the next line if
+ * necessary.
+ *
+ * @see NotificationInfo
+ */
+public class NotificationUndoLayout extends FrameLayout {
+ /**
+ * View for the prompt/confirmation text to tell the user the previous action was successful.
+ */
+ private View mConfirmationTextView;
+ /** Undo button (actionable text) view. */
+ private View mUndoView;
+
+ /**
+ * Whether {@link #mConfirmationTextView} is multiline and will require the full width of the
+ * parent (which causes the {@link #mUndoView} to push down).
+ */
+ private boolean mIsMultiline = false;
+ private int mMultilineTopMargin;
+
+ public NotificationUndoLayout(Context context) {
+ this(context, null);
+ }
+
+ public NotificationUndoLayout(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public NotificationUndoLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+
+ mConfirmationTextView = findViewById(R.id.confirmation_text);
+ mUndoView = findViewById(R.id.undo);
+
+ mMultilineTopMargin = getResources().getDimensionPixelOffset(
+ com.android.internal.R.dimen.notification_content_margin_start);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ LayoutParams confirmationLayoutParams =
+ (LayoutParams) mConfirmationTextView.getLayoutParams();
+ LayoutParams undoLayoutParams =(LayoutParams) mUndoView.getLayoutParams();
+
+ int measuredWidth = getMeasuredWidth();
+ // Ignore the left margin on the undo button - no need for additional extra space between
+ // the text and the button.
+ int requiredWidth = mConfirmationTextView.getMeasuredWidth()
+ + confirmationLayoutParams.rightMargin
+ + confirmationLayoutParams.leftMargin
+ + mUndoView.getMeasuredWidth()
+ + undoLayoutParams.rightMargin;
+ // If the measured width isn't enough to accommodate both the undo button and the text in
+ // the same line, we'll need to adjust the view to be multi-line. Otherwise, we're done.
+ if (requiredWidth > measuredWidth) {
+ mIsMultiline = true;
+
+ // Update height requirement to the text height and the button's height (along with
+ // additional spacing for the top of the text).
+ int updatedHeight = mMultilineTopMargin
+ + mConfirmationTextView.getMeasuredHeight()
+ + mUndoView.getMeasuredHeight()
+ + undoLayoutParams.topMargin
+ + undoLayoutParams.bottomMargin;
+
+ setMeasuredDimension(measuredWidth, updatedHeight);
+ } else {
+ mIsMultiline = false;
+ }
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ // If the text view and undo view don't fit on the same line, we'll need to manually lay
+ // out the content.
+ if (mIsMultiline) {
+ // Re-align parent right/bottom values. Left and top are considered to be 0.
+ int parentBottom = getMeasuredHeight();
+ int parentRight = getMeasuredWidth();
+
+ LayoutParams confirmationLayoutParams =
+ (LayoutParams) mConfirmationTextView.getLayoutParams();
+ LayoutParams undoLayoutParams = (LayoutParams) mUndoView.getLayoutParams();
+
+ // The confirmation text occupies the full width as computed earlier. Both side margins
+ // are equivalent, so we only need to grab the left one here.
+ mConfirmationTextView.layout(
+ confirmationLayoutParams.leftMargin,
+ mMultilineTopMargin,
+ confirmationLayoutParams.leftMargin + mConfirmationTextView.getMeasuredWidth(),
+ mMultilineTopMargin + mConfirmationTextView.getMeasuredHeight());
+
+ // The undo button is aligned bottom|end with the parent in the case of multiline text.
+ int undoViewLeft = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL
+ ? undoLayoutParams.rightMargin
+ : parentRight - mUndoView.getMeasuredWidth() - undoLayoutParams.rightMargin;
+ mUndoView.layout(
+ undoViewLeft,
+ parentBottom - mUndoView.getMeasuredHeight() - undoLayoutParams.bottomMargin,
+ undoViewLeft + mUndoView.getMeasuredWidth(),
+ parentBottom - undoLayoutParams.bottomMargin);
+ } else {
+ super.onLayout(changed, left, top, right, bottom);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
index ccbf483..3c52e8c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
@@ -126,20 +126,21 @@
}
public void applyMobileState(MobileIconState state) {
+ boolean requestLayout = false;
if (state == null) {
+ requestLayout = getVisibility() != View.GONE;
setVisibility(View.GONE);
mState = null;
- return;
- }
-
- if (mState == null) {
+ } else if (mState == null) {
+ requestLayout = true;
mState = state.copy();
initViewState();
- return;
+ } else if (!mState.equals(state)) {
+ requestLayout = updateState(state.copy());
}
- if (!mState.equals(state)) {
- updateState(state.copy());
+ if (requestLayout) {
+ requestLayout();
}
}
@@ -162,20 +163,24 @@
mMobileRoaming.setVisibility(mState.roaming ? View.VISIBLE : View.GONE);
mMobileRoamingSpace.setVisibility(mState.roaming ? View.VISIBLE : View.GONE);
mIn.setVisibility(mState.activityIn ? View.VISIBLE : View.GONE);
- mOut.setVisibility(mState.activityIn ? View.VISIBLE : View.GONE);
+ mOut.setVisibility(mState.activityOut ? View.VISIBLE : View.GONE);
mInoutContainer.setVisibility((mState.activityIn || mState.activityOut)
? View.VISIBLE : View.GONE);
}
- private void updateState(MobileIconState state) {
+ private boolean updateState(MobileIconState state) {
+ boolean needsLayout = false;
+
setContentDescription(state.contentDescription);
if (mState.visible != state.visible) {
mMobileGroup.setVisibility(state.visible ? View.VISIBLE : View.GONE);
+ needsLayout = true;
}
if (mState.strengthId != state.strengthId) {
mMobileDrawable.setLevel(state.strengthId);
}
if (mState.typeId != state.typeId) {
+ needsLayout |= state.typeId == 0 || mState.typeId == 0;
if (state.typeId != 0) {
mMobileType.setContentDescription(state.typeContentDescription);
mMobileType.setImageResource(state.typeId);
@@ -188,11 +193,16 @@
mMobileRoaming.setVisibility(state.roaming ? View.VISIBLE : View.GONE);
mMobileRoamingSpace.setVisibility(state.roaming ? View.VISIBLE : View.GONE);
mIn.setVisibility(state.activityIn ? View.VISIBLE : View.GONE);
- mOut.setVisibility(state.activityIn ? View.VISIBLE : View.GONE);
+ mOut.setVisibility(state.activityOut ? View.VISIBLE : View.GONE);
mInoutContainer.setVisibility((state.activityIn || state.activityOut)
? View.VISIBLE : View.GONE);
+ needsLayout |= state.roaming != mState.roaming
+ || state.activityIn != mState.activityIn
+ || state.activityOut != mState.activityOut;
+
mState = state;
+ return needsLayout;
}
@Override
@@ -243,7 +253,7 @@
}
@Override
- public void setVisibleState(int state) {
+ public void setVisibleState(int state, boolean animate) {
if (state == mVisibleState) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
index 0ed6b77..f3fc99e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
@@ -124,7 +124,7 @@
}
@Override
- public void setVisibleState(int state) {
+ public void setVisibleState(int state, boolean animate) {
if (state == mVisibleState) {
return;
}
@@ -191,23 +191,26 @@
}
public void applyWifiState(WifiIconState state) {
+ boolean requestLayout = false;
+
if (state == null) {
+ requestLayout = getVisibility() != View.GONE;
setVisibility(View.GONE);
mState = null;
- return;
- }
-
- if (mState == null) {
+ } else if (mState == null) {
+ requestLayout = true;
mState = state.copy();
initViewState();
+ } else if (!mState.equals(state)) {
+ requestLayout = updateState(state.copy());
}
- if (!mState.equals(state)) {
- updateState(state.copy());
+ if (requestLayout) {
+ requestLayout();
}
}
- private void updateState(WifiIconState state) {
+ private boolean updateState(WifiIconState state) {
setContentDescription(state.contentDescription);
if (mState.resId != state.resId && state.resId >= 0) {
NeutralGoodDrawable drawable = NeutralGoodDrawable
@@ -222,11 +225,17 @@
(state.activityIn || state.activityOut) ? View.VISIBLE : View.GONE);
mAirplaneSpacer.setVisibility(state.airplaneSpacerVisible ? View.VISIBLE : View.GONE);
mSignalSpacer.setVisibility(state.signalSpacerVisible ? View.VISIBLE : View.GONE);
+
+ boolean needsLayout = state.activityIn != mState.activityIn
+ ||state.activityOut != mState.activityOut;
+
if (mState.visible != state.visible) {
+ needsLayout |= true;
setVisibility(state.visible ? View.VISIBLE : View.GONE);
}
mState = state;
+ return needsLayout;
}
private void initViewState() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusIconDisplayable.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusIconDisplayable.java
index b831b86..beb90b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusIconDisplayable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusIconDisplayable.java
@@ -22,7 +22,10 @@
String getSlot();
void setStaticDrawableColor(int color);
void setDecorColor(int color);
- void setVisibleState(int state);
+ default void setVisibleState(int state) {
+ setVisibleState(state, false);
+ }
+ void setVisibleState(int state, boolean animate);
int getVisibleState();
boolean isIconVisible();
default boolean isIconBlocked() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
similarity index 77%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index f0b1a82..0b6fd13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import android.hardware.biometrics.BiometricSourceType;
import android.content.Context;
import android.os.Handler;
import android.os.PowerManager;
@@ -35,14 +36,14 @@
import java.io.PrintWriter;
/**
- * Controller which coordinates all the fingerprint unlocking actions with the UI.
+ * Controller which coordinates all the biometric unlocking actions with the UI.
*/
-public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback {
+public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
- private static final String TAG = "FingerprintController";
- private static final boolean DEBUG_FP_WAKELOCK = KeyguardConstants.DEBUG_FP_WAKELOCK;
- private static final long FINGERPRINT_WAKELOCK_TIMEOUT_MS = 15 * 1000;
- private static final String FINGERPRINT_WAKE_LOCK_NAME = "wake-and-unlock wakelock";
+ private static final String TAG = "BiometricUnlockController";
+ private static final boolean DEBUG_BIO_WAKELOCK = KeyguardConstants.DEBUG_BIOMETRIC_WAKELOCK;
+ private static final long BIOMETRIC_WAKELOCK_TIMEOUT_MS = 15 * 1000;
+ private static final String BIOMETRIC_WAKE_LOCK_NAME = "wake-and-unlock wakelock";
/**
* Mode in which we don't need to wake up the device when we get a fingerprint.
@@ -90,9 +91,9 @@
public static final int MODE_WAKE_AND_UNLOCK_FROM_DREAM = 7;
/**
- * How much faster we collapse the lockscreen when authenticating with fingerprint.
+ * How much faster we collapse the lockscreen when authenticating with biometric.
*/
- private static final float FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR = 1.1f;
+ private static final float BIOMETRIC_COLLAPSE_SPEEDUP_FACTOR = 1.1f;
private PowerManager mPowerManager;
private Handler mHandler = new Handler();
@@ -108,15 +109,16 @@
private final UnlockMethodCache mUnlockMethodCache;
private final Context mContext;
private int mPendingAuthenticatedUserId = -1;
+ private BiometricSourceType mPendingAuthenticatedBioSourceType = null;
private boolean mPendingShowBouncer;
private boolean mHasScreenTurnedOnSinceAuthenticating;
- public FingerprintUnlockController(Context context,
- DozeScrimController dozeScrimController,
- KeyguardViewMediator keyguardViewMediator,
- ScrimController scrimController,
- StatusBar statusBar,
- UnlockMethodCache unlockMethodCache) {
+ public BiometricUnlockController(Context context,
+ DozeScrimController dozeScrimController,
+ KeyguardViewMediator keyguardViewMediator,
+ ScrimController scrimController,
+ StatusBar statusBar,
+ UnlockMethodCache unlockMethodCache) {
mContext = context;
mPowerManager = context.getSystemService(PowerManager.class);
mUpdateMonitor = KeyguardUpdateMonitor.getInstance(context);
@@ -136,21 +138,21 @@
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
}
- private final Runnable mReleaseFingerprintWakeLockRunnable = new Runnable() {
+ private final Runnable mReleaseBiometricWakeLockRunnable = new Runnable() {
@Override
public void run() {
- if (DEBUG_FP_WAKELOCK) {
- Log.i(TAG, "fp wakelock: TIMEOUT!!");
+ if (DEBUG_BIO_WAKELOCK) {
+ Log.i(TAG, "biometric wakelock: TIMEOUT!!");
}
- releaseFingerprintWakeLock();
+ releaseBiometricWakeLock();
}
};
- private void releaseFingerprintWakeLock() {
+ private void releaseBiometricWakeLock() {
if (mWakeLock != null) {
- mHandler.removeCallbacks(mReleaseFingerprintWakeLockRunnable);
- if (DEBUG_FP_WAKELOCK) {
- Log.i(TAG, "releasing fp wakelock");
+ mHandler.removeCallbacks(mReleaseBiometricWakeLockRunnable);
+ if (DEBUG_BIO_WAKELOCK) {
+ Log.i(TAG, "releasing biometric wakelock");
}
mWakeLock.release();
mWakeLock = null;
@@ -158,24 +160,27 @@
}
@Override
- public void onFingerprintAcquired() {
- Trace.beginSection("FingerprintUnlockController#onFingerprintAcquired");
- releaseFingerprintWakeLock();
+ public void onBiometricAcquired(BiometricSourceType biometricSourceType) {
+ Trace.beginSection("BiometricUnlockController#onBiometricAcquired");
+ releaseBiometricWakeLock();
if (!mUpdateMonitor.isDeviceInteractive()) {
if (LatencyTracker.isEnabled(mContext)) {
- LatencyTracker.getInstance(mContext).onActionStart(
- LatencyTracker.ACTION_FINGERPRINT_WAKE_AND_UNLOCK);
+ int action = LatencyTracker.ACTION_FINGERPRINT_WAKE_AND_UNLOCK;
+ if (biometricSourceType == BiometricSourceType.FACE) {
+ action = LatencyTracker.ACTION_FACE_WAKE_AND_UNLOCK;
+ }
+ LatencyTracker.getInstance(mContext).onActionStart(action);
}
mWakeLock = mPowerManager.newWakeLock(
- PowerManager.PARTIAL_WAKE_LOCK, FINGERPRINT_WAKE_LOCK_NAME);
+ PowerManager.PARTIAL_WAKE_LOCK, BIOMETRIC_WAKE_LOCK_NAME);
Trace.beginSection("acquiring wake-and-unlock");
mWakeLock.acquire();
Trace.endSection();
- if (DEBUG_FP_WAKELOCK) {
- Log.i(TAG, "fingerprint acquired, grabbing fp wakelock");
+ if (DEBUG_BIO_WAKELOCK) {
+ Log.i(TAG, "biometric acquired, grabbing biometric wakelock");
}
- mHandler.postDelayed(mReleaseFingerprintWakeLockRunnable,
- FINGERPRINT_WAKELOCK_TIMEOUT_MS);
+ mHandler.postDelayed(mReleaseBiometricWakeLockRunnable,
+ BIOMETRIC_WAKELOCK_TIMEOUT_MS);
}
Trace.endSection();
}
@@ -187,10 +192,11 @@
}
@Override
- public void onFingerprintAuthenticated(int userId) {
- Trace.beginSection("FingerprintUnlockController#onFingerprintAuthenticated");
+ public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType) {
+ Trace.beginSection("BiometricUnlockController#onBiometricAuthenticated");
if (mUpdateMonitor.isGoingToSleep()) {
mPendingAuthenticatedUserId = userId;
+ mPendingAuthenticatedBioSourceType = biometricSourceType;
Trace.endSection();
return;
}
@@ -211,13 +217,13 @@
mStatusBarWindowManager.setForceDozeBrightness(true);
}
if (!wasDeviceInteractive) {
- if (DEBUG_FP_WAKELOCK) {
- Log.i(TAG, "fp wakelock: Authenticated, waking up...");
+ if (DEBUG_BIO_WAKELOCK) {
+ Log.i(TAG, "bio wakelock: Authenticated, waking up...");
}
- mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.policy:FINGERPRINT");
+ mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.policy:BIOMETRIC");
}
Trace.beginSection("release wake-and-unlock");
- releaseFingerprintWakeLock();
+ releaseBiometricWakeLock();
Trace.endSection();
switch (mMode) {
case MODE_DISMISS_BOUNCER:
@@ -261,7 +267,7 @@
case MODE_NONE:
break;
}
- mStatusBar.notifyFpAuthModeChanged();
+ mStatusBar.notifyBiometricAuthModeChanged();
Trace.endSection();
}
@@ -270,7 +276,7 @@
mStatusBarKeyguardViewManager.showBouncer(false);
}
mStatusBarKeyguardViewManager.animateCollapsePanels(
- FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR);
+ BIOMETRIC_COLLAPSE_SPEEDUP_FACTOR);
mPendingShowBouncer = false;
}
@@ -278,28 +284,31 @@
public void onStartedGoingToSleep(int why) {
resetMode();
mPendingAuthenticatedUserId = -1;
+ mPendingAuthenticatedBioSourceType = null;
}
@Override
public void onFinishedGoingToSleep(int why) {
- Trace.beginSection("FingerprintUnlockController#onFinishedGoingToSleep");
+ Trace.beginSection("BiometricUnlockController#onFinishedGoingToSleep");
if (mPendingAuthenticatedUserId != -1) {
// Post this to make sure it's executed after the device is fully locked.
mHandler.post(new Runnable() {
@Override
public void run() {
- onFingerprintAuthenticated(mPendingAuthenticatedUserId);
+ onBiometricAuthenticated(mPendingAuthenticatedUserId,
+ mPendingAuthenticatedBioSourceType);
}
});
}
mPendingAuthenticatedUserId = -1;
+ mPendingAuthenticatedBioSourceType = null;
Trace.endSection();
}
public boolean hasPendingAuthentication() {
return mPendingAuthenticatedUserId != -1
- && mUpdateMonitor.isUnlockingWithFingerprintAllowed()
+ && mUpdateMonitor.isUnlockingWithBiometricAllowed()
&& mPendingAuthenticatedUserId == KeyguardUpdateMonitor.getCurrentUser();
}
@@ -308,7 +317,7 @@
}
private int calculateMode() {
- boolean unlockingAllowed = mUpdateMonitor.isUnlockingWithFingerprintAllowed();
+ boolean unlockingAllowed = mUpdateMonitor.isUnlockingWithBiometricAllowed();
boolean deviceDreaming = mUpdateMonitor.isDreaming();
if (!mUpdateMonitor.isDeviceInteractive()) {
@@ -338,17 +347,18 @@
}
@Override
- public void onFingerprintAuthFailed() {
+ public void onBiometricAuthFailed(BiometricSourceType biometricSourceType) {
cleanup();
}
@Override
- public void onFingerprintError(int msgId, String errString) {
+ public void onBiometricError(int msgId, String errString,
+ BiometricSourceType biometricSourceType) {
cleanup();
}
private void cleanup() {
- releaseFingerprintWakeLock();
+ releaseBiometricWakeLock();
}
public void startKeyguardFadingAway() {
@@ -372,7 +382,7 @@
if (mStatusBar.getNavigationBarView() != null) {
mStatusBar.getNavigationBarView().setWakeAndUnlocking(false);
}
- mStatusBar.notifyFpAuthModeChanged();
+ mStatusBar.notifyBiometricAuthModeChanged();
}
private final WakefulnessLifecycle.Observer mWakefulnessObserver =
@@ -380,7 +390,7 @@
@Override
public void onFinishedWakingUp() {
if (mPendingShowBouncer) {
- FingerprintUnlockController.this.showBouncer();
+ BiometricUnlockController.this.showBouncer();
}
}
};
@@ -398,7 +408,7 @@
}
public void dump(PrintWriter pw) {
- pw.println(" FingerprintUnlockController:");
+ pw.println(" BiometricUnlockController:");
pw.print(" mMode="); pw.println(mMode);
pw.print(" mWakeLock="); pw.println(mWakeLock);
}
@@ -415,7 +425,7 @@
/**
* Successful authentication with fingerprint when the screen was either on or off.
*/
- public boolean isFingerprintUnlock() {
+ public boolean isBiometricUnlock() {
return isWakeAndUnlock() || mMode == MODE_UNLOCK;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index e0e991b..e052e53 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -203,7 +203,7 @@
v.set(icon);
v.setStaticDrawableColor(mColor);
v.setDecorColor(mColor);
- addView(v, 0, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize));
+ addView(v, 0, createLayoutParams());
}
public void addDemoWifiView(WifiIconState state) {
@@ -223,7 +223,7 @@
mWifiView = view;
mWifiView.applyWifiState(state);
mWifiView.setStaticDrawableColor(mColor);
- addView(view, viewIndex);
+ addView(view, viewIndex, createLayoutParams());
}
public void updateWifiState(WifiIconState state) {
@@ -244,7 +244,7 @@
// mobile always goes at the end
mMobileViews.add(view);
- addView(view, getChildCount());
+ addView(view, getChildCount(), createLayoutParams());
}
public void updateMobileState(MobileIconState state) {
@@ -290,6 +290,10 @@
return null;
}
+ private LayoutParams createLayoutParams() {
+ return new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize);
+ }
+
@Override
public void onDarkChanged(Rect area, float darkIntensity, int tint) {
setColor(DarkIconDispatcher.getTint(area, mStatusIcons, tint));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
index 46d9827..e2f3319 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
@@ -367,10 +367,10 @@
}
}
- private void startFinishingCircleAnimation(float velocity, Runnable mAnimationEndRunnable,
+ private void startFinishingCircleAnimation(float velocity, Runnable animationEndRunnable,
boolean right) {
KeyguardAffordanceView targetView = right ? mRightIcon : mLeftIcon;
- targetView.finishAnimation(velocity, mAnimationEndRunnable);
+ targetView.finishAnimation(velocity, animationEndRunnable);
}
private void setTranslation(float translation, boolean isReset, boolean animateReset) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 3b12051..25b97bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -28,6 +28,7 @@
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.admin.DevicePolicyManager;
+import android.hardware.biometrics.BiometricSourceType;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -774,7 +775,8 @@
}
@Override
- public void onFingerprintRunningStateChanged(boolean running) {
+ public void onBiometricRunningStateChanged(boolean running,
+ BiometricSourceType biometricSourceType) {
mLockIcon.update();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index e47dcea..20ea27a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -70,6 +70,7 @@
private static final int LAYOUT_CUTOUT = 1;
private static final int LAYOUT_NO_CUTOUT = 2;
+ private boolean mShowPercentAvailable;
private boolean mBatteryCharging;
private boolean mKeyguardUserSwitcherShowing;
private boolean mBatteryListening;
@@ -168,6 +169,8 @@
R.dimen.system_icons_super_container_avatarless_margin_end);
mCutoutSideNudge = getResources().getDimensionPixelSize(
R.dimen.display_cutout_margin_consumption);
+ mShowPercentAvailable = getContext().getResources().getBoolean(
+ com.android.internal.R.bool.config_battery_percentage_setting_available);
}
private void updateVisibilities() {
@@ -189,7 +192,7 @@
mMultiUserSwitch.setVisibility(View.GONE);
}
}
- mBatteryView.setForceShowPercent(mBatteryCharging);
+ mBatteryView.setForceShowPercent(mBatteryCharging && mShowPercentAvailable);
}
private void updateSystemIconsLayoutParams() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
index 8b8cbfe..8cace72 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
@@ -44,7 +44,7 @@
private final DarkIconDispatcher mStatusBarIconController;
private final BatteryController mBatteryController;
- private FingerprintUnlockController mFingerprintUnlockController;
+ private BiometricUnlockController mBiometricUnlockController;
private LightBarTransitionsController mNavigationBarController;
private int mSystemUiVisibility;
@@ -89,9 +89,9 @@
updateNavigation();
}
- public void setFingerprintUnlockController(
- FingerprintUnlockController fingerprintUnlockController) {
- mFingerprintUnlockController = fingerprintUnlockController;
+ public void setBiometricUnlockController(
+ BiometricUnlockController biometricUnlockController) {
+ mBiometricUnlockController = biometricUnlockController;
}
public void onSystemUiVisibilityChanged(int fullscreenStackVis, int dockedStackVis,
@@ -178,12 +178,12 @@
}
private boolean animateChange() {
- if (mFingerprintUnlockController == null) {
+ if (mBiometricUnlockController == null) {
return false;
}
- int unlockMode = mFingerprintUnlockController.getMode();
- return unlockMode != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
- && unlockMode != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK;
+ int unlockMode = mBiometricUnlockController.getMode();
+ return unlockMode != BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
+ && unlockMode != BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
}
private void updateStatus(Rect fullscreenStackBounds, Rect dockedStackBounds) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 4b66ee5a..8928530 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -306,7 +306,7 @@
private int getState() {
KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
boolean fingerprintRunning = updateMonitor.isFingerprintDetectionRunning();
- boolean unlockingAllowed = updateMonitor.isUnlockingWithFingerprintAllowed();
+ boolean unlockingAllowed = updateMonitor.isUnlockingWithBiometricAllowed();
if (mTransientFpError) {
return STATE_FINGERPRINT_ERROR;
} else if (mUnlockMethodCache.canSkipBouncer()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index dce7537..ed1ae10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -75,7 +75,6 @@
private int mTouchDownY;
private boolean mDownOnRecents;
private VelocityTracker mVelocityTracker;
- private boolean mIsInScreenPinning;
private boolean mNotificationsVisibleOnDown;
private boolean mDockWindowEnabled;
@@ -110,7 +109,6 @@
public boolean onInterceptTouchEvent(MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
- mIsInScreenPinning = mNavigationBarView.inScreenPinning();
mNotificationsVisibleOnDown = !mStatusBar.isPresenterFullyCollapsed();
}
if (!canHandleGestures()) {
@@ -277,8 +275,7 @@
}
private boolean canHandleGestures() {
- return !mIsInScreenPinning && !mStatusBar.isKeyguardShowing()
- && !mNotificationsVisibleOnDown;
+ return !mStatusBar.isKeyguardShowing() && !mNotificationsVisibleOnDown;
}
private int calculateDragMode() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 8b9e12c..6077e79 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -18,6 +18,7 @@
import static android.view.MotionEvent.ACTION_DOWN;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_BACK;
+import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_DEAD_ZONE;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_HOME;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE;
@@ -161,6 +162,13 @@
private int mRotateBtnStyle = R.style.RotateButtonCCWStart90;
+ /**
+ * Helper that is responsible for showing the right toast when a disallowed activity operation
+ * occurred. In pinned mode, we show instructions on how to break out of this mode, whilst in
+ * fully locked mode we only show that unlocking is blocked.
+ */
+ private ScreenPinningNotify mScreenPinningNotify;
+
private class NavTransitionListener implements TransitionListener {
private boolean mBackTransitioning;
private boolean mHomeAppearing;
@@ -286,6 +294,7 @@
mConfiguration.updateFrom(context.getResources().getConfiguration());
reloadNavIcons();
+ mScreenPinningNotify = new ScreenPinningNotify(mContext);
mBarTransitions = new NavigationBarTransitions(this);
mButtonDispatchers.put(R.id.back, new ButtonDispatcher(R.id.back));
@@ -328,15 +337,15 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
- if (shouldDeadZoneConsumeTouchEvents(event)) {
- return true;
- }
+ final boolean deadZoneConsumed = shouldDeadZoneConsumeTouchEvents(event);
switch (event.getActionMasked()) {
case ACTION_DOWN:
int x = (int) event.getX();
int y = (int) event.getY();
mDownHitTarget = HIT_TARGET_NONE;
- if (getBackButton().isVisible() && mBackButtonBounds.contains(x, y)) {
+ if (deadZoneConsumed) {
+ mDownHitTarget = HIT_TARGET_DEAD_ZONE;
+ } else if (getBackButton().isVisible() && mBackButtonBounds.contains(x, y)) {
mDownHitTarget = HIT_TARGET_BACK;
} else if (getHomeButton().isVisible() && mHomeButtonBounds.contains(x, y)) {
mDownHitTarget = HIT_TARGET_HOME;
@@ -353,9 +362,7 @@
@Override
public boolean onTouchEvent(MotionEvent event) {
- if (shouldDeadZoneConsumeTouchEvents(event)) {
- return true;
- }
+ shouldDeadZoneConsumeTouchEvents(event);
if (mGestureHelper.onTouchEvent(event)) {
return true;
}
@@ -764,7 +771,7 @@
showSwipeUpUI ? mQuickStepAccessibilityDelegate : null);
}
- private void updateSlippery() {
+ public void updateSlippery() {
setSlippery(!isQuickStepSwipeUpEnabled() || mPanelView.isFullyExpanded());
}
@@ -983,6 +990,18 @@
mBarTransitions.reapplyDarkIntensity();
}
+ public void showPinningEnterExitToast(boolean entering) {
+ if (entering) {
+ mScreenPinningNotify.showPinningStartToast();
+ } else {
+ mScreenPinningNotify.showPinningExitToast();
+ }
+ }
+
+ public void showPinningEscapeToast() {
+ mScreenPinningNotify.showEscapeToast(isRecentsButtonVisible());
+ }
+
public boolean isVertical() {
return mVertical;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 165b9b4..492efa2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -223,6 +223,7 @@
private boolean mClosingWithAlphaFadeOut;
private boolean mHeadsUpAnimatingAway;
private boolean mLaunchingAffordance;
+ private boolean mAffordanceHasPreview;
private FalsingManager mFalsingManager;
private String mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE;
@@ -2491,7 +2492,7 @@
}
protected void setVerticalPanelTranslation(float translation) {
- mNotificationStackScroller.setTranslationX(translation);
+ mNotificationStackScroller.setVerticalPanelTranslation(translation);
mQsFrame.setTranslationX(translation);
int size = mVerticalTranslationListener.size();
for (int i = 0; i < size; i++) {
@@ -2571,6 +2572,7 @@
} else {
animate = false;
}
+ mAffordanceHasPreview = mKeyguardBottomArea.getRightPreview() != null;
mAffordanceHelper.launchAffordance(animate, getLayoutDirection() == LAYOUT_DIRECTION_RTL);
}
@@ -2616,6 +2618,13 @@
}
/**
+ * Return true when a bottom affordance is launching an occluded activity with a splash screen.
+ */
+ public boolean isLaunchingAffordanceWithPreview() {
+ return mLaunchingAffordance && mAffordanceHasPreview;
+ }
+
+ /**
* Whether the camera application can be launched for the camera launch gesture.
*
* @param keyguardIsShowing whether keyguard is being shown
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index 18bc4e5..5d23494 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -33,6 +33,7 @@
private static final String STATE = "state";
private boolean mBouncerShowing;
private boolean mExpanded;
+ protected float mPanelFraction;
public static final void LOG(String fmt, Object... args) {
if (!DEBUG) return;
@@ -99,6 +100,14 @@
if (mPanel != null) mPanel.setImportantForAccessibility(important);
}
+ public float getExpansionFraction() {
+ return mPanelFraction;
+ }
+
+ public boolean isExpanded() {
+ return mExpanded;
+ }
+
private void updateVisibility() {
mPanel.setVisibility(mExpanded || mBouncerShowing ? VISIBLE : INVISIBLE);
}
@@ -153,6 +162,7 @@
if (SPEW) LOG("panelExpansionChanged: start state=%d", mState);
PanelView pv = mPanel;
mExpanded = expanded;
+ mPanelFraction = frac;
updateVisibility();
// adjust any other panels that may be partially visible
if (expanded) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 075883a..59863ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -59,7 +59,6 @@
private final PhoneStatusBarTransitions mBarTransitions;
private ScrimController mScrimController;
private float mMinFraction;
- private float mPanelFraction;
private Runnable mHideExpandedRunnable = new Runnable() {
@Override
public void run() {
@@ -269,7 +268,6 @@
@Override
public void panelExpansionChanged(float frac, boolean expanded) {
super.panelExpansionChanged(frac, expanded);
- mPanelFraction = frac;
updateScrimFraction();
if ((frac == 0 || frac == 1) && mBar.getNavigationBarView() != null) {
mBar.getNavigationBarView().onPanelExpandedChange(expanded);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
index ea1b980..9a37cbc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -22,20 +22,21 @@
import static com.android.systemui.Interpolators.ALPHA_OUT;
import static com.android.systemui.OverviewProxyService.DEBUG_OVERVIEW_PROXY;
import static com.android.systemui.OverviewProxyService.TAG_OPS;
+import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_DEAD_ZONE;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
-import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
-import android.graphics.Color;
import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.RadialGradient;
import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
+import android.graphics.Shader;
import android.os.Handler;
import android.os.RemoteException;
import android.util.FloatProperty;
@@ -54,7 +55,6 @@
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.utilities.Utilities;
import com.android.systemui.shared.system.NavigationBarCompat;
-import com.android.internal.graphics.ColorUtils;
/**
* Class to detect gestures on the navigation bar and implement quick scrub.
@@ -65,6 +65,7 @@
private static final int ANIM_IN_DURATION_MS = 150;
private static final int ANIM_OUT_DURATION_MS = 134;
private static final float TRACK_SCALE = 0.95f;
+ private static final float GRADIENT_WIDTH = .75f;
private NavigationBarView mNavigationBarView;
@@ -78,23 +79,23 @@
private boolean mIsRTL;
private float mTrackAlpha;
private float mTrackScale = TRACK_SCALE;
- private int mLightTrackColor;
- private int mDarkTrackColor;
private float mDarkIntensity;
+ private RadialGradient mHighlight;
+ private float mHighlightCenter;
private AnimatorSet mTrackAnimator;
private ButtonDispatcher mHitTarget;
private View mCurrentNavigationBarView;
+ private boolean mIsInScreenPinning;
private final Handler mHandler = new Handler();
private final Rect mTrackRect = new Rect();
- private final Drawable mTrackDrawable;
private final OverviewProxyService mOverviewEventSender;
private final int mTrackThickness;
private final int mTrackEndPadding;
private final Context mContext;
private final Matrix mTransformGlobalMatrix = new Matrix();
private final Matrix mTransformLocalMatrix = new Matrix();
- private final ArgbEvaluator mTrackColorEvaluator = new ArgbEvaluator();
+ private final Paint mTrackPaint = new Paint();
private final FloatProperty<QuickStepController> mTrackAlphaProperty =
new FloatProperty<QuickStepController>("TrackAlpha") {
@@ -155,7 +156,8 @@
mOverviewEventSender = Dependency.get(OverviewProxyService.class);
mTrackThickness = res.getDimensionPixelSize(R.dimen.nav_quick_scrub_track_thickness);
mTrackEndPadding = res.getDimensionPixelSize(R.dimen.nav_quick_scrub_track_edge_padding);
- mTrackDrawable = context.getDrawable(R.drawable.qs_scrubber_track).mutate();
+ mTrackPaint.setAntiAlias(true);
+ mTrackPaint.setDither(true);
}
public void setComponents(NavigationBarView navigationBarView) {
@@ -184,6 +186,8 @@
}
private boolean handleTouchEvent(MotionEvent event) {
+ final boolean deadZoneConsumed =
+ mNavigationBarView.getDownHitTarget() == HIT_TARGET_DEAD_ZONE;
if (mOverviewEventSender.getProxy() == null || (!mNavigationBarView.isQuickScrubEnabled()
&& !mNavigationBarView.isQuickStepSwipeUpEnabled())) {
return false;
@@ -195,6 +199,7 @@
case MotionEvent.ACTION_DOWN: {
int x = (int) event.getX();
int y = (int) event.getY();
+ mIsInScreenPinning = mNavigationBarView.inScreenPinning();
// End any existing quickscrub animations before starting the new transition
if (mTrackAnimator != null) {
@@ -287,6 +292,8 @@
} catch (RemoteException e) {
Log.e(TAG, "Failed to send progress of quick scrub.", e);
}
+ mHighlightCenter = x;
+ mNavigationBarView.invalidate();
}
break;
}
@@ -298,11 +305,11 @@
// Proxy motion events to launcher if not handled by quick scrub
// Proxy motion events up/cancel that would be sent after long press on any nav button
- if (!mQuickScrubActive && (mAllowGestureDetection || action == MotionEvent.ACTION_CANCEL
- || action == MotionEvent.ACTION_UP)) {
+ if (!mQuickScrubActive && !mIsInScreenPinning && (mAllowGestureDetection
+ || action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP)) {
proxyMotionEvents(event);
}
- return mQuickScrubActive || mQuickStepStarted;
+ return mQuickScrubActive || mQuickStepStarted || deadZoneConsumed;
}
@Override
@@ -310,18 +317,18 @@
if (!mNavigationBarView.isQuickScrubEnabled()) {
return;
}
- int color = (int) mTrackColorEvaluator.evaluate(mDarkIntensity, mLightTrackColor,
- mDarkTrackColor);
- int colorAlpha = ColorUtils.setAlphaComponent(color,
- (int) (Color.alpha(color) * mTrackAlpha));
- mTrackDrawable.setTint(colorAlpha);
+ mTrackPaint.setAlpha(Math.round(255f * mTrackAlpha));
// Scale the track, but apply the inverse scale from the nav bar
+ final float radius = mTrackRect.height() / 2;
canvas.save();
+ float translate = Utilities.clamp(mHighlightCenter, mTrackRect.left, mTrackRect.right);
+ canvas.translate(translate, 0);
canvas.scale(mTrackScale / mNavigationBarView.getScaleX(),
1f / mNavigationBarView.getScaleY(),
mTrackRect.centerX(), mTrackRect.centerY());
- mTrackDrawable.draw(canvas);
+ canvas.drawRoundRect(mTrackRect.left - translate, mTrackRect.top,
+ mTrackRect.right - translate, mTrackRect.bottom, radius, radius, mTrackPaint);
canvas.restore();
}
@@ -346,12 +353,20 @@
x2 = x1 + width - 2 * mTrackEndPadding;
}
mTrackRect.set(x1, y1, x2, y2);
- mTrackDrawable.setBounds(mTrackRect);
+ updateHighlight();
}
@Override
public void onDarkIntensityChange(float intensity) {
+ final float oldIntensity = mDarkIntensity;
mDarkIntensity = intensity;
+
+ // When in quick scrub, invalidate gradient if changing intensity from black to white and
+ // vice-versa
+ if (mNavigationBarView.isQuickScrubEnabled()
+ && Math.round(intensity) != Math.round(oldIntensity)) {
+ updateHighlight();
+ }
mNavigationBarView.invalidate();
}
@@ -382,6 +397,12 @@
}
private void startQuickStep(MotionEvent event) {
+ if (mIsInScreenPinning) {
+ mNavigationBarView.showPinningEscapeToast();
+ mAllowGestureDetection = false;
+ return;
+ }
+
mQuickStepStarted = true;
event.transform(mTransformGlobalMatrix);
try {
@@ -407,11 +428,15 @@
}
private void startQuickScrub() {
- if (!mQuickScrubActive) {
- mQuickScrubActive = true;
- mLightTrackColor = mContext.getColor(R.color.quick_step_track_background_light);
- mDarkTrackColor = mContext.getColor(R.color.quick_step_track_background_dark);
+ if (mIsInScreenPinning) {
+ mNavigationBarView.showPinningEscapeToast();
+ mAllowGestureDetection = false;
+ return;
+ }
+ if (!mQuickScrubActive) {
+ updateHighlight();
+ mQuickScrubActive = true;
ObjectAnimator trackAnimator = ObjectAnimator.ofPropertyValuesHolder(this,
PropertyValuesHolder.ofFloat(mTrackAlphaProperty, 1f),
PropertyValuesHolder.ofFloat(mTrackScaleProperty, 1f));
@@ -424,6 +449,9 @@
mTrackAnimator.playTogether(trackAnimator, navBarAnimator);
mTrackAnimator.start();
+ // Disable slippery for quick scrub to not cancel outside the nav bar
+ mNavigationBarView.updateSlippery();
+
try {
mOverviewEventSender.getProxy().onQuickScrubStart();
if (DEBUG_OVERVIEW_PROXY) {
@@ -483,6 +511,22 @@
mQuickScrubActive = false;
mAllowGestureDetection = false;
mCurrentNavigationBarView = null;
+ updateHighlight();
+ }
+
+ private void updateHighlight() {
+ int colorBase, colorGrad;
+ if (mDarkIntensity > 0.5f) {
+ colorBase = mContext.getColor(R.color.quick_step_track_background_background_dark);
+ colorGrad = mContext.getColor(R.color.quick_step_track_background_foreground_dark);
+ } else {
+ colorBase = mContext.getColor(R.color.quick_step_track_background_background_light);
+ colorGrad = mContext.getColor(R.color.quick_step_track_background_foreground_light);
+ }
+ mHighlight = new RadialGradient(0, mTrackRect.height() / 2,
+ mTrackRect.width() * GRADIENT_WIDTH, colorGrad, colorBase,
+ Shader.TileMode.CLAMP);
+ mTrackPaint.setShader(mHighlight);
}
private boolean proxyMotionEvents(MotionEvent event) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index fe141661..f573642 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -889,9 +889,14 @@
}
public void setHasBackdrop(boolean hasBackdrop) {
- ScrimState[] states = ScrimState.values();
- for (int i = 0; i < states.length; i++) {
- states[i].setHasBackdrop(hasBackdrop);
+ for (ScrimState state : ScrimState.values()) {
+ state.setHasBackdrop(hasBackdrop);
+ }
+ }
+
+ public void setLaunchingAffordanceWithPreview(boolean launchingAffordanceWithPreview) {
+ for (ScrimState state : ScrimState.values()) {
+ state.setLaunchingAffordanceWithPreview(launchingAffordanceWithPreview);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index ec6ada4..cdbad59 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -144,6 +144,7 @@
mCurrentBehindAlpha = 0;
mCurrentInFrontAlpha = 0;
mAnimationDuration = StatusBar.FADE_KEYGUARD_DURATION;
+ mAnimateChange = !mLaunchingAffordanceWithPreview;
if (previousState == ScrimState.AOD || previousState == ScrimState.PULSING) {
// Fade from black to transparent when coming directly from AOD
@@ -177,6 +178,7 @@
boolean mWallpaperSupportsAmbientMode;
int mIndex;
boolean mHasBackdrop;
+ boolean mLaunchingAffordanceWithPreview;
ScrimState(int index) {
mIndex = index;
@@ -249,6 +251,10 @@
mWallpaperSupportsAmbientMode = wallpaperSupportsAmbientMode;
}
+ public void setLaunchingAffordanceWithPreview(boolean launchingAffordanceWithPreview) {
+ mLaunchingAffordanceWithPreview = launchingAffordanceWithPreview;
+ }
+
public boolean isLowPowerState() {
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 0a1ac1b..ae1da56 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -55,6 +55,7 @@
import android.app.PendingIntent;
import android.app.StatusBarManager;
import android.app.TaskStackBuilder;
+import android.app.UiModeManager;
import android.app.WallpaperColors;
import android.app.WallpaperInfo;
import android.app.WallpaperManager;
@@ -329,6 +330,12 @@
/** If true, the lockscreen will show a distinct wallpaper */
private static final boolean ENABLE_LOCKSCREEN_WALLPAPER = true;
+ /** Whether to force dark theme if Configuration.UI_MODE_NIGHT_YES. */
+ private static final boolean DARK_THEME_IN_NIGHT_MODE = true;
+
+ /** Whether to switch the device into night mode in battery saver. */
+ private static final boolean NIGHT_MODE_IN_BATTERY_SAVER = true;
+
/**
* Never let the alpha become zero for surfaces that draw with SRC - otherwise the RenderNode
* won't draw anything and uninitialized memory will show through
@@ -361,7 +368,7 @@
private VolumeComponent mVolumeComponent;
private BrightnessMirrorController mBrightnessMirrorController;
private boolean mBrightnessMirrorVisible;
- protected FingerprintUnlockController mFingerprintUnlockController;
+ protected BiometricUnlockController mBiometricUnlockController;
private LightBarController mLightBarController;
protected LockscreenWallpaper mLockscreenWallpaper;
@@ -423,13 +430,6 @@
protected KeyguardViewMediator mKeyguardViewMediator;
private ZenModeController mZenController;
- /**
- * Helper that is responsible for showing the right toast when a disallowed activity operation
- * occurred. In pinned mode, we show instructions on how to break out of this mode, whilst in
- * fully locked mode we only show that unlocking is blocked.
- */
- private ScreenPinningNotify mScreenPinningNotify;
-
// for disabling the status bar
private int mDisabled1 = 0;
private int mDisabled2 = 0;
@@ -512,7 +512,7 @@
protected NotificationLockscreenUserManager mLockscreenUserManager;
protected NotificationRemoteInputManager mRemoteInputManager;
- private BroadcastReceiver mWallpaperChangedReceiver = new BroadcastReceiver() {
+ private final BroadcastReceiver mWallpaperChangedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
WallpaperManager wallpaperManager = context.getSystemService(WallpaperManager.class);
@@ -520,7 +520,7 @@
Log.w(TAG, "WallpaperManager not available");
return;
}
- WallpaperInfo info = wallpaperManager.getWallpaperInfo();
+ WallpaperInfo info = wallpaperManager.getWallpaperInfo(UserHandle.USER_CURRENT);
final boolean supportsAmbientMode = info != null &&
info.getSupportsAmbientMode();
@@ -714,7 +714,8 @@
// Make sure we always have the most current wallpaper info.
IntentFilter wallpaperChangedFilter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
- mContext.registerReceiver(mWallpaperChangedReceiver, wallpaperChangedFilter);
+ mContext.registerReceiverAsUser(mWallpaperChangedReceiver, UserHandle.ALL,
+ wallpaperChangedFilter, null /* broadcastPermission */, null /* scheduler */);
mWallpaperChangedReceiver.onReceive(mContext, null);
mLockscreenUserManager.setUpWithPresenter(this, mEntryManager);
@@ -839,6 +840,7 @@
CollapsedStatusBarFragment statusBarFragment =
(CollapsedStatusBarFragment) fragment;
statusBarFragment.initNotificationIconArea(mNotificationIconAreaController);
+ PhoneStatusBarView oldStatusBarView = mStatusBarView;
mStatusBarView = (PhoneStatusBarView) fragment.getView();
mStatusBarView.setBar(this);
mStatusBarView.setPanel(mNotificationPanel);
@@ -855,6 +857,11 @@
mNotificationPanel.notifyBarPanelExpansionChanged();
}
mStatusBarView.setBouncerShowing(mBouncerShowing);
+ if (oldStatusBarView != null) {
+ float fraction = oldStatusBarView.getExpansionFraction();
+ boolean expanded = oldStatusBarView.isExpanded();
+ mStatusBarView.panelExpansionChanged(fraction, expanded);
+ }
HeadsUpAppearanceController oldController = mHeadsUpAppearanceController;
if (mHeadsUpAppearanceController != null) {
@@ -864,6 +871,7 @@
mHeadsUpAppearanceController = new HeadsUpAppearanceController(
mNotificationIconAreaController, mHeadsUpManager, mStatusBarWindow);
mHeadsUpAppearanceController.readFrom(oldController);
+ mStatusBarWindow.setStatusBarView(mStatusBarView);
setAreThereNotifications();
checkBarModes();
}).getFragmentManager()
@@ -901,7 +909,6 @@
} catch (RemoteException ex) {
// no window manager? good luck with that
}
- mScreenPinningNotify = new ScreenPinningNotify(mContext);
mStackScroller.setLongPressListener(mEntryManager.getNotificationLongClicker());
mStackScroller.setStatusBar(this);
mStackScroller.setGroupManager(mGroupManager);
@@ -941,6 +948,10 @@
if (mDozeServiceHost != null) {
mDozeServiceHost.firePowerSaveChanged(isPowerSave);
}
+ if (NIGHT_MODE_IN_BATTERY_SAVER) {
+ mContext.getSystemService(UiModeManager.class).setNightMode(
+ isPowerSave ? UiModeManager.MODE_NIGHT_YES : UiModeManager.MODE_NIGHT_NO);
+ }
}
@Override
@@ -1329,18 +1340,18 @@
protected void startKeyguard() {
Trace.beginSection("StatusBar#startKeyguard");
KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
- mFingerprintUnlockController = new FingerprintUnlockController(mContext,
+ mBiometricUnlockController = new BiometricUnlockController(mContext,
mDozeScrimController, keyguardViewMediator,
mScrimController, this, UnlockMethodCache.getInstance(mContext));
mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
- getBouncerContainer(), mNotificationPanel, mFingerprintUnlockController);
+ getBouncerContainer(), mNotificationPanel, mBiometricUnlockController);
mKeyguardIndicationController
.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
- mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
+ mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mRemoteInputManager.getController().addCallback(mStatusBarKeyguardViewManager);
mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
- mLightBarController.setFingerprintUnlockController(mFingerprintUnlockController);
+ mLightBarController.setBiometricUnlockController(mBiometricUnlockController);
Dependency.get(KeyguardDismissUtil.class).setDismissHandler(this::executeWhenUnlocked);
Trace.endSection();
}
@@ -1624,8 +1635,8 @@
return; // called too early
}
- boolean wakeAndUnlock = mFingerprintUnlockController != null
- && mFingerprintUnlockController.isWakeAndUnlock();
+ boolean wakeAndUnlock = mBiometricUnlockController != null
+ && mBiometricUnlockController.isWakeAndUnlock();
if (mLaunchTransitionFadingAway || wakeAndUnlock) {
mBackdrop.setVisibility(View.INVISIBLE);
Trace.endSection();
@@ -1677,8 +1688,8 @@
if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK)
&& (mState != StatusBarState.SHADE || allowWhenShade)
- && mFingerprintUnlockController.getMode()
- != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
+ && mBiometricUnlockController.getMode()
+ != BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
&& !hideBecauseOccluded) {
// time to show some art!
if (mBackdrop.getVisibility() != View.VISIBLE) {
@@ -1743,8 +1754,8 @@
Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork");
}
boolean cannotAnimateDoze = mDozing && !ScrimState.AOD.getAnimateChange();
- if (mFingerprintUnlockController.getMode()
- == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
+ if (mBiometricUnlockController.getMode()
+ == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
|| hideBecauseOccluded || cannotAnimateDoze) {
// We are unlocking directly - no animation!
@@ -2240,17 +2251,16 @@
@Override
public void showPinningEnterExitToast(boolean entering) {
- if (entering) {
- mScreenPinningNotify.showPinningStartToast();
- } else {
- mScreenPinningNotify.showPinningExitToast();
+ if (getNavigationBarView() != null) {
+ getNavigationBarView().showPinningEnterExitToast(entering);
}
}
@Override
public void showPinningEscapeToast() {
- mScreenPinningNotify.showEscapeToast(getNavigationBarView() == null
- || getNavigationBarView().isRecentsButtonVisible());
+ if (getNavigationBarView() != null) {
+ getNavigationBarView().showPinningEscapeToast();
+ }
}
boolean panelsEnabled() {
@@ -2477,8 +2487,8 @@
return mGestureRec;
}
- public FingerprintUnlockController getFingerprintUnlockController() {
- return mFingerprintUnlockController;
+ public BiometricUnlockController getBiometricUnlockController() {
+ return mBiometricUnlockController;
}
@Override // CommandQueue
@@ -2812,8 +2822,8 @@
DozeLog.dump(pw);
- if (mFingerprintUnlockController != null) {
- mFingerprintUnlockController.dump(pw);
+ if (mBiometricUnlockController != null) {
+ mBiometricUnlockController.dump(pw);
}
if (mKeyguardIndicationController != null) {
@@ -3121,10 +3131,10 @@
&& mUnlockMethodCache.canSkipBouncer()
&& !mLeaveOpenOnKeyguardHide
&& isPulsing()) {
- // Reuse the fingerprint wake-and-unlock transition if we dismiss keyguard from a pulse.
- // TODO: Factor this transition out of FingerprintUnlockController.
- mFingerprintUnlockController.startWakeAndUnlock(
- FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING);
+ // Reuse the biometric wake-and-unlock transition if we dismiss keyguard from a pulse.
+ // TODO: Factor this transition out of BiometricUnlockController.
+ mBiometricUnlockController.startWakeAndUnlock(
+ BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING);
}
if (mStatusBarKeyguardViewManager.isShowing()) {
mStatusBarKeyguardViewManager.dismissWithAction(action, cancelAction,
@@ -3139,6 +3149,7 @@
public void onConfigChanged(Configuration newConfig) {
updateResources();
updateDisplaySize(); // populates mDisplayMetrics
+ updateTheme();
if (DEBUG) {
Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration());
@@ -3164,6 +3175,7 @@
updateNotificationViews();
mMediaManager.clearCurrentMediaNotification();
setLockscreenUser(newUserId);
+ mWallpaperChangedReceiver.onReceive(mContext, null);
}
@Override
@@ -3528,8 +3540,8 @@
}
private boolean updateIsKeyguard() {
- boolean wakeAndUnlocking = mFingerprintUnlockController.getMode()
- == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK;
+ boolean wakeAndUnlocking = mBiometricUnlockController.getMode()
+ == BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
// For dozing, keyguard needs to be shown whenever the device is non-interactive. Otherwise
// there's no surface we can show to the user. Note that the device goes fully interactive
@@ -3576,8 +3588,8 @@
}
private void updatePanelExpansionForKeyguard() {
- if (mState == StatusBarState.KEYGUARD && mFingerprintUnlockController.getMode()
- != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK) {
+ if (mState == StatusBarState.KEYGUARD && mBiometricUnlockController.getMode()
+ != BiometricUnlockController.MODE_WAKE_AND_UNLOCK) {
instantExpandNotificationsPanel();
} else if (mState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
instantCollapseNotificationPanel();
@@ -3878,8 +3890,13 @@
// The system wallpaper defines if QS should be light or dark.
WallpaperColors systemColors = mColorExtractor
.getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
- final boolean useDarkTheme = systemColors != null
+ final boolean wallpaperWantsDarkTheme = systemColors != null
&& (systemColors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0;
+ final Configuration config = mContext.getResources().getConfiguration();
+ final boolean nightModeWantsDarkTheme = DARK_THEME_IN_NIGHT_MODE
+ && (config.uiMode & Configuration.UI_MODE_NIGHT_MASK)
+ == Configuration.UI_MODE_NIGHT_YES;
+ final boolean useDarkTheme = wallpaperWantsDarkTheme || nightModeWantsDarkTheme;
if (isUsingDarkTheme() != useDarkTheme) {
mUiOffloadThread.submit(() -> {
try {
@@ -4705,7 +4722,7 @@
|| mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_ON;
}
- public void notifyFpAuthModeChanged() {
+ public void notifyBiometricAuthModeChanged() {
updateDozing();
updateScrimController();
}
@@ -4714,13 +4731,13 @@
Trace.beginSection("StatusBar#updateDozing");
// When in wake-and-unlock while pulsing, keep dozing state until fully unlocked.
boolean dozing = mDozingRequested && mState == StatusBarState.KEYGUARD
- || mFingerprintUnlockController.getMode()
- == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
+ || mBiometricUnlockController.getMode()
+ == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
final boolean alwaysOn = DozeParameters.getInstance(mContext).getAlwaysOn();
// When in wake-and-unlock we may not have received a change to mState
// but we still should not be dozing, manually set to false.
- if (mFingerprintUnlockController.getMode() ==
- FingerprintUnlockController.MODE_WAKE_AND_UNLOCK) {
+ if (mBiometricUnlockController.getMode() ==
+ mBiometricUnlockController.MODE_WAKE_AND_UNLOCK) {
dozing = false;
}
if (mDozing != dozing) {
@@ -4744,22 +4761,25 @@
// We don't want to end up in KEYGUARD state when we're unlocking with
// fingerprint from doze. We should cross fade directly from black.
- boolean wakeAndUnlocking = mFingerprintUnlockController.isWakeAndUnlock();
+ boolean wakeAndUnlocking = mBiometricUnlockController.isWakeAndUnlock();
// Do not animate the scrim expansion when triggered by the fingerprint sensor.
mScrimController.setExpansionAffectsAlpha(
- !mFingerprintUnlockController.isFingerprintUnlock());
+ !mBiometricUnlockController.isBiometricUnlock());
+
+ boolean launchingAffordanceWithPreview =
+ mNotificationPanel.isLaunchingAffordanceWithPreview();
+ mScrimController.setLaunchingAffordanceWithPreview(launchingAffordanceWithPreview);
if (mBouncerShowing) {
// Bouncer needs the front scrim when it's on top of an activity,
// tapping on a notification, editing QS or being dismissed by
// FLAG_DISMISS_KEYGUARD_ACTIVITY.
- ScrimState state = mIsOccluded || mStatusBarKeyguardViewManager.bouncerNeedsScrimming()
- || mStatusBarKeyguardViewManager.willDismissWithAction()
- || mStatusBarKeyguardViewManager.isFullscreenBouncer() ?
- ScrimState.BOUNCER_SCRIMMED : ScrimState.BOUNCER;
+ ScrimState state = mStatusBarKeyguardViewManager.bouncerNeedsScrimming()
+ ? ScrimState.BOUNCER_SCRIMMED : ScrimState.BOUNCER;
mScrimController.transitionTo(state);
- } else if (mLaunchCameraOnScreenTurningOn || isInLaunchTransition()) {
+ } else if (isInLaunchTransition() || mLaunchCameraOnScreenTurningOn
+ || launchingAffordanceWithPreview) {
mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
} else if (mBrightnessMirrorVisible) {
mScrimController.transitionTo(ScrimState.BRIGHTNESS_MIRROR);
@@ -4892,8 +4912,8 @@
@Override
public boolean isPulsingBlocked() {
- return mFingerprintUnlockController.getMode()
- == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK;
+ return mBiometricUnlockController.getMode()
+ == BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
}
@Override
@@ -4904,7 +4924,7 @@
@Override
public boolean isBlockingDoze() {
- if (mFingerprintUnlockController.hasPendingAuthentication()) {
+ if (mBiometricUnlockController.hasPendingAuthentication()) {
Log.i(TAG, "Blocking AOD because fingerprint has authenticated");
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 914bba2..378910a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.phone;
import static com.android.keyguard.KeyguardHostView.OnDismissAction;
-import static com.android.systemui.statusbar.phone.FingerprintUnlockController.MODE_WAKE_AND_UNLOCK;
-import static com.android.systemui.statusbar.phone.FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
+import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
+import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
import android.content.ComponentCallbacks2;
import android.content.Context;
@@ -91,7 +91,7 @@
protected ViewMediatorCallback mViewMediatorCallback;
protected StatusBar mStatusBar;
private NotificationPanelView mNotificationPanelView;
- private FingerprintUnlockController mFingerprintUnlockController;
+ private BiometricUnlockController mBiometricUnlockController;
private ViewGroup mContainer;
@@ -108,7 +108,7 @@
private boolean mLastBouncerDismissible;
protected boolean mLastRemoteInputActive;
private boolean mLastDozing;
- private int mLastFpMode;
+ private int mLastBiometricMode;
private boolean mGoingToSleepVisibleNotOccluded;
private OnDismissAction mAfterKeyguardGoneAction;
@@ -142,11 +142,11 @@
public void registerStatusBar(StatusBar statusBar,
ViewGroup container,
NotificationPanelView notificationPanelView,
- FingerprintUnlockController fingerprintUnlockController,
+ BiometricUnlockController biometricUnlockController,
DismissCallbackRegistry dismissCallbackRegistry) {
mStatusBar = statusBar;
mContainer = container;
- mFingerprintUnlockController = fingerprintUnlockController;
+ mBiometricUnlockController = biometricUnlockController;
mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext,
mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry,
mExpansionCallback);
@@ -170,8 +170,7 @@
// • Full-screen user switcher is displayed.
if (mNotificationPanelView.isUnlockHintRunning()) {
mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
- } else if (mOccluded || mBouncer.willDismissWithAction() || mBouncer.isShowingScrimmed()
- || mStatusBar.isFullScreenUserSwitcherState()) {
+ } else if (bouncerNeedsScrimming()) {
mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
} else if (mShowing && !mDozing) {
if (!isWakeAndUnlocking() && !mStatusBar.isInLaunchTransition()) {
@@ -260,7 +259,7 @@
}
private boolean isWakeAndUnlocking() {
- int mode = mFingerprintUnlockController.getMode();
+ int mode = mBiometricUnlockController.getMode();
return mode == MODE_WAKE_AND_UNLOCK || mode == MODE_WAKE_AND_UNLOCK_PULSING;
}
@@ -443,13 +442,13 @@
} else {
executeAfterKeyguardGoneAction();
boolean wakeUnlockPulsing =
- mFingerprintUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING;
+ mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING;
if (wakeUnlockPulsing) {
delay = 0;
fadeoutDuration = 240;
}
mStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
- mFingerprintUnlockController.startKeyguardFadingAway();
+ mBiometricUnlockController.startKeyguardFadingAway();
hideBouncer(true /* destroyView */);
if (wakeUnlockPulsing) {
mStatusBar.fadeKeyguardWhilePulsing();
@@ -461,7 +460,7 @@
wakeAndUnlockDejank();
} else {
mStatusBar.finishKeyguardFadingAway();
- mFingerprintUnlockController.finishKeyguardFadingAway();
+ mBiometricUnlockController.finishKeyguardFadingAway();
}
}
updateStates();
@@ -485,14 +484,14 @@
mContainer.postDelayed(() -> mStatusBarWindowManager.setKeyguardFadingAway(false),
100);
mStatusBar.finishKeyguardFadingAway();
- mFingerprintUnlockController.finishKeyguardFadingAway();
+ mBiometricUnlockController.finishKeyguardFadingAway();
WindowManagerGlobal.getInstance().trimMemory(
ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
}
private void wakeAndUnlockDejank() {
- if (mFingerprintUnlockController.getMode() == MODE_WAKE_AND_UNLOCK
+ if (mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK
&& LatencyTracker.isEnabled(mContext)) {
DejankUtils.postAfterTraversal(() ->
LatencyTracker.getInstance(mContext).onActionEnd(
@@ -619,7 +618,7 @@
mLastBouncerDismissible = bouncerDismissible;
mLastRemoteInputActive = remoteInputActive;
mLastDozing = mDozing;
- mLastFpMode = mFingerprintUnlockController.getMode();
+ mLastBiometricMode = mBiometricUnlockController.getMode();
mStatusBar.onKeyguardViewManagerStatesUpdated();
}
@@ -644,9 +643,9 @@
* @return Whether the navigation bar should be made visible based on the current state.
*/
protected boolean isNavBarVisible() {
- int fpMode = mFingerprintUnlockController.getMode();
+ int biometricMode = mBiometricUnlockController.getMode();
boolean keyguardShowing = mShowing && !mOccluded;
- boolean hideWhileDozing = mDozing && fpMode != MODE_WAKE_AND_UNLOCK_PULSING;
+ boolean hideWhileDozing = mDozing && biometricMode != MODE_WAKE_AND_UNLOCK_PULSING;
return (!keyguardShowing && !hideWhileDozing || mBouncer.isShowing()
|| mRemoteInputActive);
}
@@ -656,7 +655,7 @@
*/
protected boolean getLastNavBarVisible() {
boolean keyguardShowing = mLastShowing && !mLastOccluded;
- boolean hideWhileDozing = mLastDozing && mLastFpMode != MODE_WAKE_AND_UNLOCK_PULSING;
+ boolean hideWhileDozing = mLastDozing && mLastBiometricMode != MODE_WAKE_AND_UNLOCK_PULSING;
return (!keyguardShowing && !hideWhileDozing || mLastBouncerShowing
|| mLastRemoteInputActive);
}
@@ -731,12 +730,9 @@
}
}
- public boolean willDismissWithAction() {
- return mBouncer.willDismissWithAction();
- }
-
public boolean bouncerNeedsScrimming() {
- return mBouncer.isShowingScrimmed();
+ return mOccluded || mBouncer.willDismissWithAction() || mBouncer.needsFullscreenBouncer()
+ || mStatusBar.isFullScreenUserSwitcherState() || mBouncer.isShowingScrimmed();
}
public void dump(PrintWriter pw) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 237ca25..fa763c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -76,6 +76,7 @@
private NotificationStackScrollLayout mStackScrollLayout;
private NotificationPanelView mNotificationPanel;
private View mBrightnessMirror;
+ private PhoneStatusBarView mStatusBarView;
private int mRightInset = 0;
private int mLeftInset = 0;
@@ -204,6 +205,10 @@
}
}
+ public void setStatusBarView(PhoneStatusBarView statusBarView) {
+ mStatusBarView = statusBarView;
+ }
+
public void setService(StatusBar service) {
mService = service;
setDragDownHelper(new DragDownHelper(getContext(), this, mStackScrollLayout, mService));
@@ -326,7 +331,7 @@
expandingBelowNotch = true;
}
if (expandingBelowNotch) {
- return mNotificationPanel.dispatchTouchEvent(ev);
+ return mStatusBarView.dispatchTouchEvent(ev);
}
return super.dispatchTouchEvent(ev);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
index 0811179..f8f6981 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
@@ -301,11 +301,7 @@
vs.initFrom(child);
vs.alpha = 1.0f;
- if (child instanceof StatusIconDisplayable) {
- vs.hidden = !((StatusIconDisplayable)child).isIconVisible();
- } else {
- vs.hidden = false;
- }
+ vs.hidden = false;
}
}
@@ -333,22 +329,33 @@
}
StatusIconDisplayable icon = (StatusIconDisplayable) view;
AnimationProperties animationProperties = null;
- boolean animate = false;
+ boolean animateVisibility = true;
- if (justAdded) {
+ // Figure out which properties of the state transition (if any) we need to animate
+ if (justAdded
+ || icon.getVisibleState() == STATE_HIDDEN && visibleState == STATE_ICON) {
+ // Icon is appearing, fade it in by putting it where it will be and animating alpha
super.applyToView(view);
+ view.setAlpha(0.f);
+ icon.setVisibleState(STATE_HIDDEN);
animationProperties = ADD_ICON_PROPERTIES;
- animate = true;
} else if (icon.getVisibleState() != visibleState) {
- animationProperties = DOT_ANIMATION_PROPERTIES;
- animate = true;
+ if (icon.getVisibleState() == STATE_ICON && visibleState == STATE_HIDDEN) {
+ // Disappearing, don't do anything fancy
+ animateVisibility = false;
+ } else {
+ // all other transitions (to/from dot, etc)
+ animationProperties = ANIMATE_ALL_PROPERTIES;
+ }
+ } else if (visibleState != STATE_HIDDEN && xTranslation != view.getTranslationX()) {
+ // Visibility isn't changing, just animate position
+ animationProperties = X_ANIMATION_PROPERTIES;
}
- if (animate) {
+ icon.setVisibleState(visibleState, animateVisibility);
+ if (animationProperties != null) {
animateTo(view, animationProperties);
- icon.setVisibleState(visibleState);
} else {
- icon.setVisibleState(visibleState);
super.applyToView(view);
}
@@ -365,7 +372,7 @@
}
}.setDuration(200).setDelay(50);
- private static final AnimationProperties DOT_ANIMATION_PROPERTIES = new AnimationProperties() {
+ private static final AnimationProperties X_ANIMATION_PROPERTIES = new AnimationProperties() {
private AnimationFilter mAnimationFilter = new AnimationFilter().animateX();
@Override
@@ -373,4 +380,14 @@
return mAnimationFilter;
}
}.setDuration(200);
+
+ private static final AnimationProperties ANIMATE_ALL_PROPERTIES = new AnimationProperties() {
+ private AnimationFilter mAnimationFilter = new AnimationFilter().animateX().animateY()
+ .animateAlpha().animateScale();
+
+ @Override
+ public AnimationFilter getAnimationFilter() {
+ return mAnimationFilter;
+ }
+ }.setDuration(200);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
index f9c2130..e5925f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import android.hardware.biometrics.BiometricSourceType;
import android.content.Context;
import android.os.Trace;
@@ -135,9 +136,9 @@
}
@Override
- public void onFingerprintAuthenticated(int userId) {
- Trace.beginSection("KeyguardUpdateMonitorCallback#onFingerprintAuthenticated");
- if (!mKeyguardUpdateMonitor.isUnlockingWithFingerprintAllowed()) {
+ public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType) {
+ Trace.beginSection("KeyguardUpdateMonitorCallback#onBiometricAuthenticated");
+ if (!mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed()) {
Trace.endSection();
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index d6d0673..3c16329 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -134,6 +134,10 @@
@Override
public void setHotspotEnabled(boolean enabled) {
+ if (mWaitingForCallback) {
+ if (DEBUG) Log.d(TAG, "Ignoring setHotspotEnabled; waiting for callback.");
+ return;
+ }
if (enabled) {
OnStartTetheringCallback callback = new OnStartTetheringCallback();
mWaitingForCallback = true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index 59b376f..ef51bf0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -32,32 +32,33 @@
import android.os.UserManager;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
-import android.service.notification.Condition;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeConfig.ZenRule;
+import android.text.format.DateFormat;
import android.util.Log;
-import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Dumpable;
import com.android.systemui.qs.GlobalSetting;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.util.Utils;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.LinkedHashMap;
import java.util.Objects;
/** Platform implementation of the zen mode controller. **/
-public class ZenModeControllerImpl extends CurrentUserTracker implements ZenModeController {
+public class ZenModeControllerImpl extends CurrentUserTracker
+ implements ZenModeController, Dumpable {
private static final String TAG = "ZenModeController";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
+ private final ArrayList<Callback> mCallbacks = new ArrayList<>();
private final Context mContext;
private final GlobalSetting mModeSetting;
private final GlobalSetting mConfigSetting;
private final NotificationManager mNoMan;
- private final LinkedHashMap<Uri, Condition> mConditions = new LinkedHashMap<Uri, Condition>();
private final AlarmManager mAlarmManager;
private final SetupObserver mSetupObserver;
private final UserManager mUserManager;
@@ -66,6 +67,7 @@
private boolean mRegistered;
private ZenModeConfig mConfig;
private int mZenMode;
+ private long mZenUpdateTime;
public ZenModeControllerImpl(Context context, Handler handler) {
super(context);
@@ -84,7 +86,6 @@
}
};
mNoMan = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
- mConfig = mNoMan.getZenModeConfig();
mModeSetting.setListening(true);
updateZenMode(mModeSetting.getValue());
mConfigSetting.setListening(true);
@@ -209,6 +210,7 @@
@VisibleForTesting
protected void updateZenMode(int mode) {
mZenMode = mode;
+ mZenUpdateTime = System.currentTimeMillis();
}
@VisibleForTesting
@@ -217,6 +219,7 @@
if (Objects.equals(config, mConfig)) return;
final ZenRule oldRule = mConfig != null ? mConfig.manualRule : null;
mConfig = config;
+ mZenUpdateTime = System.currentTimeMillis();
fireConfigChanged(config);
final ZenRule newRule = config != null ? config.manualRule : null;
if (Objects.equals(oldRule, newRule)) return;
@@ -235,6 +238,14 @@
}
};
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("ZenModeControllerImpl:");
+ pw.println(" mZenMode=" + mZenMode);
+ pw.println(" mConfig=" + mConfig);
+ pw.println(" mZenUpdateTime=" + DateFormat.format("MM-dd HH:mm:ss", mZenUpdateTime));
+ }
+
private final class SetupObserver extends ContentObserver {
private final ContentResolver mResolver;
@@ -261,6 +272,7 @@
Global.getUriFor(Global.DEVICE_PROVISIONED), false, this);
mResolver.registerContentObserver(
Secure.getUriFor(Secure.USER_SETUP_COMPLETE), false, this, mUserId);
+ mRegistered = true;
fireZenAvailableChanged(isZenAvailable());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index 2dd3d4e..ffd5494 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -49,10 +49,14 @@
*/
public class NotificationChildrenContainer extends ViewGroup {
- private static final int NUMBER_OF_CHILDREN_WHEN_COLLAPSED = 2;
- private static final int NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED = 5;
- private static final int NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED = 8;
- private static final int NUMBER_OF_CHILDREN_WHEN_AMBIENT = 1;
+ @VisibleForTesting
+ static final int NUMBER_OF_CHILDREN_WHEN_COLLAPSED = 2;
+ @VisibleForTesting
+ static final int NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED = 5;
+ @VisibleForTesting
+ static final int NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED = 8;
+ @VisibleForTesting
+ static final int NUMBER_OF_CHILDREN_WHEN_AMBIENT = 1;
private static final AnimationProperties ALPHA_FADE_IN = new AnimationProperties() {
private AnimationFilter mAnimationFilter = new AnimationFilter().animateAlpha();
@@ -699,15 +703,18 @@
return childState.height != intrinsicHeight && !childState.hidden;
}
- private int getMaxAllowedVisibleChildren() {
+ @VisibleForTesting
+ int getMaxAllowedVisibleChildren() {
return getMaxAllowedVisibleChildren(false /* likeCollapsed */);
}
- private int getMaxAllowedVisibleChildren(boolean likeCollapsed) {
+ @VisibleForTesting
+ int getMaxAllowedVisibleChildren(boolean likeCollapsed) {
if (mContainingNotification.isShowingAmbient()) {
return NUMBER_OF_CHILDREN_WHEN_AMBIENT;
}
- if (!likeCollapsed && (mChildrenExpanded || mContainingNotification.isUserLocked())) {
+ if (!likeCollapsed && (mChildrenExpanded || mContainingNotification.isUserLocked())
+ && !showingAsLowPriority()) {
return NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED;
}
if (mIsLowPriority || !mContainingNotification.isOnKeyguard()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 7bed01b..4264adad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -422,6 +422,7 @@
private int mHeadsUpInset;
private HeadsUpAppearanceController mHeadsUpAppearanceController;
private NotificationIconAreaController mIconAreaController;
+ private float mVerticalPanelTranslation;
public NotificationStackScrollLayout(Context context) {
this(context, null);
@@ -982,7 +983,7 @@
* Measured relative to the resting position.
*/
private float getExpandTranslationStart() {
- return - mTopPadding;
+ return -mTopPadding + getMinExpansionHeight();
}
/**
@@ -4003,8 +4004,13 @@
notifyHeightChangeListener(mShelf);
}
- private void updateAntiBurnInTranslation() {
- setTranslationX(mAntiBurnInOffsetX * mDarkAmount);
+ private void updatePanelTranslation() {
+ setTranslationX(mVerticalPanelTranslation + mAntiBurnInOffsetX * mDarkAmount);
+ }
+
+ public void setVerticalPanelTranslation(float verticalPanelTranslation) {
+ mVerticalPanelTranslation = verticalPanelTranslation;
+ updatePanelTranslation();
}
/**
@@ -4034,7 +4040,7 @@
}
updateAlgorithmHeightAndPadding();
updateBackgroundDimming();
- updateAntiBurnInTranslation();
+ updatePanelTranslation();
requestChildrenUpdate();
}
@@ -4602,7 +4608,7 @@
public void setAntiBurnInOffsetX(int antiBurnInOffsetX) {
mAntiBurnInOffsetX = antiBurnInOffsetX;
- updateAntiBurnInTranslation();
+ updatePanelTranslation();
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
diff --git a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
index 67fa049..c468fef 100644
--- a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
+++ b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
@@ -113,7 +113,7 @@
NotificationChannel screenshotChannel = new NotificationChannel(SCREENSHOTS_HEADSUP,
name, NotificationManager.IMPORTANCE_HIGH); // pop on screen
- screenshotChannel.setSound(Uri.parse(""), // silent
+ screenshotChannel.setSound(null, // silent
new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION).build());
screenshotChannel.setBlockableSystem(true);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
index d7fad67..4a9856b 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
@@ -193,11 +193,11 @@
}
public void show(int reason) {
- mHandler.obtainMessage(H.SHOW, reason, 0).sendToTarget();
+ mHandler.obtainMessage(H.SHOW, reason).sendToTarget();
}
public void dismiss(int reason) {
- mHandler.obtainMessage(H.DISMISS, reason, 0).sendToTarget();
+ mHandler.obtainMessage(H.DISMISS, reason).sendToTarget();
}
private void showH(int reason) {
@@ -223,7 +223,7 @@
mHandler.removeMessages(H.DISMISS);
final int timeout = computeTimeoutH();
mHandler.sendMessageDelayed(mHandler
- .obtainMessage(H.DISMISS, Events.DISMISS_REASON_TIMEOUT, 0), timeout);
+ .obtainMessage(H.DISMISS, Events.DISMISS_REASON_TIMEOUT), timeout);
if (D.BUG) {
Log.d(TAG, "rescheduleTimeout " + timeout + " " + Debug.getCaller());
@@ -246,7 +246,6 @@
}
mListView.animate().cancel();
- mShowing = false;
mListView.setTranslationY(0);
mListView.setAlpha(1);
@@ -260,6 +259,7 @@
Log.d(TAG, "mDialog.dismiss()");
}
mDialog.dismiss();
+ mShowing = false;
}, DISMISS_DELAY_IN_MILLIS))
.start();
@@ -436,7 +436,8 @@
public boolean onTouchEvent(MotionEvent event) {
if (isShowing()) {
if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
- dismissH(Events.DISMISS_REASON_TOUCH_OUTSIDE);
+ mHandler.obtainMessage(
+ H.DISMISS, Events.DISMISS_REASON_TOUCH_OUTSIDE).sendToTarget();
return true;
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
index ff12c53..f363cf0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
@@ -308,4 +308,12 @@
mGroupRow.resetTranslation();
assertEquals(0, mGroupRow.getEntry().expandedIcon.getScrollX());
}
+
+ @Test
+ public void testIsExpanded_userExpanded() {
+ mGroupRow.setExpandable(true);
+ Assert.assertFalse(mGroupRow.isExpanded());
+ mGroupRow.setUserExpanded(true);
+ Assert.assertTrue(mGroupRow.isExpanded());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 94ab9d2..6933328 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -60,7 +60,7 @@
@Mock
private NotificationPanelView mNotificationPanelView;
@Mock
- private FingerprintUnlockController mFingerprintUnlockController;
+ private BiometricUnlockController mBiometrucUnlockController;
@Mock
private DismissCallbackRegistry mDismissCallbackRegistry;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@@ -72,7 +72,7 @@
mStatusBarKeyguardViewManager = new TestableStatusBarKeyguardViewManager(getContext(),
mViewMediatorCallback, mLockPatternUtils);
mStatusBarKeyguardViewManager.registerStatusBar(mStatusBar, mContainer,
- mNotificationPanelView, mFingerprintUnlockController, mDismissCallbackRegistry);
+ mNotificationPanelView, mBiometrucUnlockController, mDismissCallbackRegistry);
mStatusBarKeyguardViewManager.show(null);
}
@@ -170,8 +170,8 @@
@Test
public void onPanelExpansionChanged_neverTranslatesBouncerWhenWakeAndUnlock() {
- when(mFingerprintUnlockController.getMode())
- .thenReturn(FingerprintUnlockController.MODE_WAKE_AND_UNLOCK);
+ when(mBiometrucUnlockController.getMode())
+ .thenReturn(BiometricUnlockController.MODE_WAKE_AND_UNLOCK);
mStatusBarKeyguardViewManager.onPanelExpansionChanged(KeyguardBouncer.EXPANSION_VISIBLE,
false /* tracking */);
verify(mBouncer, never()).setExpansion(anyFloat());
@@ -196,7 +196,7 @@
@Override
public void registerStatusBar(StatusBar statusBar, ViewGroup container,
NotificationPanelView notificationPanelView,
- FingerprintUnlockController fingerprintUnlockController,
+ BiometricUnlockController fingerprintUnlockController,
DismissCallbackRegistry dismissCallbackRegistry) {
super.registerStatusBar(statusBar, container, notificationPanelView,
fingerprintUnlockController, dismissCallbackRegistry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index cf23bfc..f908dfb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -132,7 +132,7 @@
@Mock private IStatusBarService mBarService;
@Mock private ScrimController mScrimController;
@Mock private ArrayList<Entry> mNotificationList;
- @Mock private FingerprintUnlockController mFingerprintUnlockController;
+ @Mock private BiometricUnlockController mBiometricUnlockController;
@Mock private NotificationData mNotificationData;
// Mock dependencies:
@@ -207,7 +207,7 @@
mKeyguardIndicationController, mStackScroller, mHeadsUpManager,
mPowerManager, mNotificationPanelView, mBarService, mNotificationListener,
mNotificationLogger, mVisualStabilityManager, mViewHierarchyManager,
- mEntryManager, mScrimController, mFingerprintUnlockController,
+ mEntryManager, mScrimController, mBiometricUnlockController,
mock(ActivityLaunchAnimator.class), mKeyguardViewMediator,
mRemoteInputManager, mock(NotificationGroupManager.class),
mock(FalsingManager.class), mock(StatusBarWindowManager.class),
@@ -572,15 +572,15 @@
@Test
public void testFingerprintNotification_UpdatesScrims() {
- mStatusBar.notifyFpAuthModeChanged();
+ mStatusBar.notifyBiometricAuthModeChanged();
verify(mScrimController).transitionTo(any(), any());
}
@Test
public void testFingerprintUnlock_UpdatesScrims() {
// Simulate unlocking from AoD with fingerprint.
- when(mFingerprintUnlockController.getMode())
- .thenReturn(FingerprintUnlockController.MODE_WAKE_AND_UNLOCK);
+ when(mBiometricUnlockController.getMode())
+ .thenReturn(BiometricUnlockController.MODE_WAKE_AND_UNLOCK);
mStatusBar.updateScrimController();
verify(mScrimController).transitionTo(eq(ScrimState.UNLOCKED), any());
}
@@ -717,7 +717,7 @@
VisualStabilityManager visualStabilityManager,
NotificationViewHierarchyManager viewHierarchyManager,
TestableNotificationEntryManager entryManager, ScrimController scrimController,
- FingerprintUnlockController fingerprintUnlockController,
+ BiometricUnlockController biometricUnlockController,
ActivityLaunchAnimator launchAnimator, KeyguardViewMediator keyguardViewMediator,
NotificationRemoteInputManager notificationRemoteInputManager,
NotificationGroupManager notificationGroupManager,
@@ -743,7 +743,7 @@
mViewHierarchyManager = viewHierarchyManager;
mEntryManager = entryManager;
mScrimController = scrimController;
- mFingerprintUnlockController = fingerprintUnlockController;
+ mBiometricUnlockController = biometricUnlockController;
mActivityLaunchAnimator = launchAnimator;
mKeyguardViewMediator = keyguardViewMediator;
mClearAllEnabled = true;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationChildrenContainerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationChildrenContainerTest.java
index 8a74019..cfacf0b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationChildrenContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationChildrenContainerTest.java
@@ -40,30 +40,117 @@
private ExpandableNotificationRow mGroup;
private int mId;
private NotificationTestHelper mNotificationTestHelper;
+ private NotificationChildrenContainer mChildrenContainer;
@Before
public void setUp() throws Exception {
mNotificationTestHelper = new NotificationTestHelper(mContext);
mGroup = mNotificationTestHelper.createGroup();
+ mChildrenContainer = mGroup.getChildrenContainer();
+ }
+
+ @Test
+ public void testGetMaxAllowedVisibleChildren_ambient() {
+ mGroup.setShowAmbient(true);
+ Assert.assertEquals(mChildrenContainer.getMaxAllowedVisibleChildren(),
+ NotificationChildrenContainer.NUMBER_OF_CHILDREN_WHEN_AMBIENT);
+ }
+
+ @Test
+ public void testGetMaxAllowedVisibleChildren_lowPriority() {
+ mChildrenContainer.setIsLowPriority(true);
+ Assert.assertEquals(mChildrenContainer.getMaxAllowedVisibleChildren(),
+ NotificationChildrenContainer.NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED);
+ }
+
+ @Test
+ public void testGetMaxAllowedVisibleChildren_headsUp() {
+ mGroup.setHeadsUp(true);
+ Assert.assertEquals(mChildrenContainer.getMaxAllowedVisibleChildren(),
+ NotificationChildrenContainer.NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED);
+ }
+
+ @Test
+ public void testGetMaxAllowedVisibleChildren_lowPriority_expandedChildren() {
+ mChildrenContainer.setIsLowPriority(true);
+ mChildrenContainer.setChildrenExpanded(true);
+ Assert.assertEquals(mChildrenContainer.getMaxAllowedVisibleChildren(),
+ NotificationChildrenContainer.NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED);
+ }
+
+ @Test
+ public void testGetMaxAllowedVisibleChildren_lowPriority_userLocked() {
+ mChildrenContainer.setIsLowPriority(true);
+ mChildrenContainer.setUserLocked(true);
+ Assert.assertEquals(mChildrenContainer.getMaxAllowedVisibleChildren(),
+ NotificationChildrenContainer.NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED);
+ }
+
+ @Test
+ public void testGetMaxAllowedVisibleChildren_likeCollapsed() {
+ Assert.assertEquals(mChildrenContainer.getMaxAllowedVisibleChildren(true),
+ NotificationChildrenContainer.NUMBER_OF_CHILDREN_WHEN_COLLAPSED);
+ }
+
+
+ @Test
+ public void testGetMaxAllowedVisibleChildren_expandedChildren() {
+ mChildrenContainer.setChildrenExpanded(true);
+ Assert.assertEquals(mChildrenContainer.getMaxAllowedVisibleChildren(),
+ NotificationChildrenContainer.NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED);
+ }
+
+ @Test
+ public void testGetMaxAllowedVisibleChildren_userLocked() {
+ mGroup.setUserLocked(true);
+ Assert.assertEquals(mChildrenContainer.getMaxAllowedVisibleChildren(),
+ NotificationChildrenContainer.NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED);
+ }
+
+ @Test
+ public void testShowingAsLowPriority_lowPriority() {
+ mChildrenContainer.setIsLowPriority(true);
+ Assert.assertTrue(mChildrenContainer.showingAsLowPriority());
+ }
+
+ @Test
+ public void testShowingAsLowPriority_notLowPriority() {
+ Assert.assertFalse(mChildrenContainer.showingAsLowPriority());
+ }
+
+ @Test
+ public void testShowingAsLowPriority_lowPriority_expanded() {
+ mChildrenContainer.setIsLowPriority(true);
+ mGroup.setExpandable(true);
+ mGroup.setUserExpanded(true, false);
+ Assert.assertFalse(mChildrenContainer.showingAsLowPriority());
+ }
+
+ @Test
+ public void testGetMaxAllowedVisibleChildren_userLocked_expandedChildren_lowPriority() {
+ mGroup.setUserLocked(true);
+ mGroup.setExpandable(true);
+ mGroup.setUserExpanded(true);
+ mChildrenContainer.setIsLowPriority(true);
+ Assert.assertEquals(mChildrenContainer.getMaxAllowedVisibleChildren(),
+ NotificationChildrenContainer.NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED);
}
@Test
public void testLowPriorityHeaderCleared() {
mGroup.setIsLowPriority(true);
- NotificationChildrenContainer childrenContainer = mGroup.getChildrenContainer();
- NotificationHeaderView lowPriorityHeaderView = childrenContainer.getLowPriorityHeaderView();
+ NotificationHeaderView lowPriorityHeaderView = mChildrenContainer.getLowPriorityHeaderView();
Assert.assertTrue(lowPriorityHeaderView.getVisibility() == View.VISIBLE);
- Assert.assertTrue(lowPriorityHeaderView.getParent() == childrenContainer);
+ Assert.assertTrue(lowPriorityHeaderView.getParent() == mChildrenContainer);
mGroup.setIsLowPriority(false);
Assert.assertTrue(lowPriorityHeaderView.getParent() == null);
- Assert.assertTrue(childrenContainer.getLowPriorityHeaderView() == null);
+ Assert.assertTrue(mChildrenContainer.getLowPriorityHeaderView() == null);
}
@Test
public void testRecreateNotificationHeader_hasHeader() {
- NotificationChildrenContainer childrenContainer = mGroup.getChildrenContainer();
- childrenContainer.recreateNotificationHeader(null);
+ mChildrenContainer.recreateNotificationHeader(null);
Assert.assertNotNull("Children container must have a header after recreation",
- childrenContainer.getCurrentHeaderView());
+ mChildrenContainer.getCurrentHeaderView());
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java
index 50b4f3f..0d398be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java
@@ -103,7 +103,7 @@
NotificationManager.IMPORTANCE_MIN);
NotificationChannel newChannel =
NotificationChannels.createScreenshotChannel("newName", legacyChannel);
- assertEquals(Uri.EMPTY, newChannel.getSound());
+ assertEquals(null, newChannel.getSound());
assertEquals("newName", newChannel.getName());
// MIN importance not user locked, so HIGH wins out.
assertEquals(NotificationManager.IMPORTANCE_HIGH, newChannel.getImportance());
@@ -113,7 +113,7 @@
public void testInheritFromLegacy_noLegacyExists() {
NotificationChannel newChannel =
NotificationChannels.createScreenshotChannel("newName", null);
- assertEquals(Uri.EMPTY, newChannel.getSound());
+ assertEquals(null, newChannel.getSound());
assertEquals("newName", newChannel.getName());
assertEquals(NotificationManager.IMPORTANCE_HIGH, newChannel.getImportance());
}
diff --git a/packages/VpnDialogs/res/drawable-hdpi/ic_vpn_dialog.png b/packages/VpnDialogs/res/drawable-hdpi/ic_vpn_dialog.png
deleted file mode 100644
index a0b4b61..0000000
--- a/packages/VpnDialogs/res/drawable-hdpi/ic_vpn_dialog.png
+++ /dev/null
Binary files differ
diff --git a/packages/VpnDialogs/res/drawable-mdpi/ic_vpn_dialog.png b/packages/VpnDialogs/res/drawable-mdpi/ic_vpn_dialog.png
deleted file mode 100644
index df5dfe8..0000000
--- a/packages/VpnDialogs/res/drawable-mdpi/ic_vpn_dialog.png
+++ /dev/null
Binary files differ
diff --git a/packages/VpnDialogs/res/drawable-xhdpi/ic_vpn_dialog.png b/packages/VpnDialogs/res/drawable-xhdpi/ic_vpn_dialog.png
deleted file mode 100644
index 18d5a3a..0000000
--- a/packages/VpnDialogs/res/drawable-xhdpi/ic_vpn_dialog.png
+++ /dev/null
Binary files differ
diff --git a/packages/VpnDialogs/res/drawable-xxhdpi/ic_vpn_dialog.png b/packages/VpnDialogs/res/drawable-xxhdpi/ic_vpn_dialog.png
deleted file mode 100644
index 4d475dc..0000000
--- a/packages/VpnDialogs/res/drawable-xxhdpi/ic_vpn_dialog.png
+++ /dev/null
Binary files differ
diff --git a/packages/VpnDialogs/res/drawable-xxxhdpi/ic_vpn_dialog.png b/packages/VpnDialogs/res/drawable-xxxhdpi/ic_vpn_dialog.png
deleted file mode 100644
index 9d458b4..0000000
--- a/packages/VpnDialogs/res/drawable-xxxhdpi/ic_vpn_dialog.png
+++ /dev/null
Binary files differ
diff --git a/packages/VpnDialogs/res/drawable/ic_vpn_dialog.xml b/packages/VpnDialogs/res/drawable/ic_vpn_dialog.xml
new file mode 100644
index 0000000..24f622e
--- /dev/null
+++ b/packages/VpnDialogs/res/drawable/ic_vpn_dialog.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="17dp"
+ android:height="17dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12.09,9C11.11,7.5 9.43,6.5 7.5,6.5C4.46,6.5 2,8.96 2,12c0,3.04 2.46,5.5 5.5,5.5c1.93,0 3.61,-1 4.59,-2.5H14v3h6v-3h2V9H12.09zM20,13h-2v3h-2v-3h-5.16c-0.43,1.44 -1.76,2.5 -3.34,2.5C5.57,15.5 4,13.93 4,12c0,-1.93 1.57,-3.5 3.5,-3.5c1.58,0 2.9,1.06 3.34,2.5H20V13z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M7.5,12m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
+</vector>
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index d2990de..73eb37f 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -6118,9 +6118,33 @@
// ---- End P Constants, all P constants go above this line ----
- // First Q constant in master goes here:
- // Please delete these lines and use 1500 for your first enum.
+ // Time since this notification last interrupted (visibly or audible) the user
+ NOTIFICATION_SINCE_INTERRUPTION_MILLIS = 1500;
+ // OPEN: Notification interrupted the user, either audibly or visually.
+ // Tagged data: NOTIFICATION_SINCE_INTERRUPTION_MILLIS
+ // CATEGORY: NOTIFICATION
+ NOTIFICATION_INTERRUPTION = 1501;
+
+ // OPEN: Settings
+ // CATEGORY: SETTINGS
+ // OS: Q
+ SETTINGS_HOMEPAGE = 1502;
+
+ // OPEN: Settings > Create shortcut(widget)
+ // CATEGORY: SETTINGS
+ // OS: Q
+ SETTINGS_CREATE_SHORTCUT = 1503;
+
+ // ACTION: Authenticate using fingerprint
+ // CATEGORY: SETTINGS
+ // OS: Q
+ ACTION_FACE_AUTH = 1504;
+
+ // ACTION: Add fingerprint > Enroll fingerprint
+ // CATEGORY: SETTINGS
+ // OS: Q
+ ACTION_FACE_ENROLL = 1505;
// ---- End Q Constants, all Q constants go above this line ----
// Add new aosp constants above this line.
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index a9a14ca..fba639c 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -212,6 +212,10 @@
// Package: android
NOTE_AUTO_SAVER_SUGGESTION = 49;
+ // Notify the user that their softap config preference has changed.
+ // Package: android
+ NOTE_SOFTAP_CONFIG_CHANGED = 50;
+
// ADD_NEW_IDS_ABOVE_THIS_LINE
// Legacy IDs with arbitrary values appear below
// Legacy IDs existed as stable non-conflicting constants prior to the O release
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index a23c6d3..33fc5e5 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -459,6 +459,17 @@
// Data on wifi radio usage
optional WifiRadioUsage wifi_radio_usage = 118;
+
+ // Stores settings values used for metrics testing.
+ optional ExperimentValues experiment_values = 119;
+
+ // List of WifiIsUnusableEvents which get logged when we notice that WiFi is unusable.
+ // Collected only when WIFI_IS_UNUSABLE_EVENT_METRICS_ENABLED Settings is enabled.
+ repeated WifiIsUnusableEvent wifi_is_unusable_event_list = 120;
+
+ // Counts the occurrences of each link speed (Mbps) level
+ // with rssi (dBm) and rssi^2 sums (dBm^2)
+ repeated LinkSpeedCount link_speed_counts = 121;
}
// Information that gets logged for every WiFi connection.
@@ -644,6 +655,22 @@
optional int32 count = 2;
}
+// Number of occurrences of a specific link speed (Mbps)
+// and sum of rssi (dBm) and rssi^2 (dBm^2)
+message LinkSpeedCount {
+ // Link speed (Mbps)
+ optional int32 link_speed_mbps = 1;
+
+ // Number of RSSI polls with link_speed
+ optional int32 count = 2;
+
+ // Sum of absolute values of rssi values (dBm)
+ optional int32 rssi_sum_dbm = 3;
+
+ // Sum of squares of rssi values (dBm^2)
+ optional int64 rssi_sum_of_squares_dbm_sq = 4;
+}
+
// Number of occurrences of Soft AP session durations
message SoftApDurationBucket {
// Bucket covers duration : [duration_sec, duration_sec + bucket_size_sec)
@@ -876,7 +903,7 @@
STATE_INVALID = 12;
}
- // Bit mask of all supplicant state changes that occured since the last event
+ // Bit mask of all supplicant state changes that occurred since the last event
optional uint32 supplicant_state_changes_bitmask = 9 [default = 0];
// The number of milliseconds that have elapsed since the device booted
@@ -884,7 +911,7 @@
optional FrameworkDisconnectReason framework_disconnect_reason = 11 [default = DISCONNECT_UNKNOWN];
- // Flag which indicates if an association rejection event occured due to a timeout
+ // Flag which indicates if an association rejection event occurred due to a timeout
optional bool association_timed_out = 12 [default = false];
// Authentication failure reason, as reported by WifiManager (calculated from state & deauth code)
@@ -1513,4 +1540,75 @@
// Total time for which the radio is awake due to scan.
optional int64 scan_time_ms = 2;
+}
+
+message ExperimentValues {
+ // Indicates if we are logging WifiIsUnusableEvent in metrics
+ optional bool wifi_is_unusable_logging_enabled = 1;
+
+ // Minimum number of txBad to trigger a data stall
+ optional int32 wifi_data_stall_min_tx_bad = 2;
+
+ // Minimum number of txSuccess to trigger a data stall
+ // when rxSuccess is 0
+ optional int32 wifi_data_stall_min_tx_success_without_rx = 3;
+
+ // Indicates if we are logging LinkSpeedCount in metrics
+ optional bool link_speed_counts_logging_enabled = 4;
+}
+
+message WifiIsUnusableEvent {
+ enum TriggerType {
+ // Default/Invalid event
+ TYPE_UNKNOWN = 0;
+
+ // There is a data stall from tx failures
+ TYPE_DATA_STALL_BAD_TX = 1;
+
+ // There is a data stall from rx failures
+ TYPE_DATA_STALL_TX_WITHOUT_RX = 2;
+
+ // There is a data stall from both tx and rx failures
+ TYPE_DATA_STALL_BOTH = 3;
+
+ // Firmware generated an alert
+ TYPE_FIRMWARE_ALERT = 4;
+ }
+
+ // What event triggered WifiIsUnusableEvent.
+ optional TriggerType type = 1;
+
+ // The timestamp at which this event occurred.
+ // Measured in milliseconds that have elapsed since the device booted.
+ optional int64 start_time_millis = 2;
+
+ // NetworkAgent score of connected wifi.
+ // Defaults to -1 if the score was never set.
+ optional int32 last_score = 3 [default = -1];
+
+ // Delta of successfully transmitted (ACKed) unicast data packets
+ // between the last two WifiLinkLayerStats.
+ optional int64 tx_success_delta = 4;
+
+ // Delta of transmitted unicast data retry packets
+ // between the last two WifiLinkLayerStats.
+ optional int64 tx_retries_delta = 5;
+
+ // Delta of lost (not ACKed) transmitted unicast data packets
+ // between the last two WifiLinkLayerStats.
+ optional int64 tx_bad_delta = 6;
+
+ // Delta of received unicast data packets
+ // between the last two WifiLinkLayerStats.
+ optional int64 rx_success_delta = 7;
+
+ // Time in millisecond between the last two WifiLinkLayerStats.
+ optional int64 packet_update_time_delta = 8;
+
+ // The timestamp at which the last WifiLinkLayerStats was updated.
+ // Measured in milliseconds that have elapsed since the device booted.
+ optional int64 last_link_layer_stats_update_time = 9;
+
+ // Firmware alert code. Only valid when the event was triggered by a firmware alert, otherwise -1.
+ optional int32 firmware_alert_code = 10 [default = -1];
}
\ No newline at end of file
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 4365760..376d16b 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -20,7 +20,6 @@
import static android.view.accessibility.AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS;
-
import static com.android.internal.util.FunctionalUtils.ignoreRemoteException;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
@@ -30,8 +29,6 @@
import android.accessibilityservice.IAccessibilityServiceClient;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.ActivityManagerInternal;
-import android.app.ActivityTaskManagerInternal;
import android.app.AlertDialog;
import android.app.AppOpsManager;
import android.app.PendingIntent;
@@ -112,10 +109,9 @@
import com.android.internal.util.IntPair;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
+import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
-import libcore.util.EmptyArray;
-
import org.xmlpull.v1.XmlPullParserException;
import java.io.FileDescriptor;
@@ -134,6 +130,8 @@
import java.util.function.Consumer;
import java.util.function.IntSupplier;
+import libcore.util.EmptyArray;
+
/**
* This class is instantiated by the system as a system level service and can be
* accessed only by the system. The task of this service is to be a centralized
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index a2dc986..4206d9a 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -28,7 +28,6 @@
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.ActivityManagerInternal;
-import android.app.ActivityTaskManagerInternal;
import android.app.AppGlobals;
import android.app.IActivityManager;
import android.app.IActivityTaskManager;
@@ -83,6 +82,7 @@
import com.android.server.LocalServices;
import com.android.server.autofill.AutofillManagerService.AutofillCompatState;
import com.android.server.autofill.ui.AutoFillUI;
+import com.android.server.wm.ActivityTaskManagerInternal;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -534,7 +534,7 @@
} catch (NameNotFoundException e) {
throw new SecurityException("Could not verify UID for " + componentName);
}
- if (callingUid != packageUid && !LocalServices.getService(ActivityTaskManagerInternal.class)
+ if (callingUid != packageUid && !LocalServices.getService(ActivityManagerInternal.class)
.hasRunningActivity(callingUid, packageName)) {
final String[] packages = pm.getPackagesForUid(callingUid);
final String callingPackage = packages != null ? packages[0] : "uid-" + callingUid;
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 48f27d8..18255c5 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -16,8 +16,6 @@
package com.android.server.autofill;
-import static android.app.ActivityTaskManagerInternal.ASSIST_KEY_RECEIVER_EXTRAS;
-import static android.app.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE;
import static android.service.autofill.AutofillFieldClassificationService.EXTRA_SCORES;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
@@ -33,6 +31,8 @@
import static com.android.server.autofill.Helper.sVerbose;
import static com.android.server.autofill.Helper.toArray;
import static com.android.server.autofill.ViewState.STATE_RESTARTED_SESSION;
+import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_RECEIVER_EXTRAS;
+import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE;
import android.annotation.NonNull;
import android.annotation.Nullable;
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 8da6d1e..d9519e0 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -26,7 +26,6 @@
"android.hardware.light-V2.0-java",
"android.hardware.power-V1.0-java",
"android.hardware.tv.cec-V1.0-java",
- "android.hidl.manager-V1.0-java",
],
static_libs: [
@@ -37,12 +36,14 @@
"android.hardware.health-V1.0-java",
"android.hardware.health-V2.0-java",
"android.hardware.weaver-V1.0-java",
+ "android.hardware.biometrics.face-V1.0-java",
"android.hardware.biometrics.fingerprint-V2.1-java",
"android.hardware.oemlock-V1.0-java",
"android.hardware.tetheroffload.control-V1.0-java",
"android.hardware.vibrator-V1.0-java",
"android.hardware.configstore-V1.0-java",
"android.hardware.contexthub-V1.0-java",
+ "android.hidl.manager-V1.0-java",
],
}
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 6ca81c2..3261209 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -172,7 +172,8 @@
long mNativeData;
private long mNextWakeup;
private long mNextNonWakeup;
- private long mLastWakeupSet;
+ private long mNextWakeUpSetAt;
+ private long mNextNonWakeUpSetAt;
private long mLastWakeup;
private long mLastTrigger;
private long mLastTickSet;
@@ -1939,7 +1940,7 @@
TimeUtils.formatDuration(nowELAPSED - mLastAlarmDeliveryTime, pw);
pw.println();
pw.print(" Next non-wakeup delivery time: ");
- TimeUtils.formatDuration(nowELAPSED - mNextNonWakeupDeliveryTime, pw);
+ TimeUtils.formatDuration(mNextNonWakeupDeliveryTime, nowELAPSED, pw);
pw.println();
long nextWakeupRTC = mNextWakeup + (nowRTC - nowELAPSED);
@@ -1948,10 +1949,12 @@
TimeUtils.formatDuration(mNextNonWakeup, nowELAPSED, pw);
pw.print(" = "); pw.print(mNextNonWakeup);
pw.print(" = "); pw.println(sdf.format(new Date(nextNonWakeupRTC)));
+ pw.print(" set at "); TimeUtils.formatDuration(mNextNonWakeUpSetAt, nowELAPSED, pw);
+ pw.println();
pw.print(" Next wakeup alarm: "); TimeUtils.formatDuration(mNextWakeup, nowELAPSED, pw);
pw.print(" = "); pw.print(mNextWakeup);
pw.print(" = "); pw.println(sdf.format(new Date(nextWakeupRTC)));
- pw.print(" set at "); TimeUtils.formatDuration(mLastWakeupSet, nowELAPSED, pw);
+ pw.print(" set at "); TimeUtils.formatDuration(mNextWakeUpSetAt, nowELAPSED, pw);
pw.println();
pw.print(" Next kernel non-wakeup alarm: ");
@@ -2290,7 +2293,7 @@
proto.write(AlarmManagerServiceDumpProto.TIME_SINCE_LAST_WAKEUP_MS,
nowElapsed - mLastWakeup);
proto.write(AlarmManagerServiceDumpProto.TIME_SINCE_LAST_WAKEUP_SET_MS,
- nowElapsed - mLastWakeupSet);
+ nowElapsed - mNextWakeUpSetAt);
proto.write(AlarmManagerServiceDumpProto.TIME_CHANGE_EVENT_COUNT, mNumTimeChanged);
final TreeSet<Integer> users = new TreeSet<>();
@@ -2675,16 +2678,49 @@
DateFormat.format(pattern, info.getTriggerTime()).toString();
}
+ /**
+ * If the last time AlarmThread woke up precedes any due wakeup or non-wakeup alarm that we set
+ * by more than half a minute, log a wtf.
+ */
+ private void validateLastAlarmExpiredLocked(long nowElapsed) {
+ final StringBuilder errorMsg = new StringBuilder();
+ boolean stuck = false;
+ if (mNextNonWakeup < nowElapsed && mLastWakeup < (mNextNonWakeup - 30_000)) {
+ stuck = true;
+ errorMsg.append("[mNextNonWakeup=");
+ TimeUtils.formatDuration(mNextNonWakeup - nowElapsed, errorMsg);
+ errorMsg.append(", mLastWakeup=");
+ TimeUtils.formatDuration(mLastWakeup - nowElapsed, errorMsg);
+ errorMsg.append(", timerfd_gettime=" + getNextAlarm(mNativeData, ELAPSED_REALTIME));
+ errorMsg.append("];");
+ }
+ if (mNextWakeup < nowElapsed && mLastWakeup < (mNextWakeup - 30_000)) {
+ stuck = true;
+ errorMsg.append("[mNextWakeup=");
+ TimeUtils.formatDuration(mNextWakeup - nowElapsed, errorMsg);
+ errorMsg.append(", mLastWakeup=");
+ TimeUtils.formatDuration(mLastWakeup - nowElapsed, errorMsg);
+ errorMsg.append(", timerfd_gettime="
+ + getNextAlarm(mNativeData, ELAPSED_REALTIME_WAKEUP));
+ errorMsg.append("];");
+ }
+ if (stuck) {
+ Slog.wtf(TAG, "Alarm delivery stuck: " + errorMsg.toString());
+ }
+ }
+
void rescheduleKernelAlarmsLocked() {
// Schedule the next upcoming wakeup alarm. If there is a deliverable batch
// prior to that which contains no wakeups, we schedule that as well.
+ final long nowElapsed = SystemClock.elapsedRealtime();
+ validateLastAlarmExpiredLocked(nowElapsed);
long nextNonWakeup = 0;
if (mAlarmBatches.size() > 0) {
final Batch firstWakeup = findFirstWakeupBatchLocked();
final Batch firstBatch = mAlarmBatches.get(0);
if (firstWakeup != null) {
mNextWakeup = firstWakeup.start;
- mLastWakeupSet = SystemClock.elapsedRealtime();
+ mNextWakeUpSetAt = nowElapsed;
setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
}
if (firstBatch != firstWakeup) {
@@ -2698,6 +2734,7 @@
}
if (nextNonWakeup != 0) {
mNextNonWakeup = nextNonWakeup;
+ mNextNonWakeUpSetAt = nowElapsed;
setLocked(ELAPSED_REALTIME, nextNonWakeup);
}
}
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 786d757..1167e1d 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -198,7 +198,7 @@
@VisibleForTesting
final SparseArray<UidState> mUidStates = new SparseArray<>();
- long mLastUptime;
+ long mLastRealtime;
/*
* These are app op restrictions imposed per user from various parties.
@@ -770,7 +770,7 @@
} else {
settleTime = mConstants.BG_STATE_SETTLE_TIME;
}
- uidState.pendingStateCommitTime = SystemClock.uptimeMillis() + settleTime;
+ uidState.pendingStateCommitTime = SystemClock.elapsedRealtime() + settleTime;
}
if (uidState.startNesting != 0) {
// There is some actively running operation... need to find it
@@ -1881,11 +1881,11 @@
mUidStates.put(uid, uidState);
} else {
if (uidState.pendingStateCommitTime != 0) {
- if (uidState.pendingStateCommitTime < mLastUptime) {
+ if (uidState.pendingStateCommitTime < mLastRealtime) {
commitUidPendingStateLocked(uidState);
} else {
- mLastUptime = SystemClock.uptimeMillis();
- if (uidState.pendingStateCommitTime < mLastUptime) {
+ mLastRealtime = SystemClock.elapsedRealtime();
+ if (uidState.pendingStateCommitTime < mLastRealtime) {
commitUidPendingStateLocked(uidState);
}
}
@@ -3284,7 +3284,7 @@
}
if (uidState.pendingStateCommitTime != 0) {
pw.print(" pendingStateCommitTime=");
- TimeUtils.formatDuration(uidState.pendingStateCommitTime, nowUptime, pw);
+ TimeUtils.formatDuration(uidState.pendingStateCommitTime, nowElapsed, pw);
pw.println();
}
if (uidState.startNesting != 0) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 5b55fa1..3c94a34 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -898,6 +898,10 @@
public boolean isTetheringSupported() {
return ConnectivityService.this.isTetheringSupported();
}
+ @Override
+ public NetworkRequest getDefaultNetworkRequest() {
+ return mDefaultRequest;
+ }
};
return new Tethering(mContext, mNetd, mStatsService, mPolicyManager,
IoThread.get().getLooper(), new MockableSystemProperties(),
@@ -915,7 +919,7 @@
private NetworkRequest createDefaultInternetRequestForTransport(
int transportType, NetworkRequest.Type type) {
- NetworkCapabilities netCap = new NetworkCapabilities();
+ final NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addCapability(NET_CAPABILITY_INTERNET);
netCap.addCapability(NET_CAPABILITY_NOT_RESTRICTED);
if (transportType > -1) {
@@ -1020,7 +1024,8 @@
}
}
- private NetworkAgentInfo getNetworkAgentInfoForNetwork(Network network) {
+ @VisibleForTesting
+ protected NetworkAgentInfo getNetworkAgentInfoForNetwork(Network network) {
if (network == null) {
return null;
}
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 4e700d7..a34c2b9 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -19,7 +19,6 @@
import android.Manifest;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
-import android.app.ActivityTaskManagerInternal;
import android.app.AlarmManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -31,15 +30,15 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.database.ContentObserver;
import android.hardware.Sensor;
-import android.hardware.SensorManager;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
import android.hardware.TriggerEvent;
import android.hardware.TriggerEventListener;
-import android.location.LocationRequest;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
+import android.location.LocationRequest;
import android.net.ConnectivityManager;
import android.net.INetworkPolicyManager;
import android.net.NetworkInfo;
@@ -86,6 +85,7 @@
import com.android.internal.util.XmlUtils;
import com.android.server.am.BatteryStatsService;
import com.android.server.net.NetworkPolicyManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index caea282..4b8ece9 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -468,6 +468,13 @@
IBinder mCurFocusedWindow;
/**
+ * The last window token that we confirmed that IME started talking to. This is always updated
+ * upon reports from the input method. If the window state is already changed before the report
+ * is handled, this field just keeps the last value.
+ */
+ IBinder mLastImeTargetWindow;
+
+ /**
* {@link WindowManager.LayoutParams#softInputMode} of {@link #mCurFocusedWindow}.
*
* @see #mCurFocusedWindow
@@ -688,7 +695,7 @@
}
@GuardedBy("mMethodMap")
- private final WeakHashMap<IBinder, StartInputInfo> mStartInputMap = new WeakHashMap<>();
+ private final WeakHashMap<IBinder, IBinder> mImeTargetWindowMap = new WeakHashMap<>();
/**
* A ring buffer to store the history of {@link StartInputInfo}.
@@ -1809,7 +1816,7 @@
final StartInputInfo info = new StartInputInfo(mCurToken, mCurId, startInputReason,
!initial, mCurFocusedWindow, mCurAttribute, mCurFocusedWindowSoftInputMode,
mCurSeq);
- mStartInputMap.put(startInputToken, info);
+ mImeTargetWindowMap.put(startInputToken, mCurFocusedWindow);
mStartInputHistory.addEntry(info);
final SessionState session = mCurClient.curSession;
@@ -1827,50 +1834,6 @@
@GuardedBy("mMethodMap")
@NonNull
- InputBindResult startInputLocked(
- /* @InputMethodClient.StartInputReason */ final int startInputReason,
- IInputMethodClient client, IInputContext inputContext,
- /* @InputConnectionInspector.missingMethods */ final int missingMethods,
- @Nullable EditorInfo attribute, int controlFlags) {
- // If no method is currently selected, do nothing.
- if (mCurMethodId == null) {
- return InputBindResult.NO_IME;
- }
-
- ClientState cs = mClients.get(client.asBinder());
- if (cs == null) {
- throw new IllegalArgumentException("unknown client "
- + client.asBinder());
- }
-
- if (attribute == null) {
- Slog.w(TAG, "Ignoring startInput with null EditorInfo."
- + " uid=" + cs.uid + " pid=" + cs.pid);
- return InputBindResult.NULL_EDITOR_INFO;
- }
-
- try {
- if (!mIWindowManager.inputMethodClientHasFocus(cs.client)) {
- // Check with the window manager to make sure this client actually
- // has a window with focus. If not, reject. This is thread safe
- // because if the focus changes some time before or after, the
- // next client receiving focus that has any interest in input will
- // be calling through here after that change happens.
- if (DEBUG) {
- Slog.w(TAG, "Starting input on non-focused client " + cs.client
- + " (uid=" + cs.uid + " pid=" + cs.pid + ")");
- }
- return InputBindResult.NOT_IME_TARGET_WINDOW;
- }
- } catch (RemoteException e) {
- }
-
- return startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
- controlFlags, startInputReason);
- }
-
- @GuardedBy("mMethodMap")
- @NonNull
InputBindResult startInputUncheckedLocked(@NonNull ClientState cs, IInputContext inputContext,
/* @InputConnectionInspector.missingMethods */ final int missingMethods,
@NonNull EditorInfo attribute, int controlFlags,
@@ -1997,36 +1960,6 @@
return InputBindResult.IME_NOT_CONNECTED;
}
- @NonNull
- private InputBindResult startInput(
- /* @InputMethodClient.StartInputReason */ final int startInputReason,
- IInputMethodClient client, IInputContext inputContext,
- /* @InputConnectionInspector.missingMethods */ final int missingMethods,
- @Nullable EditorInfo attribute, int controlFlags) {
- if (!calledFromValidUser()) {
- return InputBindResult.INVALID_USER;
- }
- synchronized (mMethodMap) {
- if (DEBUG) {
- Slog.v(TAG, "startInput: reason="
- + InputMethodClient.getStartInputReason(startInputReason)
- + " client = " + client.asBinder()
- + " inputContext=" + inputContext
- + " missingMethods="
- + InputConnectionInspector.getMissingMethodFlagsAsString(missingMethods)
- + " attribute=" + attribute
- + " controlFlags=#" + Integer.toHexString(controlFlags));
- }
- final long ident = Binder.clearCallingIdentity();
- try {
- return startInputLocked(startInputReason, client, inputContext, missingMethods,
- attribute, controlFlags);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
- }
-
@Override
public void finishInput(IInputMethodClient client) {
}
@@ -2293,15 +2226,12 @@
@BinderThread
@SuppressWarnings("deprecation")
@Override
- public void setImeWindowStatus(IBinder token, IBinder startInputToken, int vis,
- int backDisposition) {
+ public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
if (!calledWithValidToken(token)) {
return;
}
- final StartInputInfo info;
synchronized (mMethodMap) {
- info = mStartInputMap.get(startInputToken);
mImeWindowVis = vis;
mBackDisposition = backDisposition;
updateSystemUiLocked(token, vis, backDisposition);
@@ -2321,8 +2251,7 @@
break;
}
mWindowManagerInternal.updateInputMethodWindowStatus(token,
- (vis & InputMethodService.IME_VISIBLE) != 0,
- dismissImeOnBackKeyPressed, info != null ? info.mTargetWindow : null);
+ (vis & InputMethodService.IME_VISIBLE) != 0, dismissImeOnBackKeyPressed);
}
private void updateSystemUi(IBinder token, int vis, int backDisposition) {
@@ -2331,6 +2260,22 @@
}
}
+ @BinderThread
+ @Override
+ public void reportStartInput(IBinder token, IBinder startInputToken) {
+ if (!calledWithValidToken(token)) {
+ return;
+ }
+
+ synchronized (mMethodMap) {
+ final IBinder targetWindow = mImeTargetWindowMap.get(startInputToken);
+ if (targetWindow != null && mLastImeTargetWindow != targetWindow) {
+ mWindowManagerInternal.updateInputMethodTargetWindow(token, targetWindow);
+ }
+ mLastImeTargetWindow = targetWindow;
+ }
+ }
+
// Caution! This method is called in this class. Handle multi-user carefully
private void updateSystemUiLocked(IBinder token, int vis, int backDisposition) {
if (!calledWithValidToken(token)) {
@@ -2741,15 +2686,13 @@
int windowFlags, @Nullable EditorInfo attribute, IInputContext inputContext,
/* @InputConnectionInspector.missingMethods */ final int missingMethods,
int unverifiedTargetSdkVersion) {
- final InputBindResult result;
- if (windowToken != null) {
- result = windowGainedFocus(startInputReason, client, windowToken, controlFlags,
- softInputMode, windowFlags, attribute, inputContext, missingMethods,
- unverifiedTargetSdkVersion);
- } else {
- result = startInput(startInputReason, client, inputContext, missingMethods, attribute,
- controlFlags);
+ if (windowToken == null) {
+ Slog.e(TAG, "windowToken cannot be null.");
+ return InputBindResult.NULL;
}
+ final InputBindResult result = startInputOrWindowGainedFocusInternal(startInputReason,
+ client, windowToken, controlFlags, softInputMode, windowFlags, attribute,
+ inputContext, missingMethods, unverifiedTargetSdkVersion);
if (result == null) {
// This must never happen, but just in case.
Slog.wtf(TAG, "InputBindResult is @NonNull. startInputReason="
@@ -2762,9 +2705,9 @@
}
@NonNull
- private InputBindResult windowGainedFocus(
+ private InputBindResult startInputOrWindowGainedFocusInternal(
/* @InputMethodClient.StartInputReason */ final int startInputReason,
- IInputMethodClient client, IBinder windowToken, int controlFlags,
+ IInputMethodClient client, @NonNull IBinder windowToken, int controlFlags,
/* @android.view.WindowManager.LayoutParams.SoftInputModeFlags */ int softInputMode,
int windowFlags, EditorInfo attribute, IInputContext inputContext,
/* @InputConnectionInspector.missingMethods */ final int missingMethods,
@@ -2775,7 +2718,7 @@
long ident = Binder.clearCallingIdentity();
try {
synchronized (mMethodMap) {
- if (DEBUG) Slog.v(TAG, "windowGainedFocus: reason="
+ if (DEBUG) Slog.v(TAG, "startInputOrWindowGainedFocusInternal: reason="
+ InputMethodClient.getStartInputReason(startInputReason)
+ " client=" + client.asBinder()
+ " inputContext=" + inputContext
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index c5ab932..de02e81 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -153,6 +153,10 @@
// default background throttling interval if not overriden in settings
private static final long DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000;
+ // Default value for maximum age of last location returned to applications with foreground-only
+ // location permissions.
+ private static final long DEFAULT_LAST_LOCATION_MAX_AGE_MS = 20 * 60 * 1000;
+
// Location Providers may sometimes deliver location updates
// slightly faster that requested - provide grace period so
// we don't unnecessarily filter events that are otherwise on
@@ -241,6 +245,9 @@
private int mCurrentUserId = UserHandle.USER_SYSTEM;
private int[] mCurrentUserProfiles = new int[]{UserHandle.USER_SYSTEM};
+ // Maximum age of last location returned to clients with foreground-only location permissions.
+ private long mLastLocationMaxAgeMs;
+
private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
private GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
@@ -308,7 +315,8 @@
}
}
};
- mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null, callback);
+ mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null,
+ AppOpsManager.WATCH_FOREGROUND_CHANGES, callback);
PackageManager.OnPermissionsChangedListener permissionListener
= new PackageManager.OnPermissionsChangedListener() {
@@ -341,6 +349,7 @@
updateUserProfiles(mCurrentUserId);
updateBackgroundThrottlingWhitelistLocked();
+ updateLastLocationMaxAgeLocked();
// prepare providers
loadProvidersLocked();
@@ -370,6 +379,18 @@
}
}, UserHandle.USER_ALL);
mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS),
+ true,
+ new ContentObserver(mLocationHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ synchronized (mLock) {
+ updateLastLocationMaxAgeLocked();
+ }
+ }
+ }
+ );
+ mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(
Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST),
true,
@@ -382,6 +403,7 @@
}
}
}, UserHandle.USER_ALL);
+
mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
// listen for user change
@@ -841,6 +863,7 @@
for (String p : mUpdateRecords.keySet()) {
s.append(" ").append(mUpdateRecords.get(p).toString());
}
+ s.append(" monitoring location: ").append(mOpMonitoring);
s.append("]");
return s.toString();
}
@@ -913,7 +936,7 @@
}
} else {
if (!allowMonitoring
- || mAppOps.checkOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
+ || mAppOps.noteOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
!= AppOpsManager.MODE_ALLOWED) {
mAppOps.finishOp(op, mIdentity.mUid, mIdentity.mPackageName);
return false;
@@ -1541,7 +1564,7 @@
boolean checkLocationAccess(int pid, int uid, String packageName, int allowedResolutionLevel) {
int op = resolutionLevelToOp(allowedResolutionLevel);
if (op >= 0) {
- if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
+ if (mAppOps.noteOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
return false;
}
}
@@ -1857,6 +1880,14 @@
Arrays.asList(setting.split(",")));
}
+ private void updateLastLocationMaxAgeLocked() {
+ mLastLocationMaxAgeMs =
+ Settings.Global.getLong(
+ mContext.getContentResolver(),
+ Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS,
+ DEFAULT_LAST_LOCATION_MAX_AGE_MS);
+ }
+
private boolean isThrottlingExemptLocked(Identity identity) {
if (identity.mUid == Process.SYSTEM_UID) {
return true;
@@ -2262,6 +2293,17 @@
if (location == null) {
return null;
}
+
+ // Don't return stale location to apps with foreground-only location permission.
+ String op = getResolutionPermission(allowedResolutionLevel);
+ long locationAgeMs = SystemClock.elapsedRealtime() -
+ location.getElapsedRealtimeNanos() / NANOS_PER_MILLI;
+ if ((locationAgeMs > mLastLocationMaxAgeMs)
+ && (mAppOps.unsafeCheckOp(op, uid, packageName)
+ == AppOpsManager.MODE_FOREGROUND)) {
+ return null;
+ }
+
if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Location noGPSLocation = location.getExtraLocation(
Location.EXTRA_NO_GPS_LOCATION);
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java
index b3a8fb6..1ff455ea 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java
@@ -16,314 +16,15 @@
package com.android.server;
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.database.ContentObserver;
-import android.net.ConnectivityManager;
-import android.net.ConnectivityManager.NetworkCallback;
-import android.net.Network;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.SystemClock;
-import android.provider.Settings;
-import android.util.Log;
-import android.util.NtpTrustedTime;
-import android.util.TimeUtils;
-
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.util.DumpUtils;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
+import android.os.IBinder;
/**
- * Monitors the network time and updates the system time if it is out of sync
- * and there hasn't been any NITZ update from the carrier recently.
- * If looking up the network time fails for some reason, it tries a few times with a short
- * interval and then resets to checking on longer intervals.
- * <p>
- * If the user enables AUTO_TIME, it will check immediately for the network time, if NITZ wasn't
- * available.
- * </p>
+ * An interface for NetworkTimeUpdateService implementations. Eventually part or all of this service
+ * will be subsumed into {@link com.android.server.timedetector.TimeDetectorService}. In the
+ * meantime this interface allows Android to use either the old or new implementation.
*/
-public class NetworkTimeUpdateService extends Binder {
-
- private static final String TAG = "NetworkTimeUpdateService";
- private static final boolean DBG = false;
-
- private static final int EVENT_AUTO_TIME_CHANGED = 1;
- private static final int EVENT_POLL_NETWORK_TIME = 2;
- private static final int EVENT_NETWORK_CHANGED = 3;
-
- private static final String ACTION_POLL =
- "com.android.server.NetworkTimeUpdateService.action.POLL";
-
- private static final int POLL_REQUEST = 0;
-
- private static final long NOT_SET = -1;
- private long mNitzTimeSetTime = NOT_SET;
- private Network mDefaultNetwork = null;
-
- private final Context mContext;
- private final NtpTrustedTime mTime;
- private final AlarmManager mAlarmManager;
- private final ConnectivityManager mCM;
- private final PendingIntent mPendingPollIntent;
- private final PowerManager.WakeLock mWakeLock;
-
- // NTP lookup is done on this thread and handler
- private Handler mHandler;
- private SettingsObserver mSettingsObserver;
- private NetworkTimeUpdateCallback mNetworkTimeUpdateCallback;
-
- // Normal polling frequency
- private final long mPollingIntervalMs;
- // Try-again polling interval, in case the network request failed
- private final long mPollingIntervalShorterMs;
- // Number of times to try again
- private final int mTryAgainTimesMax;
- // If the time difference is greater than this threshold, then update the time.
- private final int mTimeErrorThresholdMs;
- // Keeps track of how many quick attempts were made to fetch NTP time.
- // During bootup, the network may not have been up yet, or it's taking time for the
- // connection to happen.
- private int mTryAgainCounter;
-
- public NetworkTimeUpdateService(Context context) {
- mContext = context;
- mTime = NtpTrustedTime.getInstance(context);
- mAlarmManager = mContext.getSystemService(AlarmManager.class);
- mCM = mContext.getSystemService(ConnectivityManager.class);
-
- Intent pollIntent = new Intent(ACTION_POLL, null);
- mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
-
- mPollingIntervalMs = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_ntpPollingInterval);
- mPollingIntervalShorterMs = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_ntpPollingIntervalShorter);
- mTryAgainTimesMax = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_ntpRetry);
- mTimeErrorThresholdMs = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_ntpThreshold);
-
- mWakeLock = context.getSystemService(PowerManager.class).newWakeLock(
- PowerManager.PARTIAL_WAKE_LOCK, TAG);
- }
+public interface NetworkTimeUpdateService extends IBinder {
/** Initialize the receivers and initiate the first NTP request */
- public void systemRunning() {
- registerForTelephonyIntents();
- registerForAlarms();
-
- HandlerThread thread = new HandlerThread(TAG);
- thread.start();
- mHandler = new MyHandler(thread.getLooper());
- mNetworkTimeUpdateCallback = new NetworkTimeUpdateCallback();
- mCM.registerDefaultNetworkCallback(mNetworkTimeUpdateCallback, mHandler);
-
- mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED);
- mSettingsObserver.observe(mContext);
- }
-
- private void registerForTelephonyIntents() {
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIME);
- mContext.registerReceiver(mNitzReceiver, intentFilter);
- }
-
- private void registerForAlarms() {
- mContext.registerReceiver(
- new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
- }
- }, new IntentFilter(ACTION_POLL));
- }
-
- private void onPollNetworkTime(int event) {
- // If Automatic time is not set, don't bother. Similarly, if we don't
- // have any default network, don't bother.
- if (mDefaultNetwork == null) return;
- mWakeLock.acquire();
- try {
- onPollNetworkTimeUnderWakeLock(event);
- } finally {
- mWakeLock.release();
- }
- }
-
- private void onPollNetworkTimeUnderWakeLock(int event) {
- // Force an NTP fix when outdated
- if (mTime.getCacheAge() >= mPollingIntervalMs) {
- if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh");
- mTime.forceRefresh();
- }
-
- if (mTime.getCacheAge() < mPollingIntervalMs) {
- // Obtained fresh fix; schedule next normal update
- resetAlarm(mPollingIntervalMs);
- if (isAutomaticTimeRequested()) {
- updateSystemClock(event);
- }
-
- } else {
- // No fresh fix; schedule retry
- mTryAgainCounter++;
- if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
- resetAlarm(mPollingIntervalShorterMs);
- } else {
- // Try much later
- mTryAgainCounter = 0;
- resetAlarm(mPollingIntervalMs);
- }
- }
- }
-
- private long getNitzAge() {
- if (mNitzTimeSetTime == NOT_SET) {
- return Long.MAX_VALUE;
- } else {
- return SystemClock.elapsedRealtime() - mNitzTimeSetTime;
- }
- }
-
- /**
- * Consider updating system clock based on current NTP fix, if requested by
- * user, significant enough delta, and we don't have a recent NITZ.
- */
- private void updateSystemClock(int event) {
- final boolean forceUpdate = (event == EVENT_AUTO_TIME_CHANGED);
- if (!forceUpdate) {
- if (getNitzAge() < mPollingIntervalMs) {
- if (DBG) Log.d(TAG, "Ignoring NTP update due to recent NITZ");
- return;
- }
-
- final long skew = Math.abs(mTime.currentTimeMillis() - System.currentTimeMillis());
- if (skew < mTimeErrorThresholdMs) {
- if (DBG) Log.d(TAG, "Ignoring NTP update due to low skew");
- return;
- }
- }
-
- SystemClock.setCurrentTimeMillis(mTime.currentTimeMillis());
- }
-
- /**
- * Cancel old alarm and starts a new one for the specified interval.
- *
- * @param interval when to trigger the alarm, starting from now.
- */
- private void resetAlarm(long interval) {
- mAlarmManager.cancel(mPendingPollIntent);
- long now = SystemClock.elapsedRealtime();
- long next = now + interval;
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent);
- }
-
- /**
- * Checks if the user prefers to automatically set the time.
- */
- private boolean isAutomaticTimeRequested() {
- return Settings.Global.getInt(
- mContext.getContentResolver(), Settings.Global.AUTO_TIME, 0) != 0;
- }
-
- /** Receiver for Nitz time events */
- private BroadcastReceiver mNitzReceiver = new BroadcastReceiver() {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (DBG) Log.d(TAG, "Received " + action);
- if (TelephonyIntents.ACTION_NETWORK_SET_TIME.equals(action)) {
- mNitzTimeSetTime = SystemClock.elapsedRealtime();
- }
- }
- };
-
- /** Handler to do the network accesses on */
- private class MyHandler extends Handler {
-
- public MyHandler(Looper l) {
- super(l);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case EVENT_AUTO_TIME_CHANGED:
- case EVENT_POLL_NETWORK_TIME:
- case EVENT_NETWORK_CHANGED:
- onPollNetworkTime(msg.what);
- break;
- }
- }
- }
-
- private class NetworkTimeUpdateCallback extends NetworkCallback {
- @Override
- public void onAvailable(Network network) {
- Log.d(TAG, String.format("New default network %s; checking time.", network));
- mDefaultNetwork = network;
- // Running on mHandler so invoke directly.
- onPollNetworkTime(EVENT_NETWORK_CHANGED);
- }
-
- @Override
- public void onLost(Network network) {
- if (network.equals(mDefaultNetwork)) mDefaultNetwork = null;
- }
- }
-
- /** Observer to watch for changes to the AUTO_TIME setting */
- private static class SettingsObserver extends ContentObserver {
-
- private int mMsg;
- private Handler mHandler;
-
- SettingsObserver(Handler handler, int msg) {
- super(handler);
- mHandler = handler;
- mMsg = msg;
- }
-
- void observe(Context context) {
- ContentResolver resolver = context.getContentResolver();
- resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME),
- false, this);
- }
-
- @Override
- public void onChange(boolean selfChange) {
- mHandler.obtainMessage(mMsg).sendToTarget();
- }
- }
-
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
- pw.print("PollingIntervalMs: ");
- TimeUtils.formatDuration(mPollingIntervalMs, pw);
- pw.print("\nPollingIntervalShorterMs: ");
- TimeUtils.formatDuration(mPollingIntervalShorterMs, pw);
- pw.println("\nTryAgainTimesMax: " + mTryAgainTimesMax);
- pw.print("TimeErrorThresholdMs: ");
- TimeUtils.formatDuration(mTimeErrorThresholdMs, pw);
- pw.println("\nTryAgainCounter: " + mTryAgainCounter);
- pw.println("NTP cache age: " + mTime.getCacheAge());
- pw.println("NTP cache certainty: " + mTime.getCacheCertainty());
- pw.println();
- }
+ void systemRunning();
}
diff --git a/services/core/java/com/android/server/NewNetworkTimeUpdateService.java b/services/core/java/com/android/server/NewNetworkTimeUpdateService.java
new file mode 100644
index 0000000..d21741a
--- /dev/null
+++ b/services/core/java/com/android/server/NewNetworkTimeUpdateService.java
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2010 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;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.Network;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.provider.Settings;
+import android.util.Log;
+import android.util.NtpTrustedTime;
+import android.util.TimeUtils;
+
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.util.DumpUtils;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Monitors the network time and updates the system time if it is out of sync
+ * and there hasn't been any NITZ update from the carrier recently.
+ * If looking up the network time fails for some reason, it tries a few times with a short
+ * interval and then resets to checking on longer intervals.
+ * <p>
+ * If the user enables AUTO_TIME, it will check immediately for the network time, if NITZ wasn't
+ * available.
+ * </p>
+ */
+public class NewNetworkTimeUpdateService extends Binder implements NetworkTimeUpdateService {
+
+ private static final String TAG = "NetworkTimeUpdateService";
+ private static final boolean DBG = false;
+
+ private static final int EVENT_AUTO_TIME_CHANGED = 1;
+ private static final int EVENT_POLL_NETWORK_TIME = 2;
+ private static final int EVENT_NETWORK_CHANGED = 3;
+
+ private static final String ACTION_POLL =
+ "com.android.server.NetworkTimeUpdateService.action.POLL";
+
+ private static final int POLL_REQUEST = 0;
+
+ private static final long NOT_SET = -1;
+ private long mNitzTimeSetTime = NOT_SET;
+ private Network mDefaultNetwork = null;
+
+ private final Context mContext;
+ private final NtpTrustedTime mTime;
+ private final AlarmManager mAlarmManager;
+ private final ConnectivityManager mCM;
+ private final PendingIntent mPendingPollIntent;
+ private final PowerManager.WakeLock mWakeLock;
+
+ // NTP lookup is done on this thread and handler
+ private Handler mHandler;
+ private SettingsObserver mSettingsObserver;
+ private NetworkTimeUpdateCallback mNetworkTimeUpdateCallback;
+
+ // Normal polling frequency
+ private final long mPollingIntervalMs;
+ // Try-again polling interval, in case the network request failed
+ private final long mPollingIntervalShorterMs;
+ // Number of times to try again
+ private final int mTryAgainTimesMax;
+ // If the time difference is greater than this threshold, then update the time.
+ private final int mTimeErrorThresholdMs;
+ // Keeps track of how many quick attempts were made to fetch NTP time.
+ // During bootup, the network may not have been up yet, or it's taking time for the
+ // connection to happen.
+ private int mTryAgainCounter;
+
+ public NewNetworkTimeUpdateService(Context context) {
+ mContext = context;
+ mTime = NtpTrustedTime.getInstance(context);
+ mAlarmManager = mContext.getSystemService(AlarmManager.class);
+ mCM = mContext.getSystemService(ConnectivityManager.class);
+
+ Intent pollIntent = new Intent(ACTION_POLL, null);
+ mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
+
+ mPollingIntervalMs = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_ntpPollingInterval);
+ mPollingIntervalShorterMs = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_ntpPollingIntervalShorter);
+ mTryAgainTimesMax = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_ntpRetry);
+ mTimeErrorThresholdMs = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_ntpThreshold);
+
+ mWakeLock = context.getSystemService(PowerManager.class).newWakeLock(
+ PowerManager.PARTIAL_WAKE_LOCK, TAG);
+ }
+
+ @Override
+ public void systemRunning() {
+ registerForTelephonyIntents();
+ registerForAlarms();
+
+ HandlerThread thread = new HandlerThread(TAG);
+ thread.start();
+ mHandler = new MyHandler(thread.getLooper());
+ mNetworkTimeUpdateCallback = new NetworkTimeUpdateCallback();
+ mCM.registerDefaultNetworkCallback(mNetworkTimeUpdateCallback, mHandler);
+
+ mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED);
+ mSettingsObserver.observe(mContext);
+ }
+
+ private void registerForTelephonyIntents() {
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIME);
+ mContext.registerReceiver(mNitzReceiver, intentFilter);
+ }
+
+ private void registerForAlarms() {
+ mContext.registerReceiver(
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
+ }
+ }, new IntentFilter(ACTION_POLL));
+ }
+
+ private void onPollNetworkTime(int event) {
+ // If Automatic time is not set, don't bother. Similarly, if we don't
+ // have any default network, don't bother.
+ if (mDefaultNetwork == null) return;
+ mWakeLock.acquire();
+ try {
+ onPollNetworkTimeUnderWakeLock(event);
+ } finally {
+ mWakeLock.release();
+ }
+ }
+
+ private void onPollNetworkTimeUnderWakeLock(int event) {
+ // Force an NTP fix when outdated
+ if (mTime.getCacheAge() >= mPollingIntervalMs) {
+ if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh");
+ mTime.forceRefresh();
+ }
+
+ if (mTime.getCacheAge() < mPollingIntervalMs) {
+ // Obtained fresh fix; schedule next normal update
+ resetAlarm(mPollingIntervalMs);
+ if (isAutomaticTimeRequested()) {
+ updateSystemClock(event);
+ }
+
+ } else {
+ // No fresh fix; schedule retry
+ mTryAgainCounter++;
+ if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
+ resetAlarm(mPollingIntervalShorterMs);
+ } else {
+ // Try much later
+ mTryAgainCounter = 0;
+ resetAlarm(mPollingIntervalMs);
+ }
+ }
+ }
+
+ private long getNitzAge() {
+ if (mNitzTimeSetTime == NOT_SET) {
+ return Long.MAX_VALUE;
+ } else {
+ return SystemClock.elapsedRealtime() - mNitzTimeSetTime;
+ }
+ }
+
+ /**
+ * Consider updating system clock based on current NTP fix, if requested by
+ * user, significant enough delta, and we don't have a recent NITZ.
+ */
+ private void updateSystemClock(int event) {
+ final boolean forceUpdate = (event == EVENT_AUTO_TIME_CHANGED);
+ if (!forceUpdate) {
+ if (getNitzAge() < mPollingIntervalMs) {
+ if (DBG) Log.d(TAG, "Ignoring NTP update due to recent NITZ");
+ return;
+ }
+
+ final long skew = Math.abs(mTime.currentTimeMillis() - System.currentTimeMillis());
+ if (skew < mTimeErrorThresholdMs) {
+ if (DBG) Log.d(TAG, "Ignoring NTP update due to low skew");
+ return;
+ }
+ }
+
+ SystemClock.setCurrentTimeMillis(mTime.currentTimeMillis());
+ }
+
+ /**
+ * Cancel old alarm and starts a new one for the specified interval.
+ *
+ * @param interval when to trigger the alarm, starting from now.
+ */
+ private void resetAlarm(long interval) {
+ mAlarmManager.cancel(mPendingPollIntent);
+ long now = SystemClock.elapsedRealtime();
+ long next = now + interval;
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent);
+ }
+
+ /**
+ * Checks if the user prefers to automatically set the time.
+ */
+ private boolean isAutomaticTimeRequested() {
+ return Settings.Global.getInt(
+ mContext.getContentResolver(), Settings.Global.AUTO_TIME, 0) != 0;
+ }
+
+ /** Receiver for Nitz time events */
+ private BroadcastReceiver mNitzReceiver = new BroadcastReceiver() {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (DBG) Log.d(TAG, "Received " + action);
+ if (TelephonyIntents.ACTION_NETWORK_SET_TIME.equals(action)) {
+ mNitzTimeSetTime = SystemClock.elapsedRealtime();
+ }
+ }
+ };
+
+ /** Handler to do the network accesses on */
+ private class MyHandler extends Handler {
+
+ public MyHandler(Looper l) {
+ super(l);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case EVENT_AUTO_TIME_CHANGED:
+ case EVENT_POLL_NETWORK_TIME:
+ case EVENT_NETWORK_CHANGED:
+ onPollNetworkTime(msg.what);
+ break;
+ }
+ }
+ }
+
+ private class NetworkTimeUpdateCallback extends NetworkCallback {
+ @Override
+ public void onAvailable(Network network) {
+ Log.d(TAG, String.format("New default network %s; checking time.", network));
+ mDefaultNetwork = network;
+ // Running on mHandler so invoke directly.
+ onPollNetworkTime(EVENT_NETWORK_CHANGED);
+ }
+
+ @Override
+ public void onLost(Network network) {
+ if (network.equals(mDefaultNetwork)) mDefaultNetwork = null;
+ }
+ }
+
+ /** Observer to watch for changes to the AUTO_TIME setting */
+ private static class SettingsObserver extends ContentObserver {
+
+ private int mMsg;
+ private Handler mHandler;
+
+ SettingsObserver(Handler handler, int msg) {
+ super(handler);
+ mHandler = handler;
+ mMsg = msg;
+ }
+
+ void observe(Context context) {
+ ContentResolver resolver = context.getContentResolver();
+ resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME),
+ false, this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ mHandler.obtainMessage(mMsg).sendToTarget();
+ }
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+ pw.print("PollingIntervalMs: ");
+ TimeUtils.formatDuration(mPollingIntervalMs, pw);
+ pw.print("\nPollingIntervalShorterMs: ");
+ TimeUtils.formatDuration(mPollingIntervalShorterMs, pw);
+ pw.println("\nTryAgainTimesMax: " + mTryAgainTimesMax);
+ pw.print("TimeErrorThresholdMs: ");
+ TimeUtils.formatDuration(mTimeErrorThresholdMs, pw);
+ pw.println("\nTryAgainCounter: " + mTryAgainCounter);
+ pw.println("NTP cache age: " + mTime.getCacheAge());
+ pw.println("NTP cache certainty: " + mTime.getCacheCertainty());
+ pw.println();
+ }
+}
diff --git a/services/core/java/com/android/server/OldNetworkTimeUpdateService.java b/services/core/java/com/android/server/OldNetworkTimeUpdateService.java
new file mode 100644
index 0000000..068b83d
--- /dev/null
+++ b/services/core/java/com/android/server/OldNetworkTimeUpdateService.java
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2010 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;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.Network;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.provider.Settings;
+import android.util.Log;
+import android.util.NtpTrustedTime;
+import android.util.TimeUtils;
+
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.util.DumpUtils;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Monitors the network time and updates the system time if it is out of sync
+ * and there hasn't been any NITZ update from the carrier recently.
+ * If looking up the network time fails for some reason, it tries a few times with a short
+ * interval and then resets to checking on longer intervals.
+ * <p>
+ * If the user enables AUTO_TIME, it will check immediately for the network time, if NITZ wasn't
+ * available.
+ * </p>
+ */
+public class OldNetworkTimeUpdateService extends Binder implements NetworkTimeUpdateService {
+
+ private static final String TAG = "NetworkTimeUpdateService";
+ private static final boolean DBG = false;
+
+ private static final int EVENT_AUTO_TIME_CHANGED = 1;
+ private static final int EVENT_POLL_NETWORK_TIME = 2;
+ private static final int EVENT_NETWORK_CHANGED = 3;
+
+ private static final String ACTION_POLL =
+ "com.android.server.NetworkTimeUpdateService.action.POLL";
+
+ private static final int POLL_REQUEST = 0;
+
+ private static final long NOT_SET = -1;
+ private long mNitzTimeSetTime = NOT_SET;
+ private Network mDefaultNetwork = null;
+
+ private final Context mContext;
+ private final NtpTrustedTime mTime;
+ private final AlarmManager mAlarmManager;
+ private final ConnectivityManager mCM;
+ private final PendingIntent mPendingPollIntent;
+ private final PowerManager.WakeLock mWakeLock;
+
+ // NTP lookup is done on this thread and handler
+ private Handler mHandler;
+ private SettingsObserver mSettingsObserver;
+ private NetworkTimeUpdateCallback mNetworkTimeUpdateCallback;
+
+ // Normal polling frequency
+ private final long mPollingIntervalMs;
+ // Try-again polling interval, in case the network request failed
+ private final long mPollingIntervalShorterMs;
+ // Number of times to try again
+ private final int mTryAgainTimesMax;
+ // If the time difference is greater than this threshold, then update the time.
+ private final int mTimeErrorThresholdMs;
+ // Keeps track of how many quick attempts were made to fetch NTP time.
+ // During bootup, the network may not have been up yet, or it's taking time for the
+ // connection to happen.
+ private int mTryAgainCounter;
+
+ public OldNetworkTimeUpdateService(Context context) {
+ mContext = context;
+ mTime = NtpTrustedTime.getInstance(context);
+ mAlarmManager = mContext.getSystemService(AlarmManager.class);
+ mCM = mContext.getSystemService(ConnectivityManager.class);
+
+ Intent pollIntent = new Intent(ACTION_POLL, null);
+ mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
+
+ mPollingIntervalMs = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_ntpPollingInterval);
+ mPollingIntervalShorterMs = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_ntpPollingIntervalShorter);
+ mTryAgainTimesMax = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_ntpRetry);
+ mTimeErrorThresholdMs = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_ntpThreshold);
+
+ mWakeLock = context.getSystemService(PowerManager.class).newWakeLock(
+ PowerManager.PARTIAL_WAKE_LOCK, TAG);
+ }
+
+ @Override
+ public void systemRunning() {
+ registerForTelephonyIntents();
+ registerForAlarms();
+
+ HandlerThread thread = new HandlerThread(TAG);
+ thread.start();
+ mHandler = new MyHandler(thread.getLooper());
+ mNetworkTimeUpdateCallback = new NetworkTimeUpdateCallback();
+ mCM.registerDefaultNetworkCallback(mNetworkTimeUpdateCallback, mHandler);
+
+ mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED);
+ mSettingsObserver.observe(mContext);
+ }
+
+ private void registerForTelephonyIntents() {
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIME);
+ mContext.registerReceiver(mNitzReceiver, intentFilter);
+ }
+
+ private void registerForAlarms() {
+ mContext.registerReceiver(
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
+ }
+ }, new IntentFilter(ACTION_POLL));
+ }
+
+ private void onPollNetworkTime(int event) {
+ // If Automatic time is not set, don't bother. Similarly, if we don't
+ // have any default network, don't bother.
+ if (mDefaultNetwork == null) return;
+ mWakeLock.acquire();
+ try {
+ onPollNetworkTimeUnderWakeLock(event);
+ } finally {
+ mWakeLock.release();
+ }
+ }
+
+ private void onPollNetworkTimeUnderWakeLock(int event) {
+ // Force an NTP fix when outdated
+ if (mTime.getCacheAge() >= mPollingIntervalMs) {
+ if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh");
+ mTime.forceRefresh();
+ }
+
+ if (mTime.getCacheAge() < mPollingIntervalMs) {
+ // Obtained fresh fix; schedule next normal update
+ resetAlarm(mPollingIntervalMs);
+ if (isAutomaticTimeRequested()) {
+ updateSystemClock(event);
+ }
+
+ } else {
+ // No fresh fix; schedule retry
+ mTryAgainCounter++;
+ if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
+ resetAlarm(mPollingIntervalShorterMs);
+ } else {
+ // Try much later
+ mTryAgainCounter = 0;
+ resetAlarm(mPollingIntervalMs);
+ }
+ }
+ }
+
+ private long getNitzAge() {
+ if (mNitzTimeSetTime == NOT_SET) {
+ return Long.MAX_VALUE;
+ } else {
+ return SystemClock.elapsedRealtime() - mNitzTimeSetTime;
+ }
+ }
+
+ /**
+ * Consider updating system clock based on current NTP fix, if requested by
+ * user, significant enough delta, and we don't have a recent NITZ.
+ */
+ private void updateSystemClock(int event) {
+ final boolean forceUpdate = (event == EVENT_AUTO_TIME_CHANGED);
+ if (!forceUpdate) {
+ if (getNitzAge() < mPollingIntervalMs) {
+ if (DBG) Log.d(TAG, "Ignoring NTP update due to recent NITZ");
+ return;
+ }
+
+ final long skew = Math.abs(mTime.currentTimeMillis() - System.currentTimeMillis());
+ if (skew < mTimeErrorThresholdMs) {
+ if (DBG) Log.d(TAG, "Ignoring NTP update due to low skew");
+ return;
+ }
+ }
+
+ SystemClock.setCurrentTimeMillis(mTime.currentTimeMillis());
+ }
+
+ /**
+ * Cancel old alarm and starts a new one for the specified interval.
+ *
+ * @param interval when to trigger the alarm, starting from now.
+ */
+ private void resetAlarm(long interval) {
+ mAlarmManager.cancel(mPendingPollIntent);
+ long now = SystemClock.elapsedRealtime();
+ long next = now + interval;
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent);
+ }
+
+ /**
+ * Checks if the user prefers to automatically set the time.
+ */
+ private boolean isAutomaticTimeRequested() {
+ return Settings.Global.getInt(
+ mContext.getContentResolver(), Settings.Global.AUTO_TIME, 0) != 0;
+ }
+
+ /** Receiver for Nitz time events */
+ private BroadcastReceiver mNitzReceiver = new BroadcastReceiver() {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (DBG) Log.d(TAG, "Received " + action);
+ if (TelephonyIntents.ACTION_NETWORK_SET_TIME.equals(action)) {
+ mNitzTimeSetTime = SystemClock.elapsedRealtime();
+ }
+ }
+ };
+
+ /** Handler to do the network accesses on */
+ private class MyHandler extends Handler {
+
+ public MyHandler(Looper l) {
+ super(l);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case EVENT_AUTO_TIME_CHANGED:
+ case EVENT_POLL_NETWORK_TIME:
+ case EVENT_NETWORK_CHANGED:
+ onPollNetworkTime(msg.what);
+ break;
+ }
+ }
+ }
+
+ private class NetworkTimeUpdateCallback extends NetworkCallback {
+ @Override
+ public void onAvailable(Network network) {
+ Log.d(TAG, String.format("New default network %s; checking time.", network));
+ mDefaultNetwork = network;
+ // Running on mHandler so invoke directly.
+ onPollNetworkTime(EVENT_NETWORK_CHANGED);
+ }
+
+ @Override
+ public void onLost(Network network) {
+ if (network.equals(mDefaultNetwork)) mDefaultNetwork = null;
+ }
+ }
+
+ /** Observer to watch for changes to the AUTO_TIME setting */
+ private static class SettingsObserver extends ContentObserver {
+
+ private int mMsg;
+ private Handler mHandler;
+
+ SettingsObserver(Handler handler, int msg) {
+ super(handler);
+ mHandler = handler;
+ mMsg = msg;
+ }
+
+ void observe(Context context) {
+ ContentResolver resolver = context.getContentResolver();
+ resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME),
+ false, this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ mHandler.obtainMessage(mMsg).sendToTarget();
+ }
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+ pw.print("PollingIntervalMs: ");
+ TimeUtils.formatDuration(mPollingIntervalMs, pw);
+ pw.print("\nPollingIntervalShorterMs: ");
+ TimeUtils.formatDuration(mPollingIntervalShorterMs, pw);
+ pw.println("\nTryAgainTimesMax: " + mTryAgainTimesMax);
+ pw.print("TimeErrorThresholdMs: ");
+ TimeUtils.formatDuration(mTimeErrorThresholdMs, pw);
+ pw.println("\nTryAgainCounter: " + mTryAgainCounter);
+ pw.println("NTP cache age: " + mTime.getCacheAge());
+ pw.println("NTP cache certainty: " + mTime.getCacheCertainty());
+ pw.println();
+ }
+}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index d025a87..92005d2 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -24,23 +24,18 @@
import static android.os.storage.OnObbStateChangeListener.ERROR_PERMISSION_DENIED;
import static android.os.storage.OnObbStateChangeListener.MOUNTED;
import static android.os.storage.OnObbStateChangeListener.UNMOUNTED;
-
import static com.android.internal.util.XmlUtils.readIntAttribute;
import static com.android.internal.util.XmlUtils.readLongAttribute;
import static com.android.internal.util.XmlUtils.readStringAttribute;
import static com.android.internal.util.XmlUtils.writeIntAttribute;
import static com.android.internal.util.XmlUtils.writeLongAttribute;
import static com.android.internal.util.XmlUtils.writeStringAttribute;
-
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
import android.Manifest;
import android.annotation.Nullable;
import android.app.ActivityManager;
-import android.app.ActivityManagerInternal;
-import android.app.ActivityTaskManagerInternal;
-import android.app.ActivityTaskManagerInternal.ScreenObserver;
import android.app.AppOpsManager;
import android.app.IActivityManager;
import android.app.KeyguardManager;
@@ -126,9 +121,8 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.server.pm.PackageManagerService;
import com.android.server.storage.AppFuseBridge;
-
-import libcore.io.IoUtils;
-import libcore.util.EmptyArray;
+import com.android.server.wm.ActivityTaskManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal.ScreenObserver;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -164,6 +158,9 @@
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
+import libcore.io.IoUtils;
+import libcore.util.EmptyArray;
+
/**
* Service responsible for various storage media. Connects to {@code vold} to
* watch for and manage dynamically added storage, such as SD cards and USB mass
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 607db4e..ad9fa40 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1588,10 +1588,10 @@
// Wakeup apps for the (SUBSCRIPTION_)PHONE_STATE broadcast.
intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+ // Create a version of the intent with the number always populated.
Intent intentWithPhoneNumber = new Intent(intent);
- if (!TextUtils.isEmpty(incomingNumber)) {
- intentWithPhoneNumber.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber);
- }
+ intentWithPhoneNumber.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber);
+
// Send broadcast twice, once for apps that have PRIVILEGED permission and once for those
// that have the runtime one
mContext.sendBroadcastAsUser(intentWithPhoneNumber, UserHandle.ALL,
diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java
index 0941bc8..c043e18 100644
--- a/services/core/java/com/android/server/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/TextServicesManagerService.java
@@ -63,6 +63,7 @@
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.HashMap;
@@ -1024,19 +1025,46 @@
private static final class ISpellCheckerServiceCallbackBinder
extends ISpellCheckerServiceCallback.Stub {
@NonNull
- private final SpellCheckerBindGroup mBindGroup;
- @NonNull
- private final SessionRequest mRequest;
+ private final Object mCallbackLock = new Object();
- ISpellCheckerServiceCallbackBinder(@NonNull final SpellCheckerBindGroup bindGroup,
- @NonNull final SessionRequest request) {
- mBindGroup = bindGroup;
- mRequest = request;
+ @GuardedBy("mCallbackLock")
+ @Nullable
+ private WeakReference<SpellCheckerBindGroup> mBindGroup;
+
+ /**
+ * Original {@link SessionRequest} that is associated with this callback.
+ *
+ * <p>Note that {@link SpellCheckerBindGroup#mOnGoingSessionRequests} guarantees that this
+ * {@link SessionRequest} object is kept alive until the request is canceled.</p>
+ */
+ @GuardedBy("mCallbackLock")
+ @Nullable
+ private WeakReference<SessionRequest> mRequest;
+
+ ISpellCheckerServiceCallbackBinder(@NonNull SpellCheckerBindGroup bindGroup,
+ @NonNull SessionRequest request) {
+ synchronized (mCallbackLock) {
+ mBindGroup = new WeakReference<>(bindGroup);
+ mRequest = new WeakReference<>(request);
+ }
}
@Override
public void onSessionCreated(@Nullable ISpellCheckerSession newSession) {
- mBindGroup.onSessionCreated(newSession, mRequest);
+ final SpellCheckerBindGroup group;
+ final SessionRequest request;
+ synchronized (mCallbackLock) {
+ if (mBindGroup == null || mRequest == null) {
+ return;
+ }
+ group = mBindGroup.get();
+ request = mRequest.get();
+ mBindGroup = null;
+ mRequest = null;
+ }
+ if (group != null && request != null) {
+ group.onSessionCreated(newSession, request);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index ca715b5..f7cd5ad 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -24,7 +24,6 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
@@ -32,6 +31,7 @@
import java.util.Set;
import java.util.function.Predicate;
+import android.app.ActivityManagerInternal;
import android.app.ActivityThread;
import android.app.AppOpsManager;
import android.app.NotificationManager;
@@ -59,7 +59,6 @@
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.TransferPipe;
-import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.server.AppStateTracker;
@@ -1390,7 +1389,7 @@
private boolean updateServiceClientActivitiesLocked(ProcessRecord proc,
ConnectionRecord modCr, boolean updateLru) {
if (modCr != null && modCr.binding.client != null) {
- if (modCr.binding.client.activities.size() <= 0) {
+ if (!modCr.binding.client.hasActivities()) {
// This connection is from a client without activities, so adding
// and removing is not interesting.
return false;
@@ -1408,7 +1407,7 @@
// Binding to ourself is not interesting.
continue;
}
- if (cr.binding.client.activities.size() > 0) {
+ if (cr.binding.client.hasActivities()) {
anyClientActivities = true;
break;
}
@@ -1869,7 +1868,7 @@
+ " type=" + resolvedType + " callingUid=" + callingUid);
userId = mAm.mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
- ActivityManagerService.ALLOW_NON_FULL_IN_PROFILE, "service", null);
+ ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE, "service", null);
ServiceMap smap = getServiceMapLocked(userId);
final ComponentName comp = service.getComponent();
@@ -2082,7 +2081,7 @@
bumpServiceExecutingLocked(r, execInFg, "bind");
r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
- r.app.repProcState);
+ r.app.getReportedProcState());
if (!rebind) {
i.requested = true;
}
@@ -2464,7 +2463,7 @@
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
- app.repProcState);
+ app.getReportedProcState());
r.postNotification();
created = true;
} catch (DeadObjectException e) {
@@ -3051,7 +3050,7 @@
}
}
if (finishing) {
- if (r.app != null && !r.app.persistent) {
+ if (r.app != null && !r.app.isPersistent()) {
r.app.services.remove(r);
if (r.whitelistManager) {
updateWhitelistManagerLocked(r.app);
@@ -3141,7 +3140,7 @@
&& (filterByClasses == null
|| filterByClasses.contains(service.name.getClassName())));
if (sameComponent
- && (service.app == null || evenPersistent || !service.app.persistent)) {
+ && (service.app == null || evenPersistent || !service.app.isPersistent())) {
if (!doit) {
return true;
}
@@ -3149,7 +3148,7 @@
Slog.i(TAG, " Force stopping service " + service);
if (service.app != null) {
service.app.removed = killProcess;
- if (!service.app.persistent) {
+ if (!service.app.isPersistent()) {
service.app.services.remove(service);
if (service.whitelistManager) {
updateWhitelistManagerLocked(service.app);
@@ -3303,7 +3302,7 @@
synchronized (sr.stats.getBatteryStats()) {
sr.stats.stopLaunchedLocked();
}
- if (sr.app != app && sr.app != null && !sr.app.persistent) {
+ if (sr.app != app && sr.app != null && !sr.app.isPersistent()) {
sr.app.services.remove(sr);
}
sr.app = null;
@@ -3348,7 +3347,7 @@
continue;
}
// XXX turned off for now until we have more time to get a better policy.
- if (false && proc != null && !proc.persistent && proc.thread != null
+ if (false && proc != null && !proc.isPersistent() && proc.thread != null
&& proc.pid != 0 && proc.pid != ActivityManagerService.MY_PID
&& proc.setProcState >= ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
proc.kill("bound to service " + sr.name.flattenToShortString()
@@ -3366,7 +3365,7 @@
// Unless the process is persistent, this process record is going away,
// so make sure the service is cleaned out of it.
- if (!app.persistent) {
+ if (!app.isPersistent()) {
app.services.removeAt(i);
}
@@ -3476,7 +3475,7 @@
if (r.app != null && r.app.pid == ActivityManagerService.MY_PID) {
info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
}
- if (r.app != null && r.app.persistent) {
+ if (r.app != null && r.app.isPersistent()) {
info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
}
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index ee93fc8..9f9fe4c 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -30,28 +30,29 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.FLAG_PRIVATE;
import static android.view.Display.REMOVE_MODE_DESTROY_CONTENT;
+import static com.android.server.am.ActivityDisplayProto.CONFIGURATION_CONTAINER;
+import static com.android.server.am.ActivityDisplayProto.ID;
+import static com.android.server.am.ActivityDisplayProto.STACKS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.am.ActivityDisplayProto.CONFIGURATION_CONTAINER;
-import static com.android.server.am.ActivityDisplayProto.STACKS;
-import static com.android.server.am.ActivityDisplayProto.ID;
import android.annotation.Nullable;
import android.app.ActivityOptions;
-import android.app.ActivityTaskManagerInternal;
import android.app.WindowConfiguration;
import android.graphics.Point;
import android.util.IntArray;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
+
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.ConfigurationContainer;
import com.android.server.wm.DisplayWindowController;
-
import com.android.server.wm.WindowContainerListener;
+
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -300,7 +301,7 @@
}
}
- final ActivityManagerService service = mSupervisor.mService.mAm;
+ final ActivityTaskManagerService service = mSupervisor.mService;
if (!isWindowingModeSupported(windowingMode, service.mSupportsMultiWindow,
service.mSupportsSplitScreenMultiWindow, service.mSupportsFreeformWindowManagement,
service.mSupportsPictureInPicture, activityType)) {
@@ -536,7 +537,7 @@
}
// Make sure the windowing mode we are trying to use makes sense for what is supported.
- final ActivityManagerService service = mSupervisor.mService.mAm;
+ final ActivityTaskManagerService service = mSupervisor.mService;
boolean supportsMultiWindow = service.mSupportsMultiWindow;
boolean supportsSplitScreen = service.mSupportsSplitScreenMultiWindow;
boolean supportsFreeform = service.mSupportsFreeformWindowManagement;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ac4f6ab..89810f9 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -22,19 +22,16 @@
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
import static android.Manifest.permission.REMOVE_TASKS;
-import static android.Manifest.permission.STOP_APP_SWITCHES;
+import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
+import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
+import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
+import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
import static android.app.ActivityThread.PROC_START_SEQ_IDENT;
import static android.app.AppOpsManager.OP_NONE;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
import static android.content.pm.ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT;
-import static android.content.pm.PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS;
-import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
-import static android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY;
-import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
import static android.content.pm.PackageManager.GET_PROVIDERS;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
@@ -43,10 +40,8 @@
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.content.res.Configuration.UI_MODE_TYPE_TELEVISION;
import static android.net.NetworkPolicyManager.isProcStateAllowedWhileIdleOrPowerSaveMode;
import static android.net.NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground;
-import static android.os.Build.VERSION_CODES.N;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
@@ -68,7 +63,6 @@
import static android.os.Process.SCHED_RESET_ON_FORK;
import static android.os.Process.SE_UID;
import static android.os.Process.SHELL_UID;
-import static android.os.Process.SIGNAL_QUIT;
import static android.os.Process.SIGNAL_USR1;
import static android.os.Process.SYSTEM_UID;
import static android.os.Process.THREAD_GROUP_BG_NONINTERACTIVE;
@@ -95,16 +89,12 @@
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
import static android.provider.Settings.Global.DEBUG_APP;
-import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
-import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
-import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RTL;
import static android.provider.Settings.Global.HIDE_ERROR_DIALOGS;
import static android.provider.Settings.Global.NETWORK_ACCESS_TIMEOUT_MS;
import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER;
import static android.provider.Settings.System.FONT_SCALE;
import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.Display.INVALID_DISPLAY;
import static com.android.internal.util.XmlUtils.readBooleanAttribute;
import static com.android.internal.util.XmlUtils.readIntAttribute;
import static com.android.internal.util.XmlUtils.readLongAttribute;
@@ -120,7 +110,6 @@
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_LIGHT;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CLEANUP;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_IMMERSIVE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LRU;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
@@ -134,9 +123,7 @@
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROVIDER;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_URI_PERMISSION;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USAGE_STATS;
@@ -145,8 +132,6 @@
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BROADCAST;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CLEANUP;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_FOCUS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_IMMERSIVE;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LRU;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU;
@@ -157,22 +142,15 @@
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROCESS_OBSERVERS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROVIDER;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PSS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SERVICE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_UID_OBSERVERS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_URI_PERMISSION;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
-import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
import static com.android.server.am.MemoryStatUtil.hasMemcg;
-import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
-import static android.view.WindowManager.TRANSIT_NONE;
-import static android.view.WindowManager.TRANSIT_TASK_OPEN;
-import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
+import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
@@ -185,13 +163,9 @@
import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.StackInfo;
-import android.app.ActivityManager.TaskSnapshot;
import android.app.ActivityManagerInternal;
-import android.app.ActivityTaskManagerInternal.ScreenObserver;
-import android.app.ActivityTaskManagerInternal.SleepToken;
import android.app.ActivityManagerProto;
import android.app.ActivityOptions;
-import android.app.ActivityTaskManager;
import android.app.ActivityThread;
import android.app.AlertDialog;
import android.app.AppGlobals;
@@ -224,7 +198,6 @@
import android.app.WindowConfiguration.ActivityType;
import android.app.WindowConfiguration.WindowingMode;
import android.app.backup.IBackupManager;
-import android.app.servertransaction.ConfigurationChangeItem;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManagerInternal;
import android.appwidget.AppWidgetManager;
@@ -279,7 +252,6 @@
import android.os.DropBoxManager;
import android.os.Environment;
import android.os.FactoryTest;
-import android.os.FileObserver;
import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
@@ -287,7 +259,6 @@
import android.os.IPermissionController;
import android.os.IProcessInfoService;
import android.os.IProgressListener;
-import android.os.LocaleList;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
@@ -307,7 +278,6 @@
import android.os.SystemProperties;
import android.os.Trace;
import android.os.TransactionTooLargeException;
-import android.os.UpdateLock;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.WorkSource;
@@ -319,7 +289,6 @@
import android.service.voice.IVoiceInteractionSession;
import android.text.TextUtils;
import android.text.format.DateUtils;
-import android.text.format.Time;
import android.text.style.SuggestionSpan;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -346,6 +315,9 @@
import android.view.WindowManager;
import android.view.autofill.AutofillManagerInternal;
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -390,17 +362,17 @@
import com.android.server.SystemServiceManager;
import com.android.server.ThreadPriorityBooster;
import com.android.server.Watchdog;
-import com.android.server.am.ActivityStack.ActivityState;
-import com.android.server.am.MemoryStatUtil.MemoryStat;
-import com.android.server.am.ActivityManagerServiceProto;
import com.android.server.am.ActivityManagerServiceDumpActivitiesProto;
import com.android.server.am.ActivityManagerServiceDumpBroadcastsProto;
import com.android.server.am.ActivityManagerServiceDumpProcessesProto;
import com.android.server.am.ActivityManagerServiceDumpProcessesProto.UidObserverRegistrationProto;
import com.android.server.am.ActivityManagerServiceDumpServicesProto;
+import com.android.server.am.ActivityManagerServiceProto;
+import com.android.server.am.ActivityStack.ActivityState;
import com.android.server.am.GrantUriProto;
import com.android.server.am.ImportanceTokenProto;
import com.android.server.am.MemInfoDumpProto;
+import com.android.server.am.MemoryStatUtil.MemoryStat;
import com.android.server.am.NeededUriGrantsProto;
import com.android.server.am.ProcessOomProto;
import com.android.server.am.ProcessToGcProto;
@@ -412,25 +384,21 @@
import com.android.server.pm.dex.DexManager;
import com.android.server.utils.PriorityDump;
import com.android.server.vr.VrManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal.SleepToken;
import com.android.server.wm.WindowManagerService;
-import dalvik.system.VMRuntime;
-
-import libcore.io.IoUtils;
-import libcore.util.EmptyArray;
-
-import com.google.android.collect.Lists;
-import com.google.android.collect.Maps;
-
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
+import java.io.BufferedReader;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
+import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
@@ -458,6 +426,10 @@
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
+import dalvik.system.VMRuntime;
+import libcore.io.IoUtils;
+import libcore.util.EmptyArray;
+
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
@@ -471,8 +443,6 @@
private static final String TAG_BROADCAST = TAG + POSTFIX_BROADCAST;
private static final String TAG_CLEANUP = TAG + POSTFIX_CLEANUP;
private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
- private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
- private static final String TAG_IMMERSIVE = TAG + POSTFIX_IMMERSIVE;
private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
private static final String TAG_LRU = TAG + POSTFIX_LRU;
private static final String TAG_MU = TAG + POSTFIX_MU;
@@ -483,13 +453,10 @@
private static final String TAG_PROCESSES = TAG + POSTFIX_PROCESSES;
private static final String TAG_PROVIDER = TAG + POSTFIX_PROVIDER;
private static final String TAG_PSS = TAG + POSTFIX_PSS;
- private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
private static final String TAG_SERVICE = TAG + POSTFIX_SERVICE;
- private static final String TAG_STACK = TAG + POSTFIX_STACK;
private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
private static final String TAG_UID_OBSERVERS = TAG + POSTFIX_UID_OBSERVERS;
private static final String TAG_URI_PERMISSION = TAG + POSTFIX_URI_PERMISSION;
- private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
// Mock "pretend we're idle now" broadcast action to the job scheduler; declared
// here so that while the job scheduler can depend on AMS, the other way around
@@ -511,13 +478,11 @@
static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
+ private static final String ANR_TRACE_DIR = "/data/anr";
+
// Maximum number of receivers an app can register.
private static final int MAX_RECEIVERS_ALLOWED_PER_APP = 1000;
- // Amount of time after a call to stopAppSwitches() during which we will
- // prevent further untrusted switches from happening.
- static final long APP_SWITCH_DELAY_TIME = 5*1000;
-
// How long we wait for a launched process to attach to the activity manager
// before we decide it's never going to come up for real.
static final int PROC_START_TIMEOUT = 10*1000;
@@ -561,11 +526,6 @@
/** If a UID observer takes more than this long, send a WTF. */
private static final int SLOW_UID_OBSERVER_THRESHOLD_MS = 20;
- // Access modes for handleIncomingUser.
- static final int ALLOW_NON_FULL = 0;
- static final int ALLOW_NON_FULL_IN_PROFILE = 1;
- static final int ALLOW_FULL_ONLY = 2;
-
// Necessary ApplicationInfo flags to mark an app as persistent
private static final int PERSISTENT_MASK =
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT;
@@ -577,9 +537,6 @@
// Used to indicate that an app transition should be animated.
static final boolean ANIMATE = true;
- // Determines whether to take full screen screenshots
- static final boolean TAKE_FULLSCREEN_SCREENSHOTS = true;
-
/**
* Default value for {@link Settings.Global#NETWORK_ACCESS_TIMEOUT_MS}.
*/
@@ -628,9 +585,6 @@
// devices.
private boolean mShowDialogs = true;
- // VR Vr2d Display Id.
- int mVr2dDisplayId = INVALID_DISPLAY;
-
// Whether we should use SCHED_FIFO for UI and RenderThreads.
private boolean mUseFifoUiScheduling = false;
@@ -679,12 +633,6 @@
final UserController mUserController;
- /**
- * Packages that are being allowed to perform unrestricted app switches. Mapping is
- * User -> Type -> uid.
- */
- final SparseArray<ArrayMap<String, Integer>> mAllowAppSwitchUids = new SparseArray<>();
-
final AppErrors mAppErrors;
final AppWarnings mAppWarnings;
@@ -762,7 +710,22 @@
* returned by the package manager), and the keys are ApplicationRecord
* objects.
*/
- final ProcessMap<ProcessRecord> mProcessNames = new ProcessMap<ProcessRecord>();
+ final MyProcessMap mProcessNames = new MyProcessMap();
+ final class MyProcessMap extends ProcessMap<ProcessRecord> {
+ @Override
+ public ProcessRecord put(String name, int uid, ProcessRecord value) {
+ final ProcessRecord r = super.put(name, uid, value);
+ mAtmInternal.onProcessAdded(r.getWindowProcessController());
+ return r;
+ }
+
+ @Override
+ public ProcessRecord remove(String name, int uid) {
+ final ProcessRecord r = super.remove(name, uid);
+ mAtmInternal.onProcessRemoved(name, uid);
+ return r;
+ }
+ }
/**
* Tracking long-term execution of processes to look for abuse and other
@@ -773,7 +736,7 @@
/**
* The currently running isolated processes.
*/
- final SparseArray<ProcessRecord> mIsolatedProcesses = new SparseArray<ProcessRecord>();
+ final SparseArray<ProcessRecord> mIsolatedProcesses = new SparseArray<>();
/**
* Counter for assigning isolated process uids, to avoid frequently reusing the
@@ -900,23 +863,6 @@
boolean mFullPssPending = false;
/**
- * This is the process holding what we currently consider to be
- * the "home" activity.
- */
- ProcessRecord mHomeProcess;
-
- /**
- * This is the process holding the activity the user last visited that
- * is in a different process from the one they are currently in.
- */
- ProcessRecord mPreviousProcess;
-
- /**
- * The time at which the previous process was last visible.
- */
- long mPreviousProcessVisibleTime;
-
- /**
* Track all uids that have actively running processes.
*/
final SparseArray<UidRecord> mActiveUids = new SparseArray<>();
@@ -1329,18 +1275,6 @@
final Context mUiContext;
/**
- * The time at which we will allow normal application switches again,
- * after a call to {@link #stopAppSwitches()}.
- */
- long mAppSwitchesAllowedTime;
-
- /**
- * This is set to true after the first switch after mAppSwitchesAllowedTime
- * is set; any switches after that will clear the time.
- */
- boolean mDidAppSwitch;
-
- /**
* Last time (in uptime) at which we checked for power usage.
*/
long mLastPowerCheckUptime;
@@ -1491,29 +1425,7 @@
String mOrigDebugApp = null;
boolean mOrigWaitForDebugger = false;
boolean mAlwaysFinishActivities = false;
- boolean mForceResizableActivities;
- /**
- * Flag that indicates if multi-window is enabled.
- *
- * For any particular form of multi-window to be enabled, generic multi-window must be enabled
- * in {@link com.android.internal.R.bool#config_supportsMultiWindow} config or
- * {@link Settings.Global#DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES} development option set.
- * At least one of the forms of multi-window must be enabled in order for this flag to be
- * initialized to 'true'.
- *
- * @see #mSupportsSplitScreenMultiWindow
- * @see #mSupportsFreeformWindowManagement
- * @see #mSupportsPictureInPicture
- * @see #mSupportsMultiDisplay
- */
- boolean mSupportsMultiWindow;
- boolean mSupportsSplitScreenMultiWindow;
- boolean mSupportsFreeformWindowManagement;
- boolean mSupportsPictureInPicture;
- boolean mSupportsMultiDisplay;
- boolean mSupportsLeanbackOnly;
- IActivityController mController = null;
- boolean mControllerIsAMonkey = false;
+
String mProfileApp = null;
ProcessRecord mProfileProc = null;
ProfilerInfo mProfilerInfo = null;
@@ -1637,8 +1549,6 @@
}
}
- final List<ScreenObserver> mScreenObservers = new ArrayList<>();
-
final RemoteCallbackList<IProcessObserver> mProcessObservers = new RemoteCallbackList<>();
ProcessChangeItem[] mActiveProcessChanges = new ProcessChangeItem[5];
@@ -1680,12 +1590,6 @@
long mLastWriteTime = 0;
/**
- * Used to retain an update lock when the foreground activity is in
- * immersive mode.
- */
- final UpdateLock mUpdateLock = new UpdateLock("immersive");
-
- /**
* Set to true after the system has finished booting.
*/
boolean mBooted = false;
@@ -1697,6 +1601,7 @@
WindowManagerService mWindowManager;
ActivityTaskManagerService mActivityTaskManager;
+ ActivityTaskManagerInternal mAtmInternal;
final ActivityThread mSystemThread;
private final class AppDeathRecipient implements IBinder.DeathRecipient {
@@ -1748,7 +1653,6 @@
static final int DISPATCH_PROCESSES_CHANGED_UI_MSG = 31;
static final int DISPATCH_PROCESS_DIED_UI_MSG = 32;
static final int REPORT_MEM_USAGE_MSG = 33;
- static final int IMMERSIVE_MODE_LOCK_MSG = 37;
static final int PERSIST_URI_GRANTS_MSG = 38;
static final int UPDATE_TIME_PREFERENCE_MSG = 41;
static final int FINISH_BOOTING_MSG = 45;
@@ -1763,8 +1667,6 @@
static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG = 57;
static final int IDLE_UIDS_MSG = 58;
static final int HANDLE_TRUST_STORAGE_UPDATE_MSG = 63;
- static final int DISPATCH_SCREEN_AWAKE_MSG = 64;
- static final int DISPATCH_SCREEN_KEYGUARD_MSG = 65;
static final int SERVICE_FOREGROUND_TIMEOUT_MSG = 66;
static final int DISPATCH_PENDING_INTENT_CANCEL_MSG = 67;
static final int PUSH_TEMP_WHITELIST_UI_MSG = 68;
@@ -1790,11 +1692,6 @@
*/
private boolean mUserIsMonkey;
- /** The dimensions of the thumbnails in the Recents UI. */
- int mThumbnailWidth;
- int mThumbnailHeight;
- float mFullscreenThumbnailScale;
-
final ServiceThread mHandlerThread;
final MainHandler mHandler;
final Handler mUiHandler;
@@ -2038,6 +1935,9 @@
}
}
callbacks.finishBroadcast();
+ // We have to clean up the RemoteCallbackList here, because otherwise it will
+ // needlessly hold the enclosed callbacks until the remote process dies.
+ callbacks.kill();
} break;
case UPDATE_TIME_ZONE: {
synchronized (ActivityManagerService.this) {
@@ -2128,13 +2028,13 @@
}
ActivityRecord root = (ActivityRecord)msg.obj;
- ProcessRecord process = root.app;
+ final WindowProcessController process = root.app;
if (process == null) {
return;
}
try {
- Context context = mContext.createPackageContext(process.info.packageName, 0);
+ Context context = mContext.createPackageContext(process.mInfo.packageName, 0);
String text = mContext.getString(R.string.heavy_weight_notification,
context.getApplicationInfo().loadLabel(context.getPackageManager()));
Notification notification =
@@ -2198,20 +2098,6 @@
thread.start();
break;
}
- case IMMERSIVE_MODE_LOCK_MSG: {
- final boolean nextState = (msg.arg1 != 0);
- if (mUpdateLock.isHeld() != nextState) {
- if (DEBUG_IMMERSIVE) Slog.d(TAG_IMMERSIVE,
- "Applying new update lock state '" + nextState
- + "' for " + (ActivityRecord)msg.obj);
- if (nextState) {
- mUpdateLock.acquire();
- } else {
- mUpdateLock.release();
- }
- }
- break;
- }
case PERSIST_URI_GRANTS_MSG: {
writeGrantedUriPermissions();
break;
@@ -2379,18 +2265,6 @@
case IDLE_UIDS_MSG: {
idleUids();
} break;
- case DISPATCH_SCREEN_AWAKE_MSG: {
- final boolean isAwake = msg.arg1 != 0;
- for (int i = mScreenObservers.size() - 1; i >= 0; i--) {
- mScreenObservers.get(i).onAwakeStateChanged(isAwake);
- }
- } break;
- case DISPATCH_SCREEN_KEYGUARD_MSG: {
- final boolean isShowing = msg.arg1 != 0;
- for (int i = mScreenObservers.size() - 1; i >= 0; i--) {
- mScreenObservers.get(i).onKeyguardStateChanged(isShowing);
- }
- } break;
case HANDLE_TRUST_STORAGE_UPDATE_MSG: {
synchronized (ActivityManagerService.this) {
for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
@@ -2544,8 +2418,9 @@
synchronized (this) {
ProcessRecord app = newProcessRecordLocked(info, info.processName, false, 0);
- app.persistent = true;
+ app.setPersistent(true);
app.pid = MY_PID;
+ app.getWindowProcessController().setPid(MY_PID);
app.maxAdj = ProcessList.SYSTEM_ADJ;
app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
synchronized (mPidsSelfLocked) {
@@ -2581,14 +2456,6 @@
}
}
- public void setActivityTaskManager(ActivityTaskManagerService atm) {
- synchronized (this) {
- mActivityTaskManager = atm;
- mActivityTaskManager.setActivityManagerService(this);
- mStackSupervisor = mActivityTaskManager.mStackSupervisor;
- }
- }
-
public void setUsageStatsManager(UsageStatsManagerInternal usageStatsManager) {
mUsageStatsService = usageStatsManager;
}
@@ -2689,10 +2556,17 @@
public static final class Lifecycle extends SystemService {
private final ActivityManagerService mService;
+ private static ActivityTaskManagerService sAtm;
public Lifecycle(Context context) {
super(context);
- mService = new ActivityManagerService(context);
+ mService = new ActivityManagerService(context, sAtm);
+ }
+
+ public static ActivityManagerService startService(
+ SystemServiceManager ssm, ActivityTaskManagerService atm) {
+ sAtm = atm;
+ return ssm.startService(ActivityManagerService.Lifecycle.class).getService();
}
@Override
@@ -2849,7 +2723,7 @@
// Note: This method is invoked on the main thread but may need to attach various
// handlers to other threads. So take care to be explicit about the looper.
- public ActivityManagerService(Context systemContext) {
+ public ActivityManagerService(Context systemContext, ActivityTaskManagerService atm) {
LockGuard.installLock(this, LockGuard.INDEX_ACTIVITY);
mInjector = new Injector();
mContext = systemContext;
@@ -2928,6 +2802,11 @@
mCompatModePackages = new CompatModePackages(this, systemDir, mHandler);
mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
+ mActivityTaskManager = atm;
+ mActivityTaskManager.setActivityManagerService(this);
+ mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
+ mStackSupervisor = mActivityTaskManager.mStackSupervisor;
+
mProcessCpuThread = new Thread("CpuTracker") {
@Override
public void run() {
@@ -2996,6 +2875,7 @@
mAppOpsService.publish(mContext);
Slog.d("AppOps", "AppOpsService published");
LocalServices.addService(ActivityManagerInternal.class, new LocalService());
+ mActivityTaskManager.onActivityManagerInternalAdded();
// Wait for the synchronized block started in mProcessCpuThread,
// so that any other access to mProcessCpuTracker from main thread
// will be blocked during mProcessCpuTracker initialization.
@@ -3008,11 +2888,6 @@
}
}
- void onUserStoppedLocked(int userId) {
- mActivityTaskManager.getRecentTasks().unloadUserDataFromMemoryLocked(userId);
- mAllowAppSwitchUids.remove(userId);
- }
-
public void initPowerManagement() {
mStackSupervisor.initPowerManagement();
mBatteryStatsService.initPowerManagement();
@@ -3335,7 +3210,7 @@
mWindowManager.setFocusedApp(r.appToken, true);
- applyUpdateLockStateLocked(r);
+ mActivityTaskManager.applyUpdateLockStateLocked(r);
mActivityTaskManager.applyUpdateVrModeLocked(r);
EventLogTags.writeAmSetResumedActivity(
@@ -3379,16 +3254,6 @@
mActivityTaskManager.unregisterTaskStackListener(listener);
}
- final void applyUpdateLockStateLocked(ActivityRecord r) {
- // Modifications to the UpdateLock state are done on our handler, outside
- // the activity manager's locks. The new state is determined based on the
- // state *now* of the relevant activity record. The object is passed to
- // the handler solely for logging detail, not to be consulted/modified.
- final boolean nextState = r != null && r.immersive;
- mHandler.sendMessage(
- mHandler.obtainMessage(IMMERSIVE_MODE_LOCK_MSG, (nextState) ? 1 : 0, 0, r));
- }
-
final void showAskCompatModeDialogLocked(ActivityRecord r) {
Message msg = Message.obtain();
msg.what = SHOW_COMPAT_MODE_DIALOG_UI_MSG;
@@ -3415,7 +3280,7 @@
String what, Object obj, ProcessRecord srcApp) {
app.lastActivityTime = now;
- if (app.activities.size() > 0 || app.recentTasks.size() > 0) {
+ if (app.hasActivitiesOrRecentTasks()) {
// Don't want to touch dependent processes that are hosting activities.
return index;
}
@@ -3462,7 +3327,7 @@
int lrui = mLruProcesses.lastIndexOf(app);
if (lrui >= 0) {
if (!app.killed) {
- if (app.persistent) {
+ if (app.isPersistent()) {
Slog.w(TAG, "Removing persistent process that hasn't been killed: " + app);
} else {
Slog.wtfStack(TAG, "Removing process that hasn't been killed: " + app);
@@ -3486,8 +3351,8 @@
final void updateLruProcessLocked(ProcessRecord app, boolean activityChange,
ProcessRecord client) {
- final boolean hasActivity = app.activities.size() > 0 || app.hasClientActivities
- || app.treatLikeActivity || app.recentTasks.size() > 0;
+ final boolean hasActivity = app.hasActivitiesOrRecentTasks() || app.hasClientActivities
+ || app.treatLikeActivity;
final boolean hasService = false; // not impl yet. app.services.size() > 0;
if (!activityChange && hasActivity) {
// The process has activities, so we are only allowing activity-based adjustments
@@ -3519,7 +3384,7 @@
int lrui = mLruProcesses.lastIndexOf(app);
- if (app.persistent && lrui >= 0) {
+ if (app.isPersistent() && lrui >= 0) {
// We don't care about the position of persistent processes, as long as
// they are in the list.
if (DEBUG_LRU) Slog.d(TAG_LRU, "Not moving, persistent: " + app);
@@ -3591,7 +3456,7 @@
int nextIndex;
if (hasActivity) {
final int N = mLruProcesses.size();
- if ((app.activities.size() == 0 || app.recentTasks.size() > 0)
+ if ((!app.hasActivities() || app.hasRecentTasks())
&& mLruProcessActivityStart < (N - 1)) {
// Process doesn't have activities, but has clients with
// activities... move it up, but one below the top (the top
@@ -3666,14 +3531,14 @@
if (cr.binding != null && !cr.serviceDead && cr.binding.service != null
&& cr.binding.service.app != null
&& cr.binding.service.app.lruSeq != mLruSeq
- && !cr.binding.service.app.persistent) {
+ && !cr.binding.service.app.isPersistent()) {
nextIndex = updateLruProcessInternalLocked(cr.binding.service.app, now, nextIndex,
"service connection", cr, app);
}
}
for (int j=app.conProviders.size()-1; j>=0; j--) {
ContentProviderRecord cpr = app.conProviders.get(j).provider;
- if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq && !cpr.proc.persistent) {
+ if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq && !cpr.proc.isPersistent()) {
nextIndex = updateLruProcessInternalLocked(cpr.proc, now, nextIndex,
"provider reference", cpr, app);
}
@@ -3703,7 +3568,7 @@
&& proc.lastCachedPss >= 4000) {
// Turn this condition on to cause killing to happen regularly, for testing.
if (proc.baseProcessTracker != null) {
- proc.baseProcessTracker.reportCachedKill(proc.pkgList, proc.lastCachedPss);
+ proc.baseProcessTracker.reportCachedKill(proc.pkgList.mPkgList, proc.lastCachedPss);
}
proc.kill(Long.toString(proc.lastCachedPss) + "k from cached", true);
} else if (proc != null && !keepIfLarge
@@ -3712,7 +3577,7 @@
if (DEBUG_PSS) Slog.d(TAG_PSS, "May not keep " + proc + ": pss=" + proc.lastCachedPss);
if (proc.lastCachedPss >= mProcessList.getCachedRestoreThresholdKb()) {
if (proc.baseProcessTracker != null) {
- proc.baseProcessTracker.reportCachedKill(proc.pkgList, proc.lastCachedPss);
+ proc.baseProcessTracker.reportCachedKill(proc.pkgList.mPkgList, proc.lastCachedPss);
}
proc.kill(Long.toString(proc.lastCachedPss) + "k from cached", true);
}
@@ -4018,7 +3883,7 @@
}
if (app.info.isPrivilegedApp() &&
- DexManager.isPackageSelectedToRunOob(app.pkgList.keySet())) {
+ DexManager.isPackageSelectedToRunOob(app.pkgList.mPkgList.keySet())) {
runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES;
}
@@ -4060,7 +3925,7 @@
}
app.gids = gids;
- app.requiredAbi = requiredAbi;
+ app.setRequiredAbi(requiredAbi);
app.instructionSet = instructionSet;
// the per-user SELinux context must be set
@@ -4251,7 +4116,7 @@
// Ignore
}
- if (app.persistent) {
+ if (app.isPersistent()) {
Watchdog.getInstance().processStarted(app.processName, pid);
}
@@ -4310,7 +4175,7 @@
"updateUsageStats: comp=" + component + "res=" + resumed);
final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
StatsLog.write(StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED,
- component.app.uid, component.realActivity.getPackageName(),
+ component.app.mUid, component.realActivity.getPackageName(),
component.realActivity.getShortClassName(), resumed ?
StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__STATE__FOREGROUND :
StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__STATE__BACKGROUND);
@@ -4321,7 +4186,7 @@
}
synchronized (stats) {
- stats.noteActivityResumedLocked(component.app.uid);
+ stats.noteActivityResumedLocked(component.app.mUid);
}
} else {
if (mUsageStatsService != null) {
@@ -4329,7 +4194,7 @@
UsageEvents.Event.MOVE_TO_BACKGROUND);
}
synchronized (stats) {
- stats.noteActivityPausedLocked(component.app.uid);
+ stats.noteActivityPausedLocked(component.app.mUid);
}
}
}
@@ -4413,7 +4278,7 @@
return mCompatModePackages.compatibilityInfoForPackageLocked(ai);
}
- void enforceNotIsolatedCaller(String caller) {
+ private void enforceNotIsolatedCaller(String caller) {
if (UserHandle.isIsolated(Binder.getCallingUid())) {
throw new SecurityException("Isolated process not allowed to call " + caller);
}
@@ -4798,7 +4663,7 @@
// Inform the activity
try {
- activityToCallback.app.thread.scheduleLocalVoiceInteractionStarted(activity,
+ activityToCallback.app.getThread().scheduleLocalVoiceInteractionStarted(activity,
voiceInteractor);
long token = Binder.clearCallingIdentity();
try {
@@ -4866,14 +4731,7 @@
return;
}
- ArrayList<ActivityRecord> activities = new ArrayList<>(proc.activities);
- for (int i = 0; i < activities.size(); i++) {
- ActivityRecord r = activities.get(i);
- if (!r.finishing && r.isInStackLocked()) {
- r.getStack().finishActivityLocked(r, Activity.RESULT_CANCELED,
- null, "finish-heavy", true);
- }
- }
+ proc.getWindowProcessController().finishActivities();
mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,
proc.userId, 0));
@@ -4922,11 +4780,10 @@
}
// Remove this application's activities from active lists.
- boolean hasVisibleActivities = mStackSupervisor.handleAppDiedLocked(app);
+ boolean hasVisibleActivities = mStackSupervisor.handleAppDiedLocked(app.getWindowProcessController());
app.clearRecentTasks();
-
- app.activities.clear();
+ app.clearActivities();
if (app.instr != null) {
Slog.w(TAG, "Crash of app " + app.processName
@@ -4999,7 +4856,7 @@
for (int i=mLruProcesses.size()-1; i>=0; i--) {
ProcessRecord rec = mLruProcesses.get(i);
if (rec.thread != null
- && rec.setProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
+ && rec.setProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
haveBg = true;
break;
}
@@ -5169,7 +5026,7 @@
}
}
- final File tracesDir = new File("/data/anr");
+ final File tracesDir = new File(ANR_TRACE_DIR);
// Each set of ANR traces is written to a separate file and dumpstate will process
// all such files and add them to a captured bug report if they're recent enough.
maybePruneOldTraces(tracesDir);
@@ -5251,7 +5108,7 @@
return SystemClock.elapsedRealtime() - timeStart;
}
- private static void dumpStackTraces(String tracesFile, ArrayList<Integer> firstPids,
+ public static void dumpStackTraces(String tracesFile, ArrayList<Integer> firstPids,
ArrayList<Integer> nativePids, ArrayList<Integer> extraPids) {
// We don't need any sort of inotify based monitoring when we're dumping traces via
@@ -5327,90 +5184,6 @@
}
}
- final void logAppTooSlow(ProcessRecord app, long startTime, String msg) {
- if (true || Build.IS_USER) {
- return;
- }
-
- StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
- StrictMode.allowThreadDiskWrites();
- try {
- File tracesDir = new File("/data/anr");
- File tracesFile = null;
- try {
- tracesFile = File.createTempFile("app_slow", null, tracesDir);
-
- StringBuilder sb = new StringBuilder();
- Time tobj = new Time();
- tobj.set(System.currentTimeMillis());
- sb.append(tobj.format("%Y-%m-%d %H:%M:%S"));
- sb.append(": ");
- TimeUtils.formatDuration(SystemClock.uptimeMillis()-startTime, sb);
- sb.append(" since ");
- sb.append(msg);
- FileOutputStream fos = new FileOutputStream(tracesFile);
- fos.write(sb.toString().getBytes());
- if (app == null) {
- fos.write("\n*** No application process!".getBytes());
- }
- fos.close();
- FileUtils.setPermissions(tracesFile.getPath(), 0666, -1, -1); // -rw-rw-rw-
- } catch (IOException e) {
- Slog.w(TAG, "Unable to prepare slow app traces file: " + tracesFile, e);
- return;
- }
-
- if (app != null && app.pid > 0) {
- ArrayList<Integer> firstPids = new ArrayList<Integer>();
- firstPids.add(app.pid);
- dumpStackTraces(tracesFile.getAbsolutePath(), firstPids, null, null);
- }
-
- File lastTracesFile = null;
- File curTracesFile = null;
- for (int i=9; i>=0; i--) {
- String name = String.format(Locale.US, "slow%02d.txt", i);
- curTracesFile = new File(tracesDir, name);
- if (curTracesFile.exists()) {
- if (lastTracesFile != null) {
- curTracesFile.renameTo(lastTracesFile);
- } else {
- curTracesFile.delete();
- }
- }
- lastTracesFile = curTracesFile;
- }
- tracesFile.renameTo(curTracesFile);
- } finally {
- StrictMode.setThreadPolicy(oldPolicy);
- }
- }
-
- @GuardedBy("this")
- final void showLaunchWarningLocked(final ActivityRecord cur, final ActivityRecord next) {
- if (!mLaunchWarningShown) {
- mLaunchWarningShown = true;
- mUiHandler.post(new Runnable() {
- @Override
- public void run() {
- synchronized (ActivityManagerService.this) {
- final Dialog d = new LaunchWarningWindow(mContext, cur, next);
- d.show();
- mUiHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- synchronized (ActivityManagerService.this) {
- d.dismiss();
- mLaunchWarningShown = false;
- }
- }
- }, 4000);
- }
- }
- });
- }
- }
-
@Override
public boolean clearApplicationUserData(final String packageName, boolean keepState,
final IPackageDataObserver observer, int userId) {
@@ -5611,7 +5384,7 @@
final int NA = apps.size();
for (int ia = 0; ia < NA; ia++) {
final ProcessRecord app = apps.valueAt(ia);
- if (app.persistent) {
+ if (app.isPersistent()) {
// We don't kill persistent processes.
continue;
}
@@ -5648,7 +5421,7 @@
* @param maxProcState the process state at or below which to preserve
* processes, or {@code -1} to ignore the process state
*/
- private void killAllBackgroundProcessesExcept(int minTargetSdk, int maxProcState) {
+ void killAllBackgroundProcessesExcept(int minTargetSdk, int maxProcState) {
if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES)
!= PackageManager.PERMISSION_GRANTED) {
final String msg = "Permission Denial: killAllBackgroundProcessesExcept() from pid="
@@ -5866,7 +5639,7 @@
proc.baseProcessTracker.addPss(infos[i].getTotalPss(),
infos[i].getTotalUss(), infos[i].getTotalRss(), false,
ProcessStats.ADD_PSS_EXTERNAL_SLOW, endTime-startTime,
- proc.pkgList);
+ proc.pkgList.mPkgList);
}
}
}
@@ -5896,7 +5669,7 @@
if (proc.thread != null && proc.setAdj == oomAdj) {
// Record this for posterity if the process has been stable.
proc.baseProcessTracker.addPss(pss[i], tmpUss[0], tmpUss[2], false,
- ProcessStats.ADD_PSS_EXTERNAL, endTime-startTime, proc.pkgList);
+ ProcessStats.ADD_PSS_EXTERNAL, endTime-startTime, proc.pkgList.mPkgList);
}
}
}
@@ -5969,7 +5742,7 @@
final int NA = apps.size();
for (int ia=0; ia<NA; ia++) {
ProcessRecord app = apps.valueAt(ia);
- if (app.persistent && !evenPersistent) {
+ if (app.isPersistent() && !evenPersistent) {
// we don't kill persistent processes
continue;
}
@@ -6306,7 +6079,7 @@
// We shouldn't already have a process under this name, but just in case we
// need to clean up whatever may be there now.
ProcessRecord old = removeProcessNameLocked(proc.processName, proc.uid);
- if (old == proc && proc.persistent) {
+ if (old == proc && proc.isPersistent()) {
// We are re-adding a persistent process. Whatevs! Just leave it there.
Slog.w(TAG, "Re-adding persistent process " + proc);
} else if (old != null) {
@@ -6373,7 +6146,7 @@
}
}
boolean willRestart = false;
- if (app.persistent && !app.isolated) {
+ if (app.isPersistent() && !app.isolated) {
if (!callerWillRestart) {
willRestart = true;
} else {
@@ -6526,7 +6299,7 @@
app.makeActive(thread, mProcessStats);
app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ;
- app.curSchedGroup = app.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+ app.setCurrentSchedulingGroup(app.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT);
app.forcingToImportant = null;
updateProcessForegroundLocked(app, false, false);
app.hasShownUi = false;
@@ -6705,7 +6478,7 @@
app.instr.mWatcher,
app.instr.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
- isRestrictedBackupMode || !normalMode, app.persistent,
+ isRestrictedBackupMode || !normalMode, app.isPersistent(),
new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
@@ -6714,7 +6487,7 @@
thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
null, null, null, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
- isRestrictedBackupMode || !normalMode, app.persistent,
+ isRestrictedBackupMode || !normalMode, app.isPersistent(),
new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
@@ -7609,7 +7382,7 @@
}
}
- int checkComponentPermission(String permission, int pid, int uid,
+ static int checkComponentPermission(String permission, int pid, int uid,
int owningUid, boolean exported) {
if (pid == MY_PID) {
return PackageManager.PERMISSION_GRANTED;
@@ -7697,15 +7470,6 @@
}
/**
- * This can be called with or without the global lock held.
- */
- void enforceCallerIsRecentsOrHasPermission(String permission, String func) {
- if (!mActivityTaskManager.getRecentTasks().isCallerRecents(Binder.getCallingUid())) {
- enforceCallingPermission(permission, func);
- }
- }
-
- /**
* Determine if UID is holding permissions required to access {@link Uri} in
* the given {@link ProviderInfo}. Final permission checking is always done
* in {@link ContentProvider}.
@@ -9162,38 +8926,6 @@
mActivityTaskManager.cancelTaskWindowTransition(taskId);
}
- boolean isGetTasksAllowed(String caller, int callingPid, int callingUid) {
- if (mActivityTaskManager.getRecentTasks().isCallerRecents(callingUid)) {
- // Always allow the recents component to get tasks
- return true;
- }
-
- boolean allowed = checkPermission(android.Manifest.permission.REAL_GET_TASKS,
- callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
- if (!allowed) {
- if (checkPermission(android.Manifest.permission.GET_TASKS,
- callingPid, callingUid) == PackageManager.PERMISSION_GRANTED) {
- // Temporary compatibility: some existing apps on the system image may
- // still be requesting the old permission and not switched to the new
- // one; if so, we'll still allow them full access. This means we need
- // to see if they are holding the old permission and are a system app.
- try {
- if (AppGlobals.getPackageManager().isUidPrivileged(callingUid)) {
- allowed = true;
- if (DEBUG_TASKS) Slog.w(TAG, caller + ": caller " + callingUid
- + " is using old GET_TASKS but privileged; allowing");
- }
- } catch (RemoteException e) {
- }
- }
- }
- if (!allowed) {
- if (DEBUG_TASKS) Slog.w(TAG, caller + ": caller " + callingUid
- + " does not hold REAL_GET_TASKS; limiting output");
- }
- return allowed;
- }
-
@Override
public void setTaskResizeable(int taskId, int resizeableMode) {
mActivityTaskManager.setTaskResizeable(taskId, resizeableMode);
@@ -9618,7 +9350,7 @@
if (conn.stableCount == 0 && conn.unstableCount == 0) {
cpr.connections.remove(conn);
conn.client.conProviders.remove(conn);
- if (conn.client.setProcState < ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
+ if (conn.client.setProcState < PROCESS_STATE_LAST_ACTIVITY) {
// The client is more important than last activity -- note the time this
// is happening, so we keep the old provider process around a bit as last
// activity to avoid thrashing it.
@@ -10618,9 +10350,9 @@
&& userId == UserHandle.USER_SYSTEM
&& (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
// The system process is initialized to SCHED_GROUP_DEFAULT in init.rc.
- r.curSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+ r.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT);
r.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
- r.persistent = true;
+ r.setPersistent(true);
r.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;
}
if (isolated && isolatedUid != 0) {
@@ -10719,7 +10451,7 @@
}
if ((info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
- app.persistent = true;
+ app.setPersistent(true);
app.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;
}
if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
@@ -10810,8 +10542,7 @@
// Also update state in a special way for running foreground services UI.
mServices.updateScreenStateLocked(isAwake);
reportCurWakefulnessUsageEventLocked();
- mHandler.obtainMessage(DISPATCH_SCREEN_AWAKE_MSG, isAwake ? 1 : 0, 0)
- .sendToTarget();
+ mActivityTaskManager.onScreenAwakeChanged(isAwake);
}
updateOomAdjLocked();
}
@@ -10975,69 +10706,12 @@
@Override
public void stopAppSwitches() {
- enforceCallerIsRecentsOrHasPermission(STOP_APP_SWITCHES, "stopAppSwitches");
- synchronized(this) {
- mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
- + APP_SWITCH_DELAY_TIME;
- mDidAppSwitch = false;
- mActivityTaskManager.getActivityStartController().schedulePendingActivityLaunches(APP_SWITCH_DELAY_TIME);
- }
+ mActivityTaskManager.stopAppSwitches();
}
+ @Override
public void resumeAppSwitches() {
- enforceCallerIsRecentsOrHasPermission(STOP_APP_SWITCHES, "resumeAppSwitches");
- synchronized(this) {
- // Note that we don't execute any pending app switches... we will
- // let those wait until either the timeout, or the next start
- // activity request.
- mAppSwitchesAllowedTime = 0;
- }
- }
-
- boolean checkAllowAppSwitchUid(int uid) {
- ArrayMap<String, Integer> types = mAllowAppSwitchUids.get(UserHandle.getUserId(uid));
- if (types != null) {
- for (int i = types.size() - 1; i >= 0; i--) {
- if (types.valueAt(i).intValue() == uid) {
- return true;
- }
- }
- }
- return false;
- }
-
- boolean checkAppSwitchAllowedLocked(int sourcePid, int sourceUid,
- int callingPid, int callingUid, String name) {
- if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
- return true;
- }
-
- if (mActivityTaskManager.getRecentTasks().isCallerRecents(sourceUid)) {
- return true;
- }
-
- int perm = checkComponentPermission(STOP_APP_SWITCHES, sourcePid, sourceUid, -1, true);
- if (perm == PackageManager.PERMISSION_GRANTED) {
- return true;
- }
- if (checkAllowAppSwitchUid(sourceUid)) {
- return true;
- }
-
- // If the actual IPC caller is different from the logical source, then
- // also see if they are allowed to control app switches.
- if (callingUid != -1 && callingUid != sourceUid) {
- perm = checkComponentPermission(STOP_APP_SWITCHES, callingPid, callingUid, -1, true);
- if (perm == PackageManager.PERMISSION_GRANTED) {
- return true;
- }
- if (checkAllowAppSwitchUid(callingUid)) {
- return true;
- }
- }
-
- Slog.w(TAG, name + " request from " + sourceUid + " stopped");
- return false;
+ mActivityTaskManager.resumeAppSwitches();
}
public void setDebugApp(String packageName, boolean waitForDebugger,
@@ -11191,13 +10865,7 @@
@Override
public void setActivityController(IActivityController controller, boolean imAMonkey) {
- enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
- "setActivityController()");
- synchronized (this) {
- mController = controller;
- mControllerIsAMonkey = imAMonkey;
- Watchdog.getInstance().setActivityController(controller);
- }
+ mActivityTaskManager.setActivityController(controller, imAMonkey);
}
@Override
@@ -11222,7 +10890,7 @@
public boolean isUserAMonkey() {
synchronized (this) {
// If there is a controller also implies the user is a monkey.
- return (mUserIsMonkey || (mController != null && mControllerIsAMonkey));
+ return mUserIsMonkey || mActivityTaskManager.isControllerAMonkey();
}
}
@@ -11334,7 +11002,10 @@
public static long getInputDispatchingTimeoutLocked(ActivityRecord r) {
- return r != null ? getInputDispatchingTimeoutLocked(r.app) : KEY_DISPATCHING_TIMEOUT;
+ if (r == null || !r.hasProcess()) {
+ return KEY_DISPATCHING_TIMEOUT;
+ }
+ return getInputDispatchingTimeoutLocked((ProcessRecord) r.app.mOwner);
}
public static long getInputDispatchingTimeoutLocked(ProcessRecord r) {
@@ -11529,17 +11200,6 @@
return false;
}
- /**
- * Check that we have the features required for VR-related API calls, and throw an exception if
- * not.
- */
- void enforceSystemHasVrFeature() {
- if (!mContext.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE)) {
- throw new UnsupportedOperationException("VR mode not supported on this device!");
- }
- }
-
@Override
public void setRenderThread(int tid) {
synchronized (this) {
@@ -11562,7 +11222,7 @@
Slog.d("UI_FIFO", "Set RenderThread tid " + tid + " for pid " + pid);
}
// promote to FIFO now
- if (proc.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
+ if (proc.getCurrentSchedulingGroup() == ProcessList.SCHED_GROUP_TOP_APP) {
if (DEBUG_OOM_ADJ) Slog.d("UI_FIFO", "Promoting " + tid + "out of band");
if (mUseFifoUiScheduling) {
setThreadScheduler(proc.renderThreadTid,
@@ -11594,7 +11254,7 @@
@Override
public boolean isVrModePackageEnabled(ComponentName packageName) {
- enforceSystemHasVrFeature();
+ mActivityTaskManager.enforceSystemHasVrFeature();
final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
@@ -12067,78 +11727,22 @@
private void retrieveSettings() {
final ContentResolver resolver = mContext.getContentResolver();
- final boolean freeformWindowManagement =
- mContext.getPackageManager().hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT)
- || Settings.Global.getInt(
- resolver, DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0;
+ mActivityTaskManager.retrieveSettings(resolver);
- final boolean supportsMultiWindow = ActivityTaskManager.supportsMultiWindow(mContext);
- final boolean supportsPictureInPicture = supportsMultiWindow &&
- mContext.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
- final boolean supportsSplitScreenMultiWindow =
- ActivityTaskManager.supportsSplitScreenMultiWindow(mContext);
- final boolean supportsMultiDisplay = mContext.getPackageManager()
- .hasSystemFeature(FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS);
final String debugApp = Settings.Global.getString(resolver, DEBUG_APP);
final boolean waitForDebugger = Settings.Global.getInt(resolver, WAIT_FOR_DEBUGGER, 0) != 0;
final boolean alwaysFinishActivities =
Settings.Global.getInt(resolver, ALWAYS_FINISH_ACTIVITIES, 0) != 0;
- final boolean forceRtl = Settings.Global.getInt(resolver, DEVELOPMENT_FORCE_RTL, 0) != 0;
- final boolean forceResizable = Settings.Global.getInt(
- resolver, DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0;
final long waitForNetworkTimeoutMs = Settings.Global.getLong(resolver,
NETWORK_ACCESS_TIMEOUT_MS, NETWORK_ACCESS_TIMEOUT_DEFAULT_MS);
- final boolean supportsLeanbackOnly =
- mContext.getPackageManager().hasSystemFeature(FEATURE_LEANBACK_ONLY);
mHiddenApiBlacklist.registerObserver();
- // Transfer any global setting for forcing RTL layout, into a System Property
- SystemProperties.set(DEVELOPMENT_FORCE_RTL, forceRtl ? "1":"0");
-
- final Configuration configuration = new Configuration();
- Settings.System.getConfiguration(resolver, configuration);
- if (forceRtl) {
- // This will take care of setting the correct layout direction flags
- configuration.setLayoutDirection(configuration.locale);
- }
-
synchronized (this) {
mDebugApp = mOrigDebugApp = debugApp;
mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
mAlwaysFinishActivities = alwaysFinishActivities;
- mSupportsLeanbackOnly = supportsLeanbackOnly;
- mForceResizableActivities = forceResizable;
- final boolean multiWindowFormEnabled = freeformWindowManagement
- || supportsSplitScreenMultiWindow
- || supportsPictureInPicture
- || supportsMultiDisplay;
- if ((supportsMultiWindow || forceResizable) && multiWindowFormEnabled) {
- mSupportsMultiWindow = true;
- mSupportsFreeformWindowManagement = freeformWindowManagement;
- mSupportsSplitScreenMultiWindow = supportsSplitScreenMultiWindow;
- mSupportsPictureInPicture = supportsPictureInPicture;
- mSupportsMultiDisplay = supportsMultiDisplay;
- } else {
- mSupportsMultiWindow = false;
- mSupportsFreeformWindowManagement = false;
- mSupportsSplitScreenMultiWindow = false;
- mSupportsPictureInPicture = false;
- mSupportsMultiDisplay = false;
- }
- mWindowManager.setForceResizableTasks(mForceResizableActivities);
- mWindowManager.setSupportsPictureInPicture(mSupportsPictureInPicture);
- // This happens before any activities are started, so we can change global configuration
- // in-place.
- updateConfigurationLocked(configuration, null, true);
- final Configuration globalConfig = getGlobalConfiguration();
- if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Initial config: " + globalConfig);
-
// Load resources only after the current configuration has been set.
final Resources res = mContext.getResources();
- mThumbnailWidth = res.getDimensionPixelSize(
- com.android.internal.R.dimen.thumbnail_width);
- mThumbnailHeight = res.getDimensionPixelSize(
- com.android.internal.R.dimen.thumbnail_height);
mAppErrors.loadAppsNotReportingCrashesFromConfigLocked(res.getString(
com.android.internal.R.string.config_appsNotReportingCrashes));
mUserController.mUserSwitchUiEnabled = !res.getBoolean(
@@ -12146,14 +11750,6 @@
mUserController.mMaxRunningUsers = res.getInteger(
com.android.internal.R.integer.config_multiuserMaxRunningUsers);
- if ((globalConfig.uiMode & UI_MODE_TYPE_TELEVISION) == UI_MODE_TYPE_TELEVISION) {
- mFullscreenThumbnailScale = (float) res
- .getInteger(com.android.internal.R.integer.thumbnail_width_tv) /
- (float) globalConfig.screenWidthDp;
- } else {
- mFullscreenThumbnailScale = res.getFraction(
- com.android.internal.R.fraction.thumbnail_fullscreen_scale, 1, 1);
- }
mWaitForNetworkTimeoutMs = waitForNetworkTimeoutMs;
}
}
@@ -12450,13 +12046,13 @@
public void handleApplicationStrictModeViolation(
IBinder app,
- int violationMask,
+ int penaltyMask,
StrictMode.ViolationInfo info) {
// We're okay if the ProcessRecord is missing; it probably means that
// we're reporting a violation from the system process itself.
final ProcessRecord r = findAppProcess(app, "StrictMode");
- if ((violationMask & StrictMode.PENALTY_DROPBOX) != 0) {
+ if ((penaltyMask & StrictMode.PENALTY_DROPBOX) != 0) {
Integer stackFingerprint = info.hashCode();
boolean logIt = true;
synchronized (mAlreadyLoggedViolatedStacks) {
@@ -12480,7 +12076,7 @@
}
}
- if ((violationMask & StrictMode.PENALTY_DIALOG) != 0) {
+ if ((penaltyMask & StrictMode.PENALTY_DIALOG) != 0) {
AppErrorResult result = new AppErrorResult();
synchronized (this) {
final long origId = Binder.clearCallingIdentity();
@@ -12490,7 +12086,6 @@
HashMap<String, Object> data = new HashMap<String, Object>();
data.put("result", result);
data.put("app", r);
- data.put("violationMask", violationMask);
data.put("info", info);
msg.obj = data;
mUiHandler.sendMessage(msg);
@@ -12594,7 +12189,7 @@
final boolean isFatal = Build.IS_ENG || Settings.Global
.getInt(mContext.getContentResolver(), Settings.Global.WTF_IS_FATAL, 0) != 0;
- final boolean isSystem = (r == null) || r.persistent;
+ final boolean isSystem = (r == null) || r.isPersistent();
if (isFatal && !isSystem) {
mAppErrors.crashApplication(r, crashInfo);
@@ -12757,8 +12352,8 @@
if (activity != null) {
sb.append("Activity: ").append(activity.shortComponentName).append("\n");
}
- if (parent != null && parent.app != null && parent.app.pid != process.pid) {
- sb.append("Parent-Process: ").append(parent.app.processName).append("\n");
+ if (parent != null && parent.app != null && parent.app.getPid() != process.pid) {
+ sb.append("Parent-Process: ").append(parent.app.mName).append("\n");
}
if (parent != null && parent != activity) {
sb.append("Parent-Activity: ").append(parent.shortComponentName).append("\n");
@@ -12860,25 +12455,27 @@
if (!allUsers && app.userId != userId) {
continue;
}
- if ((app.thread != null) && (app.crashing || app.notResponding)) {
+ final boolean crashing = app.isCrashing();
+ final boolean notResponding = app.isNotResponding();
+ if ((app.thread != null) && (crashing || notResponding)) {
// This one's in trouble, so we'll generate a report for it
// crashes are higher priority (in case there's a crash *and* an anr)
ActivityManager.ProcessErrorStateInfo report = null;
- if (app.crashing) {
+ if (crashing) {
report = app.crashingReport;
- } else if (app.notResponding) {
+ } else if (notResponding) {
report = app.notRespondingReport;
}
if (report != null) {
if (errList == null) {
- errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
+ errList = new ArrayList<>(1);
}
errList.add(report);
} else {
Slog.w(TAG, "Missing app error report, app = " + app.processName +
- " crashing = " + app.crashing +
- " notResponding = " + app.notResponding);
+ " crashing = " + crashing +
+ " notResponding = " + notResponding);
}
}
}
@@ -12900,7 +12497,7 @@
return imp;
}
- private void fillInProcMemInfo(ProcessRecord app,
+ private void fillInProcMemInfoLocked(ProcessRecord app,
ActivityManager.RunningAppProcessInfo outInfo,
int clientTargetSdk) {
outInfo.pid = app.pid;
@@ -12908,10 +12505,10 @@
if (mHeavyWeightProcess == app) {
outInfo.flags |= ActivityManager.RunningAppProcessInfo.FLAG_CANT_SAVE_STATE;
}
- if (app.persistent) {
+ if (app.isPersistent()) {
outInfo.flags |= ActivityManager.RunningAppProcessInfo.FLAG_PERSISTENT;
}
- if (app.activities.size() > 0) {
+ if (app.hasActivities()) {
outInfo.flags |= ActivityManager.RunningAppProcessInfo.FLAG_HAS_ACTIVITIES;
}
outInfo.lastTrimLevel = app.trimMemoryLevel;
@@ -12920,6 +12517,8 @@
outInfo.importance = procStateToImportance(procState, adj, outInfo, clientTargetSdk);
outInfo.importanceReasonCode = app.adjTypeCode;
outInfo.processState = app.curProcState;
+ outInfo.isFocused = (app == getTopAppLocked());
+ outInfo.lastActivityTime = app.lastActivityTime;
}
@Override
@@ -12934,7 +12533,7 @@
final boolean allUsers = ActivityManager.checkUidPermission(INTERACT_ACROSS_USERS_FULL,
callingUid) == PackageManager.PERMISSION_GRANTED;
final int userId = UserHandle.getUserId(callingUid);
- final boolean allUids = isGetTasksAllowed(
+ final boolean allUids = mAtmInternal.isGetTasksAllowed(
"getRunningAppProcesses", Binder.getCallingPid(), callingUid);
synchronized (this) {
@@ -12945,12 +12544,12 @@
|| (!allUids && app.uid != callingUid)) {
continue;
}
- if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
+ if ((app.thread != null) && (!app.isCrashing() && !app.isNotResponding())) {
// Generate process state info for running application
ActivityManager.RunningAppProcessInfo currApp =
new ActivityManager.RunningAppProcessInfo(app.processName,
app.pid, app.getPackageList());
- fillInProcMemInfo(app, currApp, clientTargetSdk);
+ fillInProcMemInfoLocked(app, currApp, clientTargetSdk);
if (app.adjSource instanceof ProcessRecord) {
currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
currApp.importanceReasonImportance =
@@ -12958,7 +12557,7 @@
app.adjSourceProcState);
} else if (app.adjSource instanceof ActivityRecord) {
ActivityRecord r = (ActivityRecord)app.adjSource;
- if (r.app != null) currApp.importanceReasonPid = r.app.pid;
+ if (r.app != null) currApp.importanceReasonPid = r.app.getPid();
}
if (app.adjTarget instanceof ComponentName) {
currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
@@ -13019,7 +12618,7 @@
proc = mPidsSelfLocked.get(Binder.getCallingPid());
}
if (proc != null) {
- fillInProcMemInfo(proc, outState, clientTargetSdk);
+ fillInProcMemInfoLocked(proc, outState, clientTargetSdk);
}
}
}
@@ -13191,6 +12790,10 @@
synchronized (this) {
dumpLastANRLocked(pw);
}
+ } else if ("lastanr-traces".equals(cmd)) {
+ synchronized (this) {
+ dumpLastANRTracesLocked(pw);
+ }
} else if ("starter".equals(cmd)) {
synchronized (this) {
dumpActivityStarterLocked(pw, dumpPackage);
@@ -13540,6 +13143,35 @@
}
}
+ private void dumpLastANRTracesLocked(PrintWriter pw) {
+ pw.println("ACTIVITY MANAGER LAST ANR TRACES (dumpsys activity lastanr-traces)");
+
+ final File[] files = new File(ANR_TRACE_DIR).listFiles();
+ if (ArrayUtils.isEmpty(files)) {
+ return;
+ }
+ // Find the latest file.
+ File latest = null;
+ for (File f : files) {
+ if (latest == null || latest.getName().compareTo(f.getName()) < 0) {
+ latest = f;
+ }
+ }
+ pw.print("File: ");
+ pw.print(latest.getName());
+ pw.println();
+ try (BufferedReader in = new BufferedReader(new FileReader(latest))) {
+ String line;
+ while ((line = in.readLine()) != null) {
+ pw.println(line);
+ }
+ } catch (IOException e) {
+ pw.print("Unable to read: ");
+ pw.print(e);
+ pw.println();
+ }
+ }
+
private void dumpActivityContainersLocked(PrintWriter pw) {
pw.println("ACTIVITY MANAGER STARTER (dumpsys activity containers)");
mStackSupervisor.dumpChildrenNames(pw, " ");
@@ -13761,11 +13393,11 @@
pw.println(" All known processes:");
needSep = true;
}
- pw.print(r.persistent ? " *PERS*" : " *APP*");
+ pw.print(r.isPersistent() ? " *PERS*" : " *APP*");
pw.print(" UID "); pw.print(procs.keyAt(ia));
pw.print(" "); pw.println(r);
r.dump(pw, " ");
- if (r.persistent) {
+ if (r.isPersistent()) {
numPers++;
}
}
@@ -13917,27 +13549,27 @@
needSep = false;
mUserController.dump(pw, dumpAll);
}
- if (mHomeProcess != null && (dumpPackage == null
- || mHomeProcess.pkgList.containsKey(dumpPackage))) {
+ if (mActivityTaskManager.mHomeProcess != null && (dumpPackage == null
+ || mActivityTaskManager.mHomeProcess.mPkgList.contains(dumpPackage))) {
if (needSep) {
pw.println();
needSep = false;
}
- pw.println(" mHomeProcess: " + mHomeProcess);
+ pw.println(" mHomeProcess: " + mActivityTaskManager.mHomeProcess);
}
- if (mPreviousProcess != null && (dumpPackage == null
- || mPreviousProcess.pkgList.containsKey(dumpPackage))) {
+ if (mActivityTaskManager.mPreviousProcess != null && (dumpPackage == null
+ || mActivityTaskManager.mPreviousProcess.mPkgList.contains(dumpPackage))) {
if (needSep) {
pw.println();
needSep = false;
}
- pw.println(" mPreviousProcess: " + mPreviousProcess);
+ pw.println(" mPreviousProcess: " + mActivityTaskManager.mPreviousProcess);
}
- if (dumpAll && (mPreviousProcess == null || dumpPackage == null
- || mPreviousProcess.pkgList.containsKey(dumpPackage))) {
+ if (dumpAll && (mActivityTaskManager.mPreviousProcess == null || dumpPackage == null
+ || mActivityTaskManager.mPreviousProcess.mPkgList.contains(dumpPackage))) {
StringBuilder sb = new StringBuilder(128);
sb.append(" mPreviousProcessVisibleTime: ");
- TimeUtils.formatDuration(mPreviousProcessVisibleTime, sb);
+ TimeUtils.formatDuration(mActivityTaskManager.mPreviousProcessVisibleTime, sb);
pw.println(sb);
}
if (mHeavyWeightProcess != null && (dumpPackage == null
@@ -13962,7 +13594,7 @@
}
if (dumpAll) {
if (dumpPackage == null) {
- pw.println(" mConfigWillChange: " + getFocusedStack().mConfigWillChange);
+ pw.println(" mConfigWillChange: " + mActivityTaskManager.getFocusedStack().mConfigWillChange);
}
if (mCompatModePackages.getPackages().size() > 0) {
boolean printed = false;
@@ -14127,10 +13759,10 @@
pw.println(" mNativeDebuggingApp=" + mNativeDebuggingApp);
}
}
- if (mAllowAppSwitchUids.size() > 0) {
+ if (mActivityTaskManager.mAllowAppSwitchUids.size() > 0) {
boolean printed = false;
- for (int i = 0; i < mAllowAppSwitchUids.size(); i++) {
- ArrayMap<String, Integer> types = mAllowAppSwitchUids.valueAt(i);
+ for (int i = 0; i < mActivityTaskManager.mAllowAppSwitchUids.size(); i++) {
+ ArrayMap<String, Integer> types = mActivityTaskManager.mAllowAppSwitchUids.valueAt(i);
for (int j = 0; j < types.size(); j++) {
if (dumpPackage == null ||
UserHandle.getAppId(types.valueAt(j).intValue()) == dumpAppId) {
@@ -14143,7 +13775,7 @@
printed = true;
}
pw.print(" User ");
- pw.print(mAllowAppSwitchUids.keyAt(i));
+ pw.print(mActivityTaskManager.mAllowAppSwitchUids.keyAt(i));
pw.print(": Type ");
pw.print(types.keyAt(j));
pw.print(" = ");
@@ -14157,9 +13789,9 @@
if (mAlwaysFinishActivities) {
pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities);
}
- if (mController != null) {
- pw.println(" mController=" + mController
- + " mControllerIsAMonkey=" + mControllerIsAMonkey);
+ if (mActivityTaskManager.mController != null) {
+ pw.println(" mController=" + mActivityTaskManager.mController
+ + " mControllerIsAMonkey=" + mActivityTaskManager.mControllerIsAMonkey);
}
if (dumpAll) {
pw.println(" Total persistent processes: " + numPers);
@@ -14233,7 +13865,7 @@
continue;
}
r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.PROCS);
- if (r.persistent) {
+ if (r.isPersistent()) {
numPers++;
}
}
@@ -14340,18 +13972,18 @@
if (dumpPackage == null) {
mUserController.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.USER_CONTROLLER);
getGlobalConfiguration().writeToProto(proto, ActivityManagerServiceDumpProcessesProto.GLOBAL_CONFIGURATION);
- proto.write(ActivityManagerServiceDumpProcessesProto.CONFIG_WILL_CHANGE, getFocusedStack().mConfigWillChange);
+ proto.write(ActivityManagerServiceDumpProcessesProto.CONFIG_WILL_CHANGE, mActivityTaskManager.getFocusedStack().mConfigWillChange);
}
- if (mHomeProcess != null && (dumpPackage == null
- || mHomeProcess.pkgList.containsKey(dumpPackage))) {
- mHomeProcess.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.HOME_PROC);
+ if (mActivityTaskManager.mHomeProcess != null && (dumpPackage == null
+ || mActivityTaskManager.mHomeProcess.mPkgList.contains(dumpPackage))) {
+ ((ProcessRecord) mActivityTaskManager.mHomeProcess.mOwner).writeToProto(proto, ActivityManagerServiceDumpProcessesProto.HOME_PROC);
}
- if (mPreviousProcess != null && (dumpPackage == null
- || mPreviousProcess.pkgList.containsKey(dumpPackage))) {
- mPreviousProcess.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC);
- proto.write(ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC_VISIBLE_TIME_MS, mPreviousProcessVisibleTime);
+ if (mActivityTaskManager.mPreviousProcess != null && (dumpPackage == null
+ || mActivityTaskManager.mPreviousProcess.mPkgList.contains(dumpPackage))) {
+ ((ProcessRecord) mActivityTaskManager.mPreviousProcess.mOwner).writeToProto(proto, ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC);
+ proto.write(ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC_VISIBLE_TIME_MS, mActivityTaskManager.mPreviousProcessVisibleTime);
}
if (mHeavyWeightProcess != null && (dumpPackage == null
@@ -14490,10 +14122,10 @@
if (dumpPackage == null) {
proto.write(ActivityManagerServiceDumpProcessesProto.ALWAYS_FINISH_ACTIVITIES, mAlwaysFinishActivities);
- if (mController != null) {
+ if (mActivityTaskManager.mController != null) {
final long token = proto.start(ActivityManagerServiceDumpProcessesProto.CONTROLLER);
- proto.write(ActivityManagerServiceDumpProcessesProto.Controller.CONTROLLER, mController.toString());
- proto.write(ActivityManagerServiceDumpProcessesProto.Controller.IS_A_MONKEY, mControllerIsAMonkey);
+ proto.write(ActivityManagerServiceDumpProcessesProto.Controller.CONTROLLER, mActivityTaskManager.mController.toString());
+ proto.write(ActivityManagerServiceDumpProcessesProto.Controller.IS_A_MONKEY, mActivityTaskManager.mControllerIsAMonkey);
proto.end(token);
}
proto.write(ActivityManagerServiceDumpProcessesProto.TOTAL_PERSISTENT_PROCS, numPers);
@@ -14622,8 +14254,8 @@
dumpProcessesToGc(pw, needSep, null);
pw.println();
- pw.println(" mHomeProcess: " + mHomeProcess);
- pw.println(" mPreviousProcess: " + mPreviousProcess);
+ pw.println(" mHomeProcess: " + mActivityTaskManager.mHomeProcess);
+ pw.println(" mPreviousProcess: " + mActivityTaskManager.mPreviousProcess);
if (mHeavyWeightProcess != null) {
pw.println(" mHeavyWeightProcess: " + mHeavyWeightProcess);
}
@@ -14795,20 +14427,20 @@
pw.print(prefix); pw.print("ACTIVITY "); pw.print(r.shortComponentName);
pw.print(" "); pw.print(Integer.toHexString(System.identityHashCode(r)));
pw.print(" pid=");
- if (r.app != null) pw.println(r.app.pid);
+ if (r.hasProcess()) pw.println(r.app.getPid());
else pw.println("(not running)");
if (dumpAll) {
r.dump(pw, innerPrefix);
}
}
- if (r.app != null && r.app.thread != null) {
+ if (r.attachedToProcess()) {
// flush anything that is already in the PrintWriter since the thread is going
// to write to the file descriptor directly
pw.flush();
try {
TransferPipe tp = new TransferPipe();
try {
- r.app.thread.dumpActivity(tp.getWriteFd(),
+ r.app.getThread().dumpActivity(tp.getWriteFd(),
r.appToken, innerPrefix, args);
tp.go(fd);
} finally {
@@ -15163,9 +14795,9 @@
continue;
}
pw.println(String.format("%s%s #%2d: %s",
- prefix, (r.persistent ? persistentLabel : normalLabel),
+ prefix, (r.isPersistent() ? persistentLabel : normalLabel),
i, r.toString()));
- if (r.persistent) {
+ if (r.isPersistent()) {
numPers++;
}
}
@@ -15218,7 +14850,7 @@
ProcessRecord r = list.get(i).first;
long token = proto.start(fieldId);
String oomAdj = ProcessList.makeOomAdjString(r.setAdj);
- proto.write(ProcessOomProto.PERSISTENT, r.persistent);
+ proto.write(ProcessOomProto.PERSISTENT, r.isPersistent());
proto.write(ProcessOomProto.NUM, (origList.size()-1)-list.get(i).second);
proto.write(ProcessOomProto.OOM_ADJ, oomAdj);
int schedGroup = ProcessOomProto.SCHED_GROUP_UNKNOWN;
@@ -15241,7 +14873,7 @@
}
if (r.foregroundActivities) {
proto.write(ProcessOomProto.ACTIVITIES, true);
- } else if (r.foregroundServices) {
+ } else if (r.hasForegroundServices()) {
proto.write(ProcessOomProto.SERVICES, true);
}
proto.write(ProcessOomProto.STATE, ProcessList.makeProcStateProtoEnum(r.curProcState));
@@ -15338,14 +14970,14 @@
char foreground;
if (r.foregroundActivities) {
foreground = 'A';
- } else if (r.foregroundServices) {
+ } else if (r.hasForegroundServices()) {
foreground = 'S';
} else {
foreground = ' ';
}
String procState = ProcessList.makeProcStateString(r.curProcState);
pw.print(prefix);
- pw.print(r.persistent ? persistentLabel : normalLabel);
+ pw.print(r.isPersistent() ? persistentLabel : normalLabel);
pw.print(" #");
int num = (origList.size()-1)-list.get(i).second;
if (num < 10) pw.print(' ');
@@ -15960,7 +15592,7 @@
thread = r.thread;
pid = r.pid;
oomAdj = r.getSetAdjWithServices();
- hasActivities = r.activities.size() > 0;
+ hasActivities = r.hasActivities();
}
if (thread != null) {
if (!opts.isCheckinRequest && opts.dumpDetails) {
@@ -16027,7 +15659,7 @@
if (r.thread != null && oomAdj == r.getSetAdjWithServices()) {
// Record this for posterity if the process has been stable.
r.baseProcessTracker.addPss(myTotalPss, myTotalUss, myTotalRss, true,
- reportType, endTime-startTime, r.pkgList);
+ reportType, endTime-startTime, r.pkgList.mPkgList);
}
}
@@ -16463,7 +16095,7 @@
thread = r.thread;
pid = r.pid;
oomAdj = r.getSetAdjWithServices();
- hasActivities = r.activities.size() > 0;
+ hasActivities = r.hasActivities();
}
if (thread == null) {
continue;
@@ -16525,7 +16157,7 @@
if (r.thread != null && oomAdj == r.getSetAdjWithServices()) {
// Record this for posterity if the process has been stable.
r.baseProcessTracker.addPss(myTotalPss, myTotalUss, myTotalRss, true,
- reportType, endTime-startTime, r.pkgList);
+ reportType, endTime-startTime, r.pkgList.mPkgList);
}
}
@@ -17091,7 +16723,7 @@
ProcessRecord capp = conn.client;
conn.dead = true;
if (conn.stableCount > 0) {
- if (!capp.persistent && capp.thread != null
+ if (!capp.isPersistent() && capp.thread != null
&& capp.pid != 0
&& capp.pid != MY_PID) {
capp.kill("depends on provider "
@@ -17153,8 +16785,8 @@
app.waitDialog = null;
}
- app.crashing = false;
- app.notResponding = false;
+ app.setCrashing(false);
+ app.setNotResponding(false);
app.resetPackageList(mProcessStats);
app.unlinkDeathRecipient();
@@ -17263,7 +16895,7 @@
return false;
}
- if (!app.persistent || app.isolated) {
+ if (!app.isPersistent() || app.isolated) {
if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
"Removing non-persistent process during cleanup: " + app);
if (!replacingPid) {
@@ -17287,12 +16919,7 @@
TAG_CLEANUP, "Clean-up removing on hold: " + app);
mProcessesOnHold.remove(app);
- if (app == mHomeProcess) {
- mHomeProcess = null;
- }
- if (app == mPreviousProcess) {
- mPreviousProcess = null;
- }
+ mAtmInternal.onCleanUpApplicationRecord(app.getWindowProcessController());
if (restart && !app.isolated) {
// We have components that still need to be running in the
@@ -17360,8 +16987,8 @@
final int callingUid = Binder.getCallingUid();
final boolean canInteractAcrossUsers = (ActivityManager.checkUidPermission(
INTERACT_ACROSS_USERS_FULL, callingUid) == PERMISSION_GRANTED);
- final boolean allowed = isGetTasksAllowed("getServices", Binder.getCallingPid(),
- callingUid);
+ final boolean allowed = mAtmInternal.isGetTasksAllowed("getServices",
+ Binder.getCallingPid(), callingUid);
synchronized (this) {
return mServices.getRunningServiceInfoLocked(maxNum, flags, callingUid,
allowed, canInteractAcrossUsers);
@@ -18337,7 +17964,7 @@
isCallerSystem = true;
break;
default:
- isCallerSystem = (callerApp != null) && callerApp.persistent;
+ isCallerSystem = (callerApp != null) && callerApp.isPersistent();
break;
}
@@ -19333,10 +18960,6 @@
return config;
}
- ActivityStack getFocusedStack() {
- return mStackSupervisor.getFocusedStack();
- }
-
@Override
public StackInfo getFocusedStackInfo() throws RemoteException {
return mActivityTaskManager.getFocusedStackInfo();
@@ -19366,18 +18989,7 @@
int userId = UserHandle.getCallingUserId();
- synchronized(this) {
- updatePersistentConfigurationLocked(values, userId);
- }
- }
-
- private void updatePersistentConfigurationLocked(Configuration values, @UserIdInt int userId) {
- final long origId = Binder.clearCallingIdentity();
- try {
- updateConfigurationLocked(values, null, false, true, userId, false /* deferResume */);
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
+ mActivityTaskManager.updatePersistentConfiguration(values, userId);
}
private void updateFontScaleIfNeeded(@UserIdInt int userId) {
@@ -19392,7 +19004,7 @@
final Configuration configuration
= mWindowManager.computeNewConfiguration(DEFAULT_DISPLAY);
configuration.fontScale = scaleFactor;
- updatePersistentConfigurationLocked(configuration, userId);
+ mActivityTaskManager.updatePersistentConfiguration(configuration, userId);
}
}
@@ -19420,356 +19032,6 @@
return mActivityTaskManager.updateConfiguration(values);
}
- void updateUserConfigurationLocked() {
- final Configuration configuration = new Configuration(getGlobalConfiguration());
- final int currentUserId = mUserController.getCurrentUserId();
- Settings.System.adjustConfigurationForUser(mContext.getContentResolver(), configuration,
- currentUserId, Settings.System.canWrite(mContext));
- updateConfigurationLocked(configuration, null /* starting */, false /* initLocale */,
- false /* persistent */, currentUserId, false /* deferResume */);
- }
-
- boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
- boolean initLocale) {
- return updateConfigurationLocked(values, starting, initLocale, false /* deferResume */);
- }
-
- boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
- boolean initLocale, boolean deferResume) {
- // pass UserHandle.USER_NULL as userId because we don't persist configuration for any user
- return updateConfigurationLocked(values, starting, initLocale, false /* persistent */,
- UserHandle.USER_NULL, deferResume);
- }
-
- // To cache the list of supported system locales
- private String[] mSupportedSystemLocales = null;
-
- private boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
- boolean initLocale, boolean persistent, int userId, boolean deferResume) {
- return updateConfigurationLocked(values, starting, initLocale, persistent, userId,
- deferResume, null /* result */);
- }
-
- /**
- * Do either or both things: (1) change the current configuration, and (2)
- * make sure the given activity is running with the (now) current
- * configuration. Returns true if the activity has been left running, or
- * false if <var>starting</var> is being destroyed to match the new
- * configuration.
- *
- * @param userId is only used when persistent parameter is set to true to persist configuration
- * for that particular user
- */
- boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
- boolean initLocale, boolean persistent, int userId, boolean deferResume,
- ActivityTaskManagerService.UpdateConfigurationResult result) {
- int changes = 0;
- boolean kept = true;
-
- if (mWindowManager != null) {
- mWindowManager.deferSurfaceLayout();
- }
- try {
- if (values != null) {
- changes = updateGlobalConfigurationLocked(values, initLocale, persistent, userId,
- deferResume);
- }
-
- kept = ensureConfigAndVisibilityAfterUpdate(starting, changes);
- } finally {
- if (mWindowManager != null) {
- mWindowManager.continueSurfaceLayout();
- }
- }
-
- if (result != null) {
- result.changes = changes;
- result.activityRelaunched = !kept;
- }
- return kept;
- }
-
- /**
- * Returns true if this configuration change is interesting enough to send an
- * {@link Intent#ACTION_SPLIT_CONFIGURATION_CHANGED} broadcast.
- */
- private static boolean isSplitConfigurationChange(int configDiff) {
- return (configDiff & (ActivityInfo.CONFIG_LOCALE | ActivityInfo.CONFIG_DENSITY)) != 0;
- }
-
- /** Update default (global) configuration and notify listeners about changes. */
- private int updateGlobalConfigurationLocked(@NonNull Configuration values, boolean initLocale,
- boolean persistent, int userId, boolean deferResume) {
- mActivityTaskManager.mTempConfig.setTo(getGlobalConfiguration());
- final int changes = mActivityTaskManager.mTempConfig.updateFrom(values);
- if (changes == 0) {
- // Since calling to Activity.setRequestedOrientation leads to freezing the window with
- // setting WindowManagerService.mWaitingForConfig to true, it is important that we call
- // performDisplayOverrideConfigUpdate in order to send the new display configuration
- // (even if there are no actual changes) to unfreeze the window.
- performDisplayOverrideConfigUpdate(values, deferResume, DEFAULT_DISPLAY);
- return 0;
- }
-
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.i(TAG_CONFIGURATION,
- "Updating global configuration to: " + values);
-
- EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
- StatsLog.write(StatsLog.RESOURCE_CONFIGURATION_CHANGED,
- values.colorMode,
- values.densityDpi,
- values.fontScale,
- values.hardKeyboardHidden,
- values.keyboard,
- values.keyboardHidden,
- values.mcc,
- values.mnc,
- values.navigation,
- values.navigationHidden,
- values.orientation,
- values.screenHeightDp,
- values.screenLayout,
- values.screenWidthDp,
- values.smallestScreenWidthDp,
- values.touchscreen,
- values.uiMode);
-
-
- if (!initLocale && !values.getLocales().isEmpty() && values.userSetLocale) {
- final LocaleList locales = values.getLocales();
- int bestLocaleIndex = 0;
- if (locales.size() > 1) {
- if (mSupportedSystemLocales == null) {
- mSupportedSystemLocales = Resources.getSystem().getAssets().getLocales();
- }
- bestLocaleIndex = Math.max(0, locales.getFirstMatchIndex(mSupportedSystemLocales));
- }
- SystemProperties.set("persist.sys.locale",
- locales.get(bestLocaleIndex).toLanguageTag());
- LocaleList.setDefault(locales, bestLocaleIndex);
- mHandler.sendMessage(mHandler.obtainMessage(SEND_LOCALE_TO_MOUNT_DAEMON_MSG,
- locales.get(bestLocaleIndex)));
- }
-
- mActivityTaskManager.mConfigurationSeq = Math.max(++mActivityTaskManager.mConfigurationSeq, 1);
- mActivityTaskManager.mTempConfig.seq = mActivityTaskManager.mConfigurationSeq;
-
- // Update stored global config and notify everyone about the change.
- mStackSupervisor.onConfigurationChanged(mActivityTaskManager.mTempConfig);
-
- Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + mActivityTaskManager.mTempConfig);
- // TODO(multi-display): Update UsageEvents#Event to include displayId.
- mUsageStatsService.reportConfigurationChange(mActivityTaskManager.mTempConfig,
- mUserController.getCurrentUserId());
-
- // TODO: If our config changes, should we auto dismiss any currently showing dialogs?
- updateShouldShowDialogsLocked(mActivityTaskManager.mTempConfig);
-
- AttributeCache ac = AttributeCache.instance();
- if (ac != null) {
- ac.updateConfiguration(mActivityTaskManager.mTempConfig);
- }
-
- // Make sure all resources in our process are updated right now, so that anyone who is going
- // to retrieve resource values after we return will be sure to get the new ones. This is
- // especially important during boot, where the first config change needs to guarantee all
- // resources have that config before following boot code is executed.
- mSystemThread.applyConfigurationToResources(mActivityTaskManager.mTempConfig);
-
- // We need another copy of global config because we're scheduling some calls instead of
- // running them in place. We need to be sure that object we send will be handled unchanged.
- final Configuration configCopy = new Configuration(mActivityTaskManager.mTempConfig);
- if (persistent && Settings.System.hasInterestingConfigurationChanges(changes)) {
- Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
- msg.obj = configCopy;
- msg.arg1 = userId;
- mHandler.sendMessage(msg);
- }
-
- for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
- ProcessRecord app = mLruProcesses.get(i);
- try {
- if (app.thread != null) {
- if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Sending to proc "
- + app.processName + " new config " + configCopy);
- mActivityTaskManager.getLifecycleManager().scheduleTransaction(app.thread,
- ConfigurationChangeItem.obtain(configCopy));
- }
- } catch (Exception e) {
- Slog.e(TAG_CONFIGURATION, "Failed to schedule configuration change", e);
- }
- }
-
- Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_REPLACE_PENDING
- | Intent.FLAG_RECEIVER_FOREGROUND
- | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
- broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
- OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
- UserHandle.USER_ALL);
- if ((changes & ActivityInfo.CONFIG_LOCALE) != 0) {
- intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
- intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND
- | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
- | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
- if (initLocale || !mProcessesReady) {
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- }
- broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
- OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
- UserHandle.USER_ALL);
- }
-
- // Send a broadcast to PackageInstallers if the configuration change is interesting
- // for the purposes of installing additional splits.
- if (!initLocale && isSplitConfigurationChange(changes)) {
- intent = new Intent(Intent.ACTION_SPLIT_CONFIGURATION_CHANGED);
- intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
- | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
-
- // Typically only app stores will have this permission.
- String[] permissions = new String[] { android.Manifest.permission.INSTALL_PACKAGES };
- broadcastIntentLocked(null, null, intent, null, null, 0, null, null, permissions,
- OP_NONE, null, false, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
- }
-
- // Override configuration of the default display duplicates global config, so we need to
- // update it also. This will also notify WindowManager about changes.
- performDisplayOverrideConfigUpdate(mStackSupervisor.getConfiguration(), deferResume,
- DEFAULT_DISPLAY);
-
- return changes;
- }
-
- boolean updateDisplayOverrideConfigurationLocked(Configuration values, ActivityRecord starting,
- boolean deferResume, int displayId) {
- return updateDisplayOverrideConfigurationLocked(values, starting, deferResume /* deferResume */,
- displayId, null /* result */);
- }
-
- /**
- * Updates override configuration specific for the selected display. If no config is provided,
- * new one will be computed in WM based on current display info.
- */
- boolean updateDisplayOverrideConfigurationLocked(Configuration values,
- ActivityRecord starting, boolean deferResume, int displayId,
- ActivityTaskManagerService.UpdateConfigurationResult result) {
- int changes = 0;
- boolean kept = true;
-
- if (mWindowManager != null) {
- mWindowManager.deferSurfaceLayout();
- }
- try {
- if (values != null) {
- if (displayId == DEFAULT_DISPLAY) {
- // Override configuration of the default display duplicates global config, so
- // we're calling global config update instead for default display. It will also
- // apply the correct override config.
- changes = updateGlobalConfigurationLocked(values, false /* initLocale */,
- false /* persistent */, UserHandle.USER_NULL /* userId */, deferResume);
- } else {
- changes = performDisplayOverrideConfigUpdate(values, deferResume, displayId);
- }
- }
-
- kept = ensureConfigAndVisibilityAfterUpdate(starting, changes);
- } finally {
- if (mWindowManager != null) {
- mWindowManager.continueSurfaceLayout();
- }
- }
-
- if (result != null) {
- result.changes = changes;
- result.activityRelaunched = !kept;
- }
- return kept;
- }
-
- private int performDisplayOverrideConfigUpdate(Configuration values, boolean deferResume,
- int displayId) {
- mActivityTaskManager.mTempConfig.setTo(mStackSupervisor.getDisplayOverrideConfiguration(displayId));
- final int changes = mActivityTaskManager.mTempConfig.updateFrom(values);
- if (changes != 0) {
- Slog.i(TAG, "Override config changes=" + Integer.toHexString(changes) + " "
- + mActivityTaskManager.mTempConfig + " for displayId=" + displayId);
- mStackSupervisor.setDisplayOverrideConfiguration(mActivityTaskManager.mTempConfig, displayId);
-
- final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0;
- if (isDensityChange && displayId == DEFAULT_DISPLAY) {
- mAppWarnings.onDensityChanged();
-
- killAllBackgroundProcessesExcept(N,
- ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
- }
- }
-
- // Update the configuration with WM first and check if any of the stacks need to be resized
- // due to the configuration change. If so, resize the stacks now and do any relaunches if
- // necessary. This way we don't need to relaunch again afterwards in
- // ensureActivityConfiguration().
- if (mWindowManager != null) {
- final int[] resizedStacks =
- mWindowManager.setNewDisplayOverrideConfiguration(mActivityTaskManager.mTempConfig, displayId);
- if (resizedStacks != null) {
- for (int stackId : resizedStacks) {
- resizeStackWithBoundsFromWindowManager(stackId, deferResume);
- }
- }
- }
-
- return changes;
- }
-
- /** Applies latest configuration and/or visibility updates if needed. */
- private boolean ensureConfigAndVisibilityAfterUpdate(ActivityRecord starting, int changes) {
- boolean kept = true;
- final ActivityStack mainStack = mStackSupervisor.getFocusedStack();
- // mainStack is null during startup.
- if (mainStack != null) {
- if (changes != 0 && starting == null) {
- // If the configuration changed, and the caller is not already
- // in the process of starting an activity, then find the top
- // activity to check if its configuration needs to change.
- starting = mainStack.topRunningActivityLocked();
- }
-
- if (starting != null) {
- kept = starting.ensureActivityConfiguration(changes,
- false /* preserveWindow */);
- // And we need to make sure at this point that all other activities
- // are made visible with the correct configuration.
- mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes,
- !PRESERVE_WINDOWS);
- }
- }
-
- return kept;
- }
-
- /** Helper method that requests bounds from WM and applies them to stack. */
- private void resizeStackWithBoundsFromWindowManager(int stackId, boolean deferResume) {
- final Rect newStackBounds = new Rect();
- final ActivityStack stack = mStackSupervisor.getStack(stackId);
-
- // TODO(b/71548119): Revert CL introducing below once cause of mismatch is found.
- if (stack == null) {
- final StringWriter writer = new StringWriter();
- final PrintWriter printWriter = new PrintWriter(writer);
- mStackSupervisor.dumpDisplays(printWriter);
- printWriter.flush();
-
- Log.wtf(TAG, "stack not found:" + stackId + " displays:" + writer);
- }
-
- stack.getBoundsForNewConfiguration(newStackBounds);
- mStackSupervisor.resizeStackLocked(
- stack, !newStackBounds.isEmpty() ? newStackBounds : null /* bounds */,
- null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
- false /* preserveWindows */, false /* allowResizeInDockedMode */, deferResume);
- }
-
/**
* Decide based on the configuration whether we should show the ANR,
* crash, etc dialogs. The idea is that if there is no affordance to
@@ -19779,7 +19041,7 @@
* A thought: SystemUI might also want to get told about this, the Power
* dialog / global actions also might want different behaviors.
*/
- private void updateShouldShowDialogsLocked(Configuration config) {
+ void updateShouldShowDialogsLocked(Configuration config) {
final boolean inputMethodExists = !(config.keyboard == Configuration.KEYBOARD_NOKEYS
&& config.touchscreen == Configuration.TOUCHSCREEN_NOTOUCH
&& config.navigation == Configuration.NAVIGATION_NONAV);
@@ -19944,7 +19206,7 @@
if (app.thread == null) {
app.adjSeq = mAdjSeq;
- app.curSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
+ app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_BACKGROUND);
app.curProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
app.curAdj=app.curRawAdj=ProcessList.CACHED_APP_MAX_ADJ;
app.completedAdjSeq = app.adjSeq;
@@ -19957,7 +19219,7 @@
app.empty = false;
app.cached = false;
- final int activitiesSize = app.activities.size();
+ final WindowProcessController wpc = app.getWindowProcessController();
final int appUid = app.info.uid;
final int logUid = mCurOomAdjUid;
@@ -19973,7 +19235,7 @@
app.adjSeq = mAdjSeq;
app.curRawAdj = app.maxAdj;
app.foregroundActivities = false;
- app.curSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+ app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT);
app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT;
// System processes can do UI, and when they do we want to have
// them trim their memory after the user leaves the UI. To
@@ -19982,29 +19244,24 @@
app.systemNoUi = true;
if (app == TOP_APP) {
app.systemNoUi = false;
- app.curSchedGroup = ProcessList.SCHED_GROUP_TOP_APP;
+ app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);
app.adjType = "pers-top-activity";
} else if (app.hasTopUi) {
// sched group/proc state adjustment is below
app.systemNoUi = false;
app.adjType = "pers-top-ui";
- } else if (activitiesSize > 0) {
- for (int j = 0; j < activitiesSize; j++) {
- final ActivityRecord r = app.activities.get(j);
- if (r.visible) {
- app.systemNoUi = false;
- }
- }
+ } else if (wpc.hasVisibleActivities()) {
+ app.systemNoUi = false;
}
if (!app.systemNoUi) {
if (mWakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE) {
// screen on, promote UI
app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT_UI;
- app.curSchedGroup = ProcessList.SCHED_GROUP_TOP_APP;
+ app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);
} else {
// screen off, restrict UI scheduling
app.curProcState = ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
- app.curSchedGroup = ProcessList.SCHED_GROUP_RESTRICTED;
+ app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_RESTRICTED);
}
}
app.curAdj = app.maxAdj;
@@ -20103,120 +19360,127 @@
}
// Examine all activities if not already foreground.
- if (!foregroundActivities && activitiesSize > 0) {
- int minLayer = ProcessList.VISIBLE_APP_LAYER_MAX;
- for (int j = 0; j < activitiesSize; j++) {
- final ActivityRecord r = app.activities.get(j);
- if (r.app != app) {
- Log.e(TAG, "Found activity " + r + " in proc activity list using " + r.app
- + " instead of expected " + app);
- if (r.app == null || (r.app.uid == app.uid)) {
- // Only fix things up when they look sane
- r.setProcess(app);
- } else {
- continue;
- }
- }
- if (r.visible) {
- // App has a visible activity; only upgrade adjustment.
- if (adj > ProcessList.VISIBLE_APP_ADJ) {
- adj = ProcessList.VISIBLE_APP_ADJ;
- app.adjType = "vis-activity";
- if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
- reportOomAdjMessageLocked(TAG_OOM_ADJ,
- "Raise adj to vis-activity: " + app);
+ if (!foregroundActivities && wpc.hasActivities()) {
+ final int[] adjHolder = new int[1];
+ adjHolder[0] = adj;
+ final boolean[] foregroundActivitiesHolder = new boolean[1];
+ foregroundActivitiesHolder[0] = foregroundActivities;
+ int[] procStateHolder = new int[1];
+ procStateHolder[0] = procState;
+ int[] schedGroupHolder = new int[1];
+ schedGroupHolder[0] = schedGroup;
+
+ int minLayer = wpc.computeOomAdjFromActivities(ProcessList.VISIBLE_APP_LAYER_MAX,
+ new WindowProcessController.ComputeOomAdjCallback() {
+ @Override
+ public void onVisibleActivity() {
+ // App has a visible activity; only upgrade adjustment.
+ if (adjHolder[0] > ProcessList.VISIBLE_APP_ADJ) {
+ adjHolder[0] = ProcessList.VISIBLE_APP_ADJ;
+ app.adjType = "vis-activity";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ,
+ "Raise adj to vis-activity: " + app);
+ }
+ }
+ if (procStateHolder[0] > PROCESS_STATE_CUR_TOP) {
+ procStateHolder[0] = PROCESS_STATE_CUR_TOP;
+ app.adjType = "vis-activity";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ,
+ "Raise procstate to vis-activity (top): " + app);
+ }
+ }
+ if (schedGroupHolder[0] < ProcessList.SCHED_GROUP_DEFAULT) {
+ schedGroupHolder[0] = ProcessList.SCHED_GROUP_DEFAULT;
+ }
+ app.cached = false;
+ app.empty = false;
+ foregroundActivitiesHolder[0] = true;
}
- }
- if (procState > PROCESS_STATE_CUR_TOP) {
- procState = PROCESS_STATE_CUR_TOP;
- app.adjType = "vis-activity";
- if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
- reportOomAdjMessageLocked(TAG_OOM_ADJ,
- "Raise procstate to vis-activity (top): " + app);
+
+ @Override
+ public void onPausedActivity() {
+ if (adjHolder[0] > ProcessList.PERCEPTIBLE_APP_ADJ) {
+ adjHolder[0] = ProcessList.PERCEPTIBLE_APP_ADJ;
+ app.adjType = "pause-activity";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ,
+ "Raise adj to pause-activity: " + app);
+ }
+ }
+ if (procStateHolder[0] > PROCESS_STATE_CUR_TOP) {
+ procStateHolder[0] = PROCESS_STATE_CUR_TOP;
+ app.adjType = "pause-activity";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ,
+ "Raise procstate to pause-activity (top): " + app);
+ }
+ }
+ if (schedGroupHolder[0] < ProcessList.SCHED_GROUP_DEFAULT) {
+ schedGroupHolder[0] = ProcessList.SCHED_GROUP_DEFAULT;
+ }
+ app.cached = false;
+ app.empty = false;
+ foregroundActivitiesHolder[0] = true;
}
- }
- if (schedGroup < ProcessList.SCHED_GROUP_DEFAULT) {
- schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
- }
- app.cached = false;
- app.empty = false;
- foregroundActivities = true;
- final TaskRecord task = r.getTask();
- if (task != null && minLayer > 0) {
- final int layer = task.mLayerRank;
- if (layer >= 0 && minLayer > layer) {
- minLayer = layer;
+
+ @Override
+ public void onStoppingActivity(boolean finishing) {
+ if (adjHolder[0] > ProcessList.PERCEPTIBLE_APP_ADJ) {
+ adjHolder[0] = ProcessList.PERCEPTIBLE_APP_ADJ;
+ app.adjType = "stop-activity";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ,
+ "Raise adj to stop-activity: " + app);
+ }
+ }
+ // For the process state, we will at this point consider the process to
+ // be cached. It will be cached either as an activity or empty depending
+ // on whether the activity is finishing. We do this so that we can treat
+ // the process as cached for purposes of memory trimming (determining
+ // current memory level, trim command to send to process) since there
+ // can be an arbitrary number of stopping processes and they should soon
+ // all go into the cached state.
+ if (!finishing) {
+ if (procStateHolder[0] > PROCESS_STATE_LAST_ACTIVITY) {
+ procStateHolder[0] = PROCESS_STATE_LAST_ACTIVITY;
+ app.adjType = "stop-activity";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ,
+ "Raise procstate to stop-activity: " + app);
+ }
+ }
+ }
+ app.cached = false;
+ app.empty = false;
+ foregroundActivitiesHolder[0] = true;
}
- }
- break;
- } else if (r.isState(ActivityState.PAUSING, ActivityState.PAUSED)) {
- if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
- adj = ProcessList.PERCEPTIBLE_APP_ADJ;
- app.adjType = "pause-activity";
- if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
- reportOomAdjMessageLocked(TAG_OOM_ADJ,
- "Raise adj to pause-activity: " + app);
- }
- }
- if (procState > PROCESS_STATE_CUR_TOP) {
- procState = PROCESS_STATE_CUR_TOP;
- app.adjType = "pause-activity";
- if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
- reportOomAdjMessageLocked(TAG_OOM_ADJ,
- "Raise procstate to pause-activity (top): " + app);
- }
- }
- if (schedGroup < ProcessList.SCHED_GROUP_DEFAULT) {
- schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
- }
- app.cached = false;
- app.empty = false;
- foregroundActivities = true;
- } else if (r.isState(ActivityState.STOPPING)) {
- if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
- adj = ProcessList.PERCEPTIBLE_APP_ADJ;
- app.adjType = "stop-activity";
- if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
- reportOomAdjMessageLocked(TAG_OOM_ADJ,
- "Raise adj to stop-activity: " + app);
- }
- }
- // For the process state, we will at this point consider the
- // process to be cached. It will be cached either as an activity
- // or empty depending on whether the activity is finishing. We do
- // this so that we can treat the process as cached for purposes of
- // memory trimming (determing current memory level, trim command to
- // send to process) since there can be an arbitrary number of stopping
- // processes and they should soon all go into the cached state.
- if (!r.finishing) {
- if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
- procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
- app.adjType = "stop-activity";
- if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
- reportOomAdjMessageLocked(TAG_OOM_ADJ,
- "Raise procstate to stop-activity: " + app);
+
+ @Override
+ public void onOtherActivity() {
+ if (procStateHolder[0] > PROCESS_STATE_CACHED_ACTIVITY) {
+ procStateHolder[0] = PROCESS_STATE_CACHED_ACTIVITY;
+ app.adjType = "cch-act";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ,
+ "Raise procstate to cached activity: " + app);
+ }
}
}
- }
- app.cached = false;
- app.empty = false;
- foregroundActivities = true;
- } else {
- if (procState > ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
- procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
- app.adjType = "cch-act";
- if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
- reportOomAdjMessageLocked(TAG_OOM_ADJ,
- "Raise procstate to cached activity: " + app);
- }
- }
- }
- }
+ });
+
+ adj = adjHolder[0];
+ foregroundActivities = foregroundActivitiesHolder[0];
+ procState = procStateHolder[0];
+ schedGroup = schedGroupHolder[0];
+
if (adj == ProcessList.VISIBLE_APP_ADJ) {
adj += minLayer;
}
}
- if (procState > ActivityManager.PROCESS_STATE_CACHED_RECENT && app.recentTasks.size() > 0) {
+
+ if (procState > ActivityManager.PROCESS_STATE_CACHED_RECENT && app.hasRecentTasks()) {
procState = ActivityManager.PROCESS_STATE_CACHED_RECENT;
app.adjType = "cch-rec";
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
@@ -20226,7 +19490,7 @@
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
|| procState > ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
- if (app.foregroundServices) {
+ if (app.hasForegroundServices()) {
// The user is aware of this app, so make it visible.
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
@@ -20287,7 +19551,7 @@
}
}
- if (app == mHomeProcess) {
+ if (wpc == mActivityTaskManager.mHomeProcess) {
if (adj > ProcessList.HOME_APP_ADJ) {
// This process is hosting what we currently consider to be the
// home app, so we don't want to let it go into the background.
@@ -20308,7 +19572,7 @@
}
}
- if (app == mPreviousProcess && app.activities.size() > 0) {
+ if (wpc == mActivityTaskManager.mPreviousProcess && app.hasActivities()) {
if (adj > ProcessList.PREVIOUS_APP_ADJ) {
// This was the previous process that showed UI to the user.
// We want to try to keep it around more aggressively, to give
@@ -20321,8 +19585,8 @@
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to prev: " + app);
}
}
- if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
- procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
+ if (procState > PROCESS_STATE_LAST_ACTIVITY) {
+ procState = PROCESS_STATE_LAST_ACTIVITY;
app.adjType = "previous";
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to prev: " + app);
@@ -20385,7 +19649,7 @@
"Raise procstate to started service: " + app);
}
}
- if (app.hasShownUi && app != mHomeProcess) {
+ if (app.hasShownUi && wpc != mActivityTaskManager.mHomeProcess) {
// If this process has shown some UI, let it immediately
// go to the LRU list because it may be pretty heavy with
// UI stuff. We'll tag it with a label just to help
@@ -20448,7 +19712,7 @@
}
int clientAdj = client.curRawAdj;
int clientProcState = client.curProcState;
- if (clientProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
+ if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
// If the other app is cached for any reason, for purposes here
// we are going to consider it empty. The specific cached state
// doesn't propagate except under certain conditions.
@@ -20458,7 +19722,7 @@
if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
// Not doing bind OOM management, so treat
// this guy more like a started service.
- if (app.hasShownUi && app != mHomeProcess) {
+ if (app.hasShownUi && wpc != mActivityTaskManager.mHomeProcess) {
// If this process has shown some UI, let it immediately
// go to the LRU list because it may be pretty heavy with
// UI stuff. We'll tag it with a label just to help
@@ -20491,7 +19755,7 @@
// about letting this process get into the LRU
// list to be killed and restarted if needed for
// memory.
- if (app.hasShownUi && app != mHomeProcess
+ if (app.hasShownUi && wpc != mActivityTaskManager.mHomeProcess
&& clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
if (adj >= ProcessList.CACHED_APP_MIN_ADJ) {
adjType = "cch-bound-ui-services";
@@ -20535,9 +19799,10 @@
// This will treat important bound services identically to
// the top app, which may behave differently than generic
// foreground work.
- if (client.curSchedGroup > schedGroup) {
+ final int curSchedGroup = client.getCurrentSchedulingGroup();
+ if (curSchedGroup > schedGroup) {
if ((cr.flags&Context.BIND_IMPORTANT) != 0) {
- schedGroup = client.curSchedGroup;
+ schedGroup = curSchedGroup;
} else {
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
}
@@ -20675,14 +19940,14 @@
}
int clientAdj = client.curRawAdj;
int clientProcState = client.curProcState;
- if (clientProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
+ if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
// If the other app is cached for any reason, for purposes here
// we are going to consider it empty.
clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
}
String adjType = null;
if (adj > clientAdj) {
- if (app.hasShownUi && app != mHomeProcess
+ if (app.hasShownUi && wpc != mActivityTaskManager.mHomeProcess
&& clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
adjType = "cch-ui-provider";
} else {
@@ -20723,7 +19988,7 @@
if (procState > clientProcState) {
procState = clientProcState;
}
- if (client.curSchedGroup > schedGroup) {
+ if (client.getCurrentSchedulingGroup() > schedGroup) {
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
}
if (adjType != null) {
@@ -20776,8 +20041,8 @@
"Raise adj to recent provider: " + app);
}
}
- if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
- procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
+ if (procState > PROCESS_STATE_LAST_ACTIVITY) {
+ procState = PROCESS_STATE_LAST_ACTIVITY;
app.adjType = "recent-provider";
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ,
@@ -20839,7 +20104,7 @@
} else if (app.treatLikeActivity) {
// This is a cached process, but somebody wants us to treat it like it has
// an activity, okay!
- procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
+ procState = PROCESS_STATE_CACHED_ACTIVITY;
app.adjType = "cch-as-act";
}
}
@@ -20898,7 +20163,7 @@
// worry about this for max adj above, since max adj will always be used to
// keep it out of the cached vaues.
app.curAdj = app.modifyRawOomAdj(adj);
- app.curSchedGroup = schedGroup;
+ app.setCurrentSchedulingGroup(schedGroup);
app.curProcState = procState;
app.foregroundActivities = foregroundActivities;
app.completedAdjSeq = mAdjSeq;
@@ -20915,7 +20180,8 @@
EventLogTags.writeAmPss(proc.pid, proc.uid, proc.processName, pss * 1024, uss * 1024,
swapPss * 1024, rss * 1024, statType, procState, pssDuration);
proc.lastPssTime = now;
- proc.baseProcessTracker.addPss(pss, uss, rss, true, statType, pssDuration, proc.pkgList);
+ proc.baseProcessTracker.addPss(
+ pss, uss, rss, true, statType, pssDuration, proc.pkgList.mPkgList);
if (DEBUG_PSS) Slog.d(TAG_PSS,
"pss of " + proc.toShortString() + ": " + pss + " lastPss=" + proc.lastPss
+ " state=" + ProcessList.makeProcStateString(procState));
@@ -21266,7 +20532,7 @@
}
app.kill("excessive cpu " + cputimeUsed + " during " + uptimeSince
+ " dur=" + checkDur + " limit=" + cpuLimit, true);
- app.baseProcessTracker.reportExcessiveCpu(app.pkgList);
+ app.baseProcessTracker.reportExcessiveCpu(app.pkgList.mPkgList);
}
}
app.lastCpuTime = app.curCpuTime;
@@ -21295,12 +20561,13 @@
app.verifiedAdj = ProcessList.INVALID_ADJ;
}
- if (app.setSchedGroup != app.curSchedGroup) {
+ final int curSchedGroup = app.getCurrentSchedulingGroup();
+ if (app.setSchedGroup != curSchedGroup) {
int oldSchedGroup = app.setSchedGroup;
- app.setSchedGroup = app.curSchedGroup;
+ app.setSchedGroup = curSchedGroup;
if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mCurOomAdjUid == app.uid) {
String msg = "Setting sched group of " + app.processName
- + " to " + app.curSchedGroup + ": " + app.adjType;
+ + " to " + curSchedGroup + ": " + app.adjType;
reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
}
if (app.waitingToKill != null && app.curReceivers.isEmpty()
@@ -21309,7 +20576,7 @@
success = false;
} else {
int processGroup;
- switch (app.curSchedGroup) {
+ switch (curSchedGroup) {
case ProcessList.SCHED_GROUP_BACKGROUND:
processGroup = THREAD_GROUP_BG_NONINTERACTIVE;
break;
@@ -21327,10 +20594,11 @@
long oldId = Binder.clearCallingIdentity();
try {
setProcessGroup(app.pid, processGroup);
- if (app.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
+ if (curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
// do nothing if we already switched to RT
if (oldSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
- mActivityTaskManager.onTopProcChangedLocked(app);
+ mActivityTaskManager.onTopProcChangedLocked(
+ app.getWindowProcessController());
if (mUseFifoUiScheduling) {
// Switch UI pipeline for app to SCHED_FIFO
app.savedPriority = Process.getThreadPriority(app.pid);
@@ -21361,8 +20629,9 @@
}
}
} else if (oldSchedGroup == ProcessList.SCHED_GROUP_TOP_APP &&
- app.curSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
- mActivityTaskManager.onTopProcChangedLocked(app);
+ curSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
+ mActivityTaskManager.onTopProcChangedLocked(
+ app.getWindowProcessController());
if (mUseFifoUiScheduling) {
try {
// Reset UI pipeline to SCHED_OTHER
@@ -21391,7 +20660,7 @@
} catch (Exception e) {
if (false) {
Slog.w(TAG, "Failed setting process group of " + app.pid
- + " to " + app.curSchedGroup);
+ + " to " + app.getCurrentSchedulingGroup());
Slog.w(TAG, "at location", e);
}
} finally {
@@ -21403,16 +20672,16 @@
app.repForegroundActivities = app.foregroundActivities;
changes |= ProcessChangeItem.CHANGE_ACTIVITIES;
}
- if (app.repProcState != app.curProcState) {
- app.repProcState = app.curProcState;
+ if (app.getReportedProcState() != app.curProcState) {
+ app.setReportedProcState(app.curProcState);
if (app.thread != null) {
try {
if (false) {
//RuntimeException h = new RuntimeException("here");
- Slog.i(TAG, "Sending new process state " + app.repProcState
+ Slog.i(TAG, "Sending new process state " + app.getReportedProcState()
+ " to " + app /*, h*/);
}
- app.thread.setProcessState(app.repProcState);
+ app.thread.setProcessState(app.getReportedProcState());
} catch (RemoteException e) {
}
}
@@ -21699,10 +20968,9 @@
}
private final void setProcessTrackerStateLocked(ProcessRecord proc, int memFactor, long now) {
- if (proc.thread != null) {
- if (proc.baseProcessTracker != null) {
- proc.baseProcessTracker.setState(proc.repProcState, memFactor, now, proc.pkgList);
- }
+ if (proc.thread != null && proc.baseProcessTracker != null) {
+ proc.baseProcessTracker.setState(
+ proc.getReportedProcState(), memFactor, now, proc.pkgList.mPkgList);
}
}
@@ -21720,8 +20988,8 @@
@GuardedBy("this")
final void updateProcessForegroundLocked(ProcessRecord proc, boolean isForeground,
boolean oomAdj) {
- if (isForeground != proc.foregroundServices) {
- proc.foregroundServices = isForeground;
+ if (isForeground != proc.hasForegroundServices()) {
+ proc.setHasForegroundServices(isForeground);
ArrayList<ProcessRecord> curProcs = mForegroundPackages.get(proc.info.packageName,
proc.info.uid);
if (isForeground) {
@@ -21791,7 +21059,8 @@
@GuardedBy("this")
final boolean updateOomAdjLocked(ProcessRecord app, boolean oomAdjAll) {
final ActivityRecord TOP_ACT = resumedAppLocked();
- final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
+ final ProcessRecord TOP_APP = TOP_ACT != null && TOP_ACT.hasProcess()
+ ? (ProcessRecord) TOP_ACT.app.mOwner : null;
final boolean wasCached = app.cached;
mAdjSeq++;
@@ -21814,20 +21083,23 @@
}
@GuardedBy("this")
- final void updateOomAdjLocked() {
+ ProcessRecord getTopAppLocked() {
final ActivityRecord TOP_ACT = resumedAppLocked();
- final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
+ if (TOP_ACT != null && TOP_ACT.hasProcess()) {
+ return (ProcessRecord) TOP_ACT.app.mOwner;
+ } else {
+ return null;
+ }
+ }
+
+ @GuardedBy("this")
+ final void updateOomAdjLocked() {
+ final ProcessRecord TOP_APP = getTopAppLocked();
final long now = SystemClock.uptimeMillis();
final long nowElapsed = SystemClock.elapsedRealtime();
final long oldTime = now - ProcessList.MAX_EMPTY_TIME;
final int N = mLruProcesses.size();
- if (false) {
- RuntimeException e = new RuntimeException();
- e.fillInStackTrace();
- Slog.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
- }
-
// Reset state in all uid records.
for (int i=mActiveUids.size()-1; i>=0; i--) {
final UidRecord uidRec = mActiveUids.valueAt(i);
@@ -21903,7 +21175,7 @@
// to the process, do that now.
if (app.curAdj >= ProcessList.UNKNOWN_ADJ) {
switch (app.curProcState) {
- case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
+ case PROCESS_STATE_CACHED_ACTIVITY:
case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
case ActivityManager.PROCESS_STATE_CACHED_RECENT:
// This process is a cached process holding activities...
@@ -21989,7 +21261,7 @@
// Count the number of process types.
switch (app.curProcState) {
- case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
+ case PROCESS_STATE_CACHED_ACTIVITY:
case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
mNumCachedHiddenProcs++;
numCached++;
@@ -22032,7 +21304,7 @@
if (uidRec.curProcState > app.curProcState) {
uidRec.curProcState = app.curProcState;
}
- if (app.foregroundServices) {
+ if (app.hasForegroundServices()) {
uidRec.foregroundServices = true;
}
}
@@ -22107,8 +21379,8 @@
}
int factor = numTrimming/3;
int minFactor = 2;
- if (mHomeProcess != null) minFactor++;
- if (mPreviousProcess != null) minFactor++;
+ if (mActivityTaskManager.mHomeProcess != null) minFactor++;
+ if (mActivityTaskManager.mPreviousProcess != null) minFactor++;
if (factor < minFactor) factor = minFactor;
int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
for (int i=N-1; i>=0; i--) {
@@ -22126,19 +21398,6 @@
app.thread.scheduleTrimMemory(curLevel);
} catch (RemoteException e) {
}
- if (false) {
- // For now we won't do this; our memory trimming seems
- // to be good enough at this point that destroying
- // activities causes more harm than good.
- if (curLevel >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE
- && app != mHomeProcess && app != mPreviousProcess) {
- // Need to do this on its own message because the stack may not
- // be in a consistent state at this point.
- // For these apps we will also finish their activities
- // to help them free memory.
- mStackSupervisor.scheduleDestroyAllActivities(app, "trim");
- }
- }
}
app.trimMemoryLevel = curLevel;
step++;
@@ -22689,7 +21948,7 @@
// has been removed.
for (int i=mRemovedProcesses.size()-1; i>=0; i--) {
final ProcessRecord app = mRemovedProcesses.get(i);
- if (app.activities.size() == 0 && app.recentTasks.size() == 0
+ if (!app.hasActivitiesOrRecentTasks()
&& app.curReceivers.isEmpty() && app.services.size() == 0) {
Slog.i(
TAG, "Exiting empty application process "
@@ -22708,7 +21967,7 @@
cleanUpApplicationRecordLocked(app, false, true, -1, false /*replacingPid*/);
mRemovedProcesses.remove(i);
- if (app.persistent) {
+ if (app.isPersistent()) {
addAppLocked(app.info, null, false, null /* ABI override */);
}
}
@@ -22734,7 +21993,7 @@
for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
ProcessRecord r = mLruProcesses.get(i);
- if (r.thread != null && r.persistent) {
+ if (r.thread != null && r.isPersistent()) {
sendSignal(r.pid, sig);
}
}
@@ -23230,15 +22489,6 @@
}
@Override
- public void onUserRemoved(int userId) {
- synchronized (ActivityManagerService.this) {
- ActivityManagerService.this.onUserStoppedLocked(userId);
- }
- mBatteryStatsService.onUserRemoved(userId);
- mUserController.onUserRemoved(userId);
- }
-
- @Override
public void killForegroundAppsForUser(int userHandle) {
synchronized (ActivityManagerService.this) {
final ArrayList<ProcessRecord> procs = new ArrayList<>();
@@ -23248,7 +22498,7 @@
final int NA = apps.size();
for (int ia = 0; ia < NA; ia++) {
final ProcessRecord app = apps.valueAt(ia);
- if (app.persistent) {
+ if (app.isPersistent()) {
// We don't kill persistent processes.
continue;
}
@@ -23297,17 +22547,6 @@
}
@Override
- public void updatePersistentConfigurationForUser(@NonNull Configuration values,
- int userId) {
- Preconditions.checkNotNull(values, "Configuration must not be null");
- Preconditions.checkArgumentNonnegative(userId, "userId " + userId + " not supported");
- synchronized (ActivityManagerService.this) {
- updateConfigurationLocked(values, null, false, true, userId,
- false /* deferResume */);
- }
- }
-
- @Override
public int getUidProcessState(int uid) {
return getUidState(uid);
}
@@ -23425,27 +22664,6 @@
}
@Override
- public void setAllowAppSwitches(@NonNull String type, int uid, int userId) {
- synchronized (ActivityManagerService.this) {
- if (mUserController.isUserRunning(userId, ActivityManager.FLAG_OR_STOPPED)) {
- ArrayMap<String, Integer> types = mAllowAppSwitchUids.get(userId);
- if (types == null) {
- if (uid < 0) {
- return;
- }
- types = new ArrayMap<>();
- mAllowAppSwitchUids.put(userId, types);
- }
- if (uid < 0) {
- types.remove(type);
- } else {
- types.put(type, uid);
- }
- }
- }
- }
-
- @Override
public boolean isRuntimeRestarted() {
return mSystemServiceManager.isRuntimeRestarted();
}
@@ -23508,6 +22726,87 @@
}
return processMemoryStates;
}
+
+ @Override
+ public int handleIncomingUser(int callingPid, int callingUid, int userId,
+ boolean allowAll, int allowMode, String name, String callerPackage) {
+ return mUserController.handleIncomingUser(callingPid, callingUid, userId, allowAll,
+ allowMode, name, callerPackage);
+ }
+
+ @Override
+ public void enforceCallingPermission(String permission, String func) {
+ ActivityManagerService.this.enforceCallingPermission(permission, func);
+ }
+
+ @Override
+ public int getCurrentUserId() {
+ return mUserController.getCurrentUserIdLU();
+ }
+
+ @Override
+ public boolean isUserRunning(int userId, int flags) {
+ synchronized (ActivityManagerService.this) {
+ return mUserController.isUserRunning(userId, flags);
+ }
+ }
+
+ @Override
+ public void trimApplications() {
+ ActivityManagerService.this.trimApplications();
+ }
+
+ public int getPackageScreenCompatMode(ApplicationInfo ai) {
+ synchronized (ActivityManagerService.this) {
+ return mCompatModePackages.computeCompatModeLocked(ai);
+ }
+ }
+
+ public void setPackageScreenCompatMode(ApplicationInfo ai, int mode) {
+ synchronized (ActivityManagerService.this) {
+ mCompatModePackages.setPackageScreenCompatModeLocked(ai, mode);
+ }
+ }
+
+ public void closeSystemDialogs(String reason) {
+ ActivityManagerService.this.closeSystemDialogs(reason);
+ }
+
+ public void killProcessesForRemovedTask(ArrayList<Object> procsToKill) {
+ synchronized (ActivityManagerService.this) {
+ for (int i = 0; i < procsToKill.size(); i++) {
+ final WindowProcessController wpc =
+ (WindowProcessController) procsToKill.get(i);
+ final ProcessRecord pr = (ProcessRecord) wpc.mOwner;
+ if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND
+ && pr.curReceivers.isEmpty()) {
+ pr.kill("remove task", true);
+ } else {
+ // We delay killing processes that are not in the background or running a
+ // receiver.
+ pr.waitingToKill = "remove task";
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean hasRunningActivity(int uid, @Nullable String packageName) {
+ if (packageName == null) return false;
+
+ synchronized (ActivityManagerService.this) {
+ for (int i = 0; i < mLruProcesses.size(); i++) {
+ final ProcessRecord pr = mLruProcesses.get(i);
+ if (pr.uid != uid) {
+ continue;
+ }
+ if (pr.getWindowProcessController().hasRunningActivity(packageName)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
}
/**
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 1611a38..9b08823 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -2,7 +2,7 @@
import static android.app.ActivityManager.START_SUCCESS;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
-import static android.app.ActivityTaskManagerInternal.APP_TRANSITION_TIMEOUT;
+import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_TIMEOUT;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
@@ -154,7 +154,7 @@
launchedActivityLaunchToken = info.launchedActivity.info.launchToken;
launchedActivityAppRecordRequiredAbi = info.launchedActivity.app == null
? null
- : info.launchedActivity.app.requiredAbi;
+ : info.launchedActivity.app.getRequiredAbi();
reason = info.reason;
startingWindowDelayMs = info.startingWindowDelayMs;
bindApplicationDelayMs = info.bindApplicationDelayMs;
@@ -246,25 +246,11 @@
// of caches might be purged so the time until it produces the first frame is very
// interesting.
final boolean processSwitch = processRecord == null
- || !hasStartedActivity(processRecord, launchedActivity);
+ || !processRecord.getWindowProcessController().hasStartedActivity(launchedActivity);
notifyActivityLaunched(resultCode, launchedActivity, processRunning, processSwitch);
}
- private boolean hasStartedActivity(ProcessRecord record, ActivityRecord launchedActivity) {
- final ArrayList<ActivityRecord> activities = record.activities;
- for (int i = activities.size() - 1; i >= 0; i--) {
- final ActivityRecord activity = activities.get(i);
- if (launchedActivity == activity) {
- continue;
- }
- if (!activity.stopped) {
- return true;
- }
- }
- return false;
- }
-
/**
* Notifies the tracker the the activity is actually launching.
*
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 0e427d6..d40b9b4 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -288,7 +288,7 @@
AppTimeTracker appTimeTracker; // set if we are tracking the time in this app/task/activity
HashSet<ConnectionRecord> connections; // All ConnectionRecord we hold
UriPermissionOwner uriPermissions; // current special URI access perms.
- ProcessRecord app; // if non-null, hosting application
+ WindowProcessController app; // if non-null, hosting application
private ActivityState mState; // current state we are in
Bundle icicle; // last saved activity state
PersistableBundle persistentState; // last persistently saved activity state
@@ -622,7 +622,7 @@
}
private void scheduleActivityMovedToDisplay(int displayId, Configuration config) {
- if (app == null || app.thread == null) {
+ if (!attachedToProcess()) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.w(TAG,
"Can't report activity moved to display - client not running, activityRecord="
+ this + ", displayId=" + displayId);
@@ -633,7 +633,7 @@
"Reporting activity moved to display" + ", activityRecord=" + this
+ ", displayId=" + displayId + ", config=" + config);
- service.getLifecycleManager().scheduleTransaction(app.thread, appToken,
+ service.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
MoveToDisplayItem.obtain(displayId, config));
} catch (RemoteException e) {
// If process died, whatever.
@@ -641,7 +641,7 @@
}
private void scheduleConfigurationChanged(Configuration config) {
- if (app == null || app.thread == null) {
+ if (attachedToProcess()) {
if (DEBUG_CONFIGURATION) Slog.w(TAG,
"Can't report activity configuration update - client not running"
+ ", activityRecord=" + this);
@@ -651,7 +651,7 @@
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + this + ", config: "
+ config);
- service.getLifecycleManager().scheduleTransaction(app.thread, appToken,
+ service.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
ActivityConfigurationChangeItem.obtain(config));
} catch (RemoteException e) {
// If process died, whatever.
@@ -659,7 +659,7 @@
}
void updateMultiWindowMode() {
- if (task == null || task.getStack() == null || app == null || app.thread == null) {
+ if (task == null || task.getStack() == null || !attachedToProcess()) {
return;
}
@@ -678,7 +678,7 @@
private void scheduleMultiWindowModeChanged(Configuration overrideConfig) {
try {
- service.getLifecycleManager().scheduleTransaction(app.thread, appToken,
+ service.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
MultiWindowModeChangeItem.obtain(mLastReportedMultiWindowMode, overrideConfig));
} catch (Exception e) {
// If process died, I don't care.
@@ -686,7 +686,7 @@
}
void updatePictureInPictureMode(Rect targetStackBounds, boolean forceUpdate) {
- if (task == null || task.getStack() == null || app == null || app.thread == null) {
+ if (task == null || task.getStack() == null || !attachedToProcess()) {
return;
}
@@ -705,7 +705,7 @@
private void schedulePictureInPictureModeChanged(Configuration overrideConfig) {
try {
- service.getLifecycleManager().scheduleTransaction(app.thread, appToken,
+ service.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
PipModeChangeItem.obtain(mLastReportedPictureInPictureMode,
overrideConfig));
} catch (Exception e) {
@@ -984,7 +984,7 @@
}
}
- void setProcess(ProcessRecord proc) {
+ void setProcess(WindowProcessController proc) {
app = proc;
final ActivityRecord root = task != null ? task.getRootActivity() : null;
if (root == this) {
@@ -992,6 +992,14 @@
}
}
+ boolean hasProcess() {
+ return app != null;
+ }
+
+ boolean attachedToProcess() {
+ return hasProcess() && app.hasThread();
+ }
+
AppWindowContainerController getWindowContainerController() {
return mWindowContainerController;
}
@@ -1220,7 +1228,7 @@
* @return whether this activity supports PiP multi-window and can be put in the pinned stack.
*/
boolean supportsPictureInPicture() {
- return service.mAm.mSupportsPictureInPicture && isActivityTypeStandardOrUndefined()
+ return service.mSupportsPictureInPicture && isActivityTypeStandardOrUndefined()
&& info.supportsPictureInPicture();
}
@@ -1233,7 +1241,7 @@
// An activity can not be docked even if it is considered resizeable because it only
// supports picture-in-picture mode but has a non-resizeable resizeMode
return super.supportsSplitScreenWindowingMode()
- && service.mAm.mSupportsSplitScreenMultiWindow && supportsResizeableMultiWindow();
+ && service.mSupportsSplitScreenMultiWindow && supportsResizeableMultiWindow();
}
/**
@@ -1241,16 +1249,16 @@
* stack.
*/
boolean supportsFreeform() {
- return service.mAm.mSupportsFreeformWindowManagement && supportsResizeableMultiWindow();
+ return service.mSupportsFreeformWindowManagement && supportsResizeableMultiWindow();
}
/**
* @return whether this activity supports non-PiP multi-window.
*/
private boolean supportsResizeableMultiWindow() {
- return service.mAm.mSupportsMultiWindow && !isActivityTypeHome()
+ return service.mSupportsMultiWindow && !isActivityTypeHome()
&& (ActivityInfo.isResizeableMode(info.resizeMode)
- || service.mAm.mForceResizableActivities);
+ || service.mForceResizableActivities);
}
/**
@@ -1366,7 +1374,7 @@
clearOptionsLocked();
}
- if (service.mAm != null) {
+ if (service != null) {
service.getTaskChangeNotificationController().notifyTaskStackChanged();
}
}
@@ -1435,13 +1443,13 @@
// - It is currently resumed or paused. i.e. it is currently visible to the user and we want
// the user to see the visual effects caused by the intent delivery now.
// - The device is sleeping and it is the top activity behind the lock screen (b/6700897).
- if ((mState == RESUMED || mState == PAUSED
- || isTopActivityWhileSleeping) && app != null && app.thread != null) {
+ if ((mState == RESUMED || mState == PAUSED || isTopActivityWhileSleeping)
+ && attachedToProcess()) {
try {
ArrayList<ReferrerIntent> ar = new ArrayList<>(1);
ar.add(rintent);
service.getLifecycleManager().scheduleTransaction(
- app.thread, appToken, NewIntentItem.obtain(ar, mState == PAUSED));
+ app.getThread(), appToken, NewIntentItem.obtain(ar, mState == PAUSED));
unsent = false;
} catch (RemoteException e) {
Slog.w(TAG, "Exception thrown sending new intent to " + this, e);
@@ -1744,7 +1752,7 @@
}
setVisible(true);
sleeping = false;
- app.pendingUiClean = true;
+ app.setPendingUiClean(true);
if (reportToClient) {
makeClientVisible();
} else {
@@ -1764,13 +1772,13 @@
void makeClientVisible() {
mClientVisibilityDeferred = false;
try {
- service.getLifecycleManager().scheduleTransaction(app.thread, appToken,
+ service.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
WindowVisibilityItem.obtain(true /* showWindow */));
if (shouldPauseWhenBecomingVisible()) {
// An activity must be in the {@link PAUSING} state for the system to validate
// the move to {@link PAUSED}.
setState(PAUSING, "makeVisibleIfNeeded");
- service.getLifecycleManager().scheduleTransaction(app.thread, appToken,
+ service.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
PauseActivityItem.obtain(finishing, false /* userLeaving */,
configChangeFlags, false /* dontReport */));
}
@@ -1816,7 +1824,7 @@
stopFreezingScreenLocked(false);
try {
if (returningOptions != null) {
- app.thread.scheduleOnNewActivityOptions(appToken, returningOptions.toBundle());
+ app.getThread().scheduleOnNewActivityOptions(appToken, returningOptions.toBundle());
}
} catch(RemoteException e) {
}
@@ -1850,9 +1858,9 @@
stopped = false;
if (isActivityTypeHome()) {
- ProcessRecord app = task.mActivities.get(0).app;
- if (app != null && app != service.mAm.mHomeProcess) {
- service.mAm.mHomeProcess = app;
+ WindowProcessController app = task.mActivities.get(0).app;
+ if (hasProcess() && app != service.mHomeProcess) {
+ service.mHomeProcess = app;
}
}
@@ -1873,8 +1881,8 @@
// Mark the point when the activity is resuming
// TODO: To be more accurate, the mark should be before the onCreate,
// not after the onResume. But for subsequent starts, onResume is fine.
- if (app != null) {
- cpuTimeAtResume = service.mAm.mProcessCpuTracker.getCpuTimeForPid(app.pid);
+ if (hasProcess()) {
+ cpuTimeAtResume = service.mAm.mProcessCpuTracker.getCpuTimeForPid(app.getPid());
} else {
cpuTimeAtResume = 0; // Couldn't get the cpu time of process
}
@@ -1970,15 +1978,15 @@
// IApplicationToken
- public boolean mayFreezeScreenLocked(ProcessRecord app) {
+ public boolean mayFreezeScreenLocked(WindowProcessController app) {
// Only freeze the screen if this activity is currently attached to
// an application, and that application is not blocked or unresponding.
// In any other case, we can't count on getting the screen unfrozen,
// so it is best to leave as-is.
- return app != null && !app.crashing && !app.notResponding;
+ return hasProcess() && !app.isCrashing() && !app.isNotResponding();
}
- public void startFreezingScreenLocked(ProcessRecord app, int configChanges) {
+ public void startFreezingScreenLocked(WindowProcessController app, int configChanges) {
if (mayFreezeScreenLocked(app)) {
mWindowContainerController.startFreezingScreen(configChanges);
}
@@ -2135,17 +2143,17 @@
@Override
public boolean keyDispatchingTimedOut(String reason, int windowPid) {
ActivityRecord anrActivity;
- ProcessRecord anrApp;
+ WindowProcessController anrApp;
boolean windowFromSameProcessAsActivity;
synchronized (service.mGlobalLock) {
anrActivity = getWaitingHistoryRecordLocked();
anrApp = app;
windowFromSameProcessAsActivity =
- app == null || app.pid == windowPid || windowPid == -1;
+ !hasProcess() || app.getPid() == windowPid || windowPid == -1;
}
if (windowFromSameProcessAsActivity) {
return service.mAm.inputDispatchingTimedOut(
- anrApp, anrActivity, this, false, reason);
+ (ProcessRecord) anrApp.mOwner, anrActivity, this, false, reason);
} else {
// In this case another process added windows using this activity token. So, we call the
// generic service input dispatch timed out method so that the right process is blamed.
@@ -2202,9 +2210,9 @@
if (!force && sleeping == _sleeping) {
return;
}
- if (app != null && app.thread != null) {
+ if (attachedToProcess()) {
try {
- app.thread.scheduleSleeping(appToken, _sleeping);
+ app.getThread().scheduleSleeping(appToken, _sleeping);
if (_sleeping && !mStackSupervisor.mGoingToSleepActivities.contains(this)) {
mStackSupervisor.mGoingToSleepActivities.add(this);
}
@@ -2253,7 +2261,7 @@
}
final boolean isDestroyable() {
- if (finishing || app == null) {
+ if (finishing || !hasProcess()) {
// This would be redundant.
return false;
}
@@ -2347,7 +2355,7 @@
displayId, displayConfig, mayFreezeScreenLocked(app));
if (config != null) {
frozenBeforeDestroy = true;
- if (!service.mAm.updateDisplayOverrideConfigurationLocked(config, this,
+ if (!service.updateDisplayOverrideConfigurationLocked(config, this,
false /* deferResume */, displayId)) {
mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
@@ -2593,7 +2601,7 @@
// If the activity isn't currently running, just leave the new configuration and it will
// pick that up next time it starts.
- if (app == null || app.thread == null) {
+ if (!attachedToProcess()) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Configuration doesn't matter not running " + this);
stopFreezingScreenLocked(false);
@@ -2614,7 +2622,7 @@
startFreezingScreenLocked(app, globalChanges);
forceNewConfig = false;
preserveWindow &= isResizeOnlyChange(changes);
- if (app == null || app.thread == null) {
+ if (!attachedToProcess()) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Config is destroying non-running " + this);
stack.destroyActivityLocked(this, true, "config");
@@ -2774,7 +2782,7 @@
} else {
lifecycleItem = PauseActivityItem.obtain();
}
- final ClientTransaction transaction = ClientTransaction.obtain(app.thread, appToken);
+ final ClientTransaction transaction = ClientTransaction.obtain(app.getThread(), appToken);
transaction.addCallback(callbackItem);
transaction.setLifecycleStateRequest(lifecycleItem);
service.getLifecycleManager().scheduleTransaction(transaction);
@@ -2804,11 +2812,11 @@
}
private boolean isProcessRunning() {
- ProcessRecord proc = app;
+ WindowProcessController proc = app;
if (proc == null) {
- proc = service.mAm.mProcessNames.get(processName, info.applicationInfo.uid);
+ proc = service.mProcessNames.get(processName, info.applicationInfo.uid);
}
- return proc != null && proc.thread != null;
+ return proc != null && proc.hasThread();
}
/**
@@ -3037,8 +3045,8 @@
proto.write(STATE, mState.toString());
proto.write(VISIBLE, visible);
proto.write(FRONT_OF_TASK, frontOfTask);
- if (app != null) {
- proto.write(PROC_ID, app.pid);
+ if (hasProcess()) {
+ proto.write(PROC_ID, app.getPid());
}
proto.write(TRANSLUCENT, !fullscreen);
proto.end(token);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 6118131..dae145d 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -367,9 +367,9 @@
static final int TRANSLUCENT_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 6;
private static class ScheduleDestroyArgs {
- final ProcessRecord mOwner;
+ final WindowProcessController mOwner;
final String mReason;
- ScheduleDestroyArgs(ProcessRecord owner, String reason) {
+ ScheduleDestroyArgs(WindowProcessController owner, String reason) {
mOwner = owner;
mReason = reason;
}
@@ -392,8 +392,8 @@
// so we need to be conservative and assume it isn't.
Slog.w(TAG, "Activity pause timeout for " + r);
synchronized (mService.mGlobalLock) {
- if (r.app != null) {
- mService.mAm.logAppTooSlow(r.app, r.pauseTime, "pausing " + r);
+ if (r.hasProcess()) {
+ mService.logAppTooSlow(r.app, r.pauseTime, "pausing " + r);
}
activityPausedLocked(r.appToken, true);
}
@@ -402,7 +402,7 @@
ActivityRecord r = (ActivityRecord)msg.obj;
synchronized (mService.mGlobalLock) {
if (r.continueLaunchTickingLocked()) {
- mService.mAm.logAppTooSlow(r.app, r.launchTickTime, "launching " + r);
+ mService.logAppTooSlow(r.app, r.launchTickTime, "launching " + r);
}
}
} break;
@@ -1453,15 +1453,15 @@
mService.mAm.updateCpuStats();
- if (prev.app != null && prev.app.thread != null) {
+ if (prev.attachedToProcess()) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
try {
EventLogTags.writeAmPauseActivity(prev.userId, System.identityHashCode(prev),
prev.shortComponentName, "userLeaving=" + userLeaving);
mService.mAm.updateUsageStats(prev, false);
- mService.getLifecycleManager().scheduleTransaction(prev.app.thread, prev.appToken,
- PauseActivityItem.obtain(prev.finishing, userLeaving,
+ mService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),
+ prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving,
prev.configChangeFlags, pauseImmediately));
} catch (Exception e) {
// Ignore exception, if process died other code will cleanup.
@@ -1563,7 +1563,7 @@
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Executing finish of activity: " + prev);
prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false,
"completedPausedLocked");
- } else if (prev.app != null) {
+ } else if (prev.hasProcess()) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueue pending stop if needed: " + prev
+ " wasStopping=" + wasStopping + " visible=" + prev.visible);
if (mStackSupervisor.mActivitiesWaitingForVisibleActivity.remove(prev)) {
@@ -1620,9 +1620,9 @@
if (prev != null) {
prev.resumeKeyDispatchingLocked();
- if (prev.app != null && prev.cpuTimeAtResume > 0
+ if (prev.hasProcess() && prev.cpuTimeAtResume > 0
&& mService.mAm.mBatteryStatsService.isOnBattery()) {
- long diff = mService.mAm.mProcessCpuTracker.getCpuTimeForPid(prev.app.pid)
+ long diff = mService.mAm.mProcessCpuTracker.getCpuTimeForPid(prev.app.getPid())
- prev.cpuTimeAtResume;
if (diff > 0) {
BatteryStatsImpl bsi = mService.mAm.mBatteryStatsService.getActiveStatistics();
@@ -1654,6 +1654,16 @@
void addToStopping(ActivityRecord r, boolean scheduleIdle, boolean idleDelayed) {
if (!mStackSupervisor.mStoppingActivities.contains(r)) {
mStackSupervisor.mStoppingActivities.add(r);
+
+ // Some activity is waiting for another activity to become visible before it's being
+ // stopped, which means that we also want to wait with stopping this one to avoid
+ // flickers.
+ if (!mStackSupervisor.mActivitiesWaitingForVisibleActivity.isEmpty()
+ && !mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(r)) {
+ if (DEBUG_SWITCH) Slog.i(TAG_SWITCH, "adding to waiting visible activity=" + r
+ + " existing=" + mStackSupervisor.mActivitiesWaitingForVisibleActivity);
+ mStackSupervisor.mActivitiesWaitingForVisibleActivity.add(r);
+ }
}
// If we already have a few activities waiting to stop, then give up
@@ -1904,7 +1914,7 @@
true /* ignoreStopState */);
}
- if (r.app == null || r.app.thread == null) {
+ if (!r.attachedToProcess()) {
if (makeVisibleAndRestartIfNeeded(starting, configChanges, isTop,
resumeNextActivity, r)) {
if (activityNdx >= activities.size()) {
@@ -2136,11 +2146,11 @@
switch (r.getState()) {
case STOPPING:
case STOPPED:
- if (r.app != null && r.app.thread != null) {
+ if (r.attachedToProcess()) {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
"Scheduling invisibility: " + r);
- mService.getLifecycleManager().scheduleTransaction(r.app.thread, r.appToken,
- WindowVisibilityItem.obtain(false /* showWindow */));
+ mService.getLifecycleManager().scheduleTransaction(r.app.getThread(),
+ r.appToken, WindowVisibilityItem.obtain(false /* showWindow */));
}
// Reset the flag indicating that an app can enter picture-in-picture once the
@@ -2217,9 +2227,9 @@
if (waitingActivity != null) {
mWindowManager.setWindowOpaque(waitingActivity.appToken, false);
- if (waitingActivity.app != null && waitingActivity.app.thread != null) {
+ if (waitingActivity.attachedToProcess()) {
try {
- waitingActivity.app.thread.scheduleTranslucentConversionComplete(
+ waitingActivity.app.getThread().scheduleTranslucentConversionComplete(
waitingActivity.appToken, r != null);
} catch (RemoteException e) {
}
@@ -2451,8 +2461,9 @@
// at the top of the LRU list, since we know we will be needing it
// very soon and it would be a waste to let it get killed if it
// happens to be sitting towards the end.
- if (next.app != null && next.app.thread != null) {
- mService.mAm.updateLruProcessLocked(next.app, true, null);
+ if (next.attachedToProcess()) {
+ next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
+ true /* updateLru */, true /* activityChange */, false /* updateOomAdj */);
}
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
if (lastResumed != null) {
@@ -2577,7 +2588,7 @@
mStackSupervisor.mNoAnimActivities.clear();
ActivityStack lastStack = mStackSupervisor.getLastStack();
- if (next.app != null && next.app.thread != null) {
+ if (next.attachedToProcess()) {
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next
+ " stopped=" + next.stopped + " visible=" + next.visible);
@@ -2618,9 +2629,9 @@
next.setState(RESUMED, "resumeTopActivityInnerLocked");
- mService.mAm.updateLruProcessLocked(next.app, true, null);
+ next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
+ true /* updateLru */, true /* activityChange */, true /* updateOomAdj */);
updateLRUListLocked(next);
- mService.mAm.updateOomAdjLocked();
// Have the window manager re-evaluate the orientation of
// the screen based on the new activity order.
@@ -2662,8 +2673,8 @@
}
try {
- final ClientTransaction transaction = ClientTransaction.obtain(next.app.thread,
- next.appToken);
+ final ClientTransaction transaction =
+ ClientTransaction.obtain(next.app.getThread(), next.appToken);
// Deliver all pending results.
ArrayList<ResultInfo> a = next.results;
if (a != null) {
@@ -2691,11 +2702,11 @@
next.sleeping = false;
mService.mAm.getAppWarningsLocked().onResumeActivity(next);
mService.mAm.showAskCompatModeDialogLocked(next);
- next.app.pendingUiClean = true;
- next.app.forceProcessStateUpTo(mService.mAm.mTopProcessState);
+ next.app.setPendingUiCleanAndForceProcessStateUpTo(
+ mService.mAm.mTopProcessState);
next.clearOptionsLocked();
transaction.setLifecycleStateRequest(
- ResumeActivityItem.obtain(next.app.repProcState,
+ ResumeActivityItem.obtain(next.app.getReportedProcState(),
mService.isNextTransitionForward()));
mService.getLifecycleManager().scheduleTransaction(transaction);
@@ -3345,12 +3356,12 @@
if (DEBUG_RESULTS) Slog.v(TAG, "Send activity result to " + r
+ " : who=" + resultWho + " req=" + requestCode
+ " res=" + resultCode + " data=" + data);
- if (mResumedActivity == r && r.app != null && r.app.thread != null) {
+ if (mResumedActivity == r && r.attachedToProcess()) {
try {
ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
list.add(new ResultInfo(resultWho, requestCode,
resultCode, data));
- mService.getLifecycleManager().scheduleTransaction(r.app.thread, r.appToken,
+ mService.getLifecycleManager().scheduleTransaction(r.app.getThread(), r.appToken,
ActivityResultItem.obtain(list));
return;
} catch (Exception e) {
@@ -3464,7 +3475,7 @@
}
}
- if (r.app != null && r.app.thread != null) {
+ if (r.attachedToProcess()) {
adjustFocusedActivityStack(r, "stopActivity");
r.resumeKeyDispatchingLocked();
try {
@@ -3479,7 +3490,7 @@
}
EventLogTags.writeAmStopActivity(
r.userId, System.identityHashCode(r), r.shortComponentName);
- mService.getLifecycleManager().scheduleTransaction(r.app.thread, r.appToken,
+ mService.getLifecycleManager().scheduleTransaction(r.app.getThread(), r.appToken,
StopActivityItem.obtain(r.visible, r.configChangeFlags));
if (shouldSleepOrShutDownActivities()) {
r.setSleeping(true);
@@ -3546,7 +3557,7 @@
* @return The task that was finished in this stack, {@code null} if top running activity does
* not belong to the crashed app.
*/
- final TaskRecord finishTopCrashedActivityLocked(ProcessRecord app, String reason) {
+ final TaskRecord finishTopCrashedActivityLocked(WindowProcessController app, String reason) {
ActivityRecord r = topRunningActivityLocked();
TaskRecord finishedTask = null;
if (r == null || r.app != app) {
@@ -3578,7 +3589,7 @@
if (activityNdx >= 0) {
r = mTaskHistory.get(taskNdx).mActivities.get(activityNdx);
if (r.isState(RESUMED, PAUSING, PAUSED)) {
- if (!r.isActivityTypeHome() || mService.mAm.mHomeProcess != r.app) {
+ if (!r.isActivityTypeHome() || mService.mHomeProcess != r.app) {
Slog.w(TAG, " Force finishing activity "
+ r.intent.getComponent().flattenToShortString());
finishActivityLocked(r, Activity.RESULT_CANCELED, null, reason, false);
@@ -3606,13 +3617,12 @@
// Check if any of the activities are using voice
for (int activityNdx = tr.mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
ActivityRecord r = tr.mActivities.get(activityNdx);
- if (r.voiceSession != null
- && r.voiceSession.asBinder() == sessionBinder) {
+ if (r.voiceSession != null && r.voiceSession.asBinder() == sessionBinder) {
// Inform of cancellation
r.clearVoiceSessionLocked();
try {
- r.app.thread.scheduleLocalVoiceInteractionStarted((IBinder) r.appToken,
- null);
+ r.app.getThread().scheduleLocalVoiceInteractionStarted(
+ r.appToken, null);
} catch (RemoteException re) {
// Ok
}
@@ -3956,7 +3966,9 @@
}
}
- IActivityController controller = mService.mAm.mController;
+ // TODO: There is a dup. of this block of code in ActivityTaskManagerService.finishActivity
+ // We should consolidate.
+ IActivityController controller = mService.mController;
if (controller != null) {
ActivityRecord next = topRunningActivityLocked(srec.appToken, 0);
if (next != null) {
@@ -3965,7 +3977,7 @@
try {
resumeOK = controller.activityResuming(next.packageName);
} catch (RemoteException e) {
- mService.mAm.mController = null;
+ mService.mController = null;
Watchdog.getInstance().setActivityController(null);
}
@@ -4000,7 +4012,7 @@
// TODO(b/64750076): Check if calling pid should really be -1.
final int res = mService.getActivityStartController()
.obtainStarter(destIntent, "navigateUpTo")
- .setCaller(srec.app.thread)
+ .setCaller(srec.app.getThread())
.setActivityInfo(aInfo)
.setResultTo(parent.appToken)
.setCallingPid(-1)
@@ -4167,13 +4179,13 @@
}
}
- final void scheduleDestroyActivities(ProcessRecord owner, String reason) {
+ final void scheduleDestroyActivities(WindowProcessController owner, String reason) {
Message msg = mHandler.obtainMessage(DESTROY_ACTIVITIES_MSG);
msg.obj = new ScheduleDestroyArgs(owner, reason);
mHandler.sendMessage(msg);
}
- private void destroyActivitiesLocked(ProcessRecord owner, String reason) {
+ private void destroyActivitiesLocked(WindowProcessController owner, String reason) {
boolean lastIsOpaque = false;
boolean activityRemoved = false;
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
@@ -4218,7 +4230,7 @@
return false;
}
- final int releaseSomeActivitiesLocked(ProcessRecord app, ArraySet<TaskRecord> tasks,
+ final int releaseSomeActivitiesLocked(WindowProcessController app, ArraySet<TaskRecord> tasks,
String reason) {
// Iterate over tasks starting at the back (oldest) first.
if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Trying to release some activities in " + app);
@@ -4272,7 +4284,7 @@
final boolean destroyActivityLocked(ActivityRecord r, boolean removeFromApp, String reason) {
if (DEBUG_SWITCH || DEBUG_CLEANUP) Slog.v(TAG_SWITCH,
"Removing activity from " + reason + ": token=" + r
- + ", app=" + (r.app != null ? r.app.processName : "(null)"));
+ + ", app=" + (r.hasProcess() ? r.app.mName : "(null)"));
if (r.isState(DESTROYING, DESTROYED)) {
if (DEBUG_STATES) Slog.v(TAG_STATES, "activity " + r + " already destroying."
@@ -4288,23 +4300,23 @@
cleanUpActivityLocked(r, false, false);
- final boolean hadApp = r.app != null;
+ final boolean hadApp = r.hasProcess();
if (hadApp) {
if (removeFromApp) {
- r.app.activities.remove(r);
- if (mService.mAm.mHeavyWeightProcess == r.app && r.app.activities.size() <= 0) {
+ r.app.removeActivity(r);
+ if (mService.mAm.mHeavyWeightProcess != null
+ && mService.mAm.mHeavyWeightProcess.getWindowProcessController() == r.app
+ && !r.app.hasActivities()) {
mService.mAm.mHeavyWeightProcess = null;
mService.mAm.mHandler.sendEmptyMessage(
ActivityManagerService.CANCEL_HEAVY_NOTIFICATION_MSG);
}
- if (r.app.activities.isEmpty()) {
+ if (!r.app.hasActivities()) {
// Update any services we are bound to that might care about whether
// their client may have activities.
- mService.mAm.mServices.updateServiceConnectionActivitiesLocked(r.app);
// No longer have activities, so update LRU list and oom adj.
- mService.mAm.updateLruProcessLocked(r.app, false, null);
- mService.mAm.updateOomAdjLocked();
+ r.app.updateProcessInfo(true, true, false, true);
}
}
@@ -4312,7 +4324,7 @@
try {
if (DEBUG_SWITCH) Slog.i(TAG_SWITCH, "Destroying: " + r);
- mService.getLifecycleManager().scheduleTransaction(r.app.thread, r.appToken,
+ mService.getLifecycleManager().scheduleTransaction(r.app.getThread(), r.appToken,
DestroyActivityItem.obtain(r.finishing, r.configChangeFlags));
} catch (Exception e) {
// We can just ignore exceptions here... if the process
@@ -4403,7 +4415,7 @@
}
private void removeHistoryRecordsForAppLocked(ArrayList<ActivityRecord> list,
- ProcessRecord app, String listName) {
+ WindowProcessController app, String listName) {
int i = list.size();
if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
"Removing app " + app + " from list " + listName + " with " + i + " entries");
@@ -4419,7 +4431,7 @@
}
}
- private boolean removeHistoryRecordsForAppLocked(ProcessRecord app) {
+ private boolean removeHistoryRecordsForAppLocked(WindowProcessController app) {
removeHistoryRecordsForAppLocked(mLRUActivities, app, "mLRUActivities");
removeHistoryRecordsForAppLocked(mStackSupervisor.mStoppingActivities, app,
"mStoppingActivities");
@@ -4662,7 +4674,7 @@
// If we have a watcher, preflight the move before committing to it. First check
// for *other* available tasks, but if none are available, then try again allowing the
// current task to be selected.
- if (isTopStackOnDisplay() && mService.mAm.mController != null) {
+ if (isTopStackOnDisplay() && mService.mController != null) {
ActivityRecord next = topRunningActivityLocked(null, taskId);
if (next == null) {
next = topRunningActivityLocked(null, 0);
@@ -4671,9 +4683,9 @@
// ask watcher if this is allowed
boolean moveOK = true;
try {
- moveOK = mService.mAm.mController.activityResuming(next.packageName);
+ moveOK = mService.mController.activityResuming(next.packageName);
} catch (RemoteException e) {
- mService.mAm.mController = null;
+ mService.mController = null;
Watchdog.getInstance().setActivityController(null);
}
if (!moveOK) {
@@ -4893,7 +4905,7 @@
|| (packageName == null && r.userId == userId);
if ((userId == UserHandle.USER_ALL || r.userId == userId)
&& (sameComponent || r.getTask() == lastTask)
- && (r.app == null || evenPersistent || !r.app.persistent)) {
+ && (r.app == null || evenPersistent || !r.app.isPersistent())) {
if (!doit) {
if (r.finishing) {
// If this activity is just finishing, then it is not
@@ -4913,8 +4925,8 @@
didSomething = true;
Slog.i(TAG, " Force finishing activity " + r);
if (sameComponent) {
- if (r.app != null) {
- r.app.removed = true;
+ if (r.hasProcess()) {
+ r.app.setRemoved(true);
}
r.app = null;
}
@@ -4985,7 +4997,7 @@
* @param app The app of the activity that died.
* @return result from removeHistoryRecordsForAppLocked.
*/
- boolean handleAppDiedLocked(ProcessRecord app) {
+ boolean handleAppDiedLocked(WindowProcessController app) {
if (mPausingActivity != null && mPausingActivity.app == app) {
if (DEBUG_PAUSE || DEBUG_CLEANUP) Slog.v(TAG_PAUSE,
"App died while pausing: " + mPausingActivity);
@@ -4999,7 +5011,7 @@
return removeHistoryRecordsForAppLocked(app);
}
- void handleAppCrashLocked(ProcessRecord app) {
+ void handleAppCrashLocked(WindowProcessController app) {
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
@@ -5277,6 +5289,20 @@
}
}
+ public void setAlwaysOnTop(boolean alwaysOnTop) {
+ if (isAlwaysOnTop() == alwaysOnTop) {
+ return;
+ }
+ super.setAlwaysOnTop(alwaysOnTop);
+ final ActivityDisplay display = getDisplay();
+ // positionChildAtTop() must be called even when always on top gets turned off because we
+ // need to make sure that the stack is moved from among always on top windows to below other
+ // always on top windows. Since the position the stack should be inserted into is calculated
+ // properly in {@link ActivityDisplay#getTopInsertPosition()} in both cases, we can just
+ // request that the stack is put at top here.
+ display.positionChildAtTop(this);
+ }
+
void moveToFrontAndResumeStateIfNeeded(ActivityRecord r, boolean moveToFront, boolean setResume,
boolean setPause, String reason) {
if (!moveToFront) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index a77d734..1cb6be6 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -109,7 +109,9 @@
import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.StackInfo;
-import android.app.ActivityTaskManagerInternal.SleepToken;
+import android.app.ActivityManagerInternal;
+import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.server.wm.ActivityTaskManagerInternal.SleepToken;
import android.app.ActivityOptions;
import android.app.AppOpsManager;
import android.app.ProfilerInfo;
@@ -488,7 +490,7 @@
// No restrictions for the default display.
return true;
}
- if (!mService.mAm.mSupportsMultiDisplay) {
+ if (!mService.mSupportsMultiDisplay) {
// Can't launch on secondary displays if feature is not supported.
return false;
}
@@ -580,21 +582,21 @@
final ActivityRecord sourceRecord;
final int startFlags;
final ActivityStack stack;
- final ProcessRecord callerApp;
+ final WindowProcessController callerApp;
PendingActivityLaunch(ActivityRecord _r, ActivityRecord _sourceRecord,
- int _startFlags, ActivityStack _stack, ProcessRecord _callerApp) {
+ int _startFlags, ActivityStack _stack, WindowProcessController app) {
r = _r;
sourceRecord = _sourceRecord;
startFlags = _startFlags;
stack = _stack;
- callerApp = _callerApp;
+ callerApp = app;
}
void sendErrorResult(String message) {
try {
- if (callerApp.thread != null) {
- callerApp.thread.scheduleCrash(message);
+ if (callerApp.hasThread()) {
+ callerApp.getThread().scheduleCrash(message);
}
} catch (RemoteException e) {
Slog.e(TAG, "Exception scheduling crash of failed "
@@ -624,7 +626,7 @@
mActivityMetricsLogger = new ActivityMetricsLogger(this, mService.mContext, mHandler.getLooper());
mKeyguardController = new KeyguardController(mService.mAm, this);
- mLaunchParamsController = new LaunchParamsController(mService.mAm);
+ mLaunchParamsController = new LaunchParamsController(mService);
mLaunchParamsController.registerDefaultModifiers(this);
}
@@ -1399,12 +1401,13 @@
beginDeferResume();
try {
- r.startFreezingScreenLocked(app, 0);
+ final WindowProcessController proc = app.getWindowProcessController();
+ r.startFreezingScreenLocked(proc, 0);
// schedule launch ticks to collect information about slow apps.
r.startLaunchTickingLocked();
- r.setProcess(app);
+ r.setProcess(proc);
if (getKeyguardController().isKeyguardLocked()) {
r.notifyUnknownVisibilityLaunched();
@@ -1448,12 +1451,8 @@
if (DEBUG_ALL) Slog.v(TAG, "Launching: " + r);
- int idx = app.activities.indexOf(r);
- if (idx < 0) {
- app.activities.add(r);
- }
- mService.mAm.updateLruProcessLocked(app, true, null);
- mService.mAm.updateOomAdjLocked();
+ proc.addActivityIfNeeded(r);
+ proc.updateProcessInfo(false, true, true, true);
final LockTaskController lockTaskController = mService.getLockTaskController();
if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
@@ -1483,7 +1482,7 @@
System.identityHashCode(r), task.taskId, r.shortComponentName);
if (r.isActivityTypeHome()) {
// Home process is the root process of the task.
- mService.mAm.mHomeProcess = task.mActivities.get(0).app;
+ mService.mHomeProcess = task.mActivities.get(0).app;
}
mService.mAm.notifyPackageUse(r.intent.getComponent().getPackageName(),
PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY);
@@ -1534,9 +1533,9 @@
// and override configs.
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
- r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
- r.persistentState, results, newIntents, mService.isNextTransitionForward(),
- profilerInfo));
+ r.launchedFromPackage, task.voiceInteractor, app.getReportedProcState(),
+ r.icicle, r.persistentState, results, newIntents,
+ mService.isNextTransitionForward(), profilerInfo));
// Set desired final state.
final ActivityLifecycleItem lifecycleItem;
@@ -1587,7 +1586,7 @@
// This is the first time we failed -- restart process and
// retry.
r.launchFailed = true;
- app.activities.remove(r);
+ proc.removeActivity(r);
throw e;
}
} finally {
@@ -1625,7 +1624,7 @@
// Update any services we are bound to that might care about whether
// their client may have activities.
if (r.app != null) {
- mService.mAm.mServices.updateServiceConnectionActivitiesLocked(r.app);
+ r.app.updateServiceConnectionActivities();
}
return true;
@@ -1639,6 +1638,8 @@
* @param markFrozenIfConfigChanged Whether to set {@link ActivityRecord#frozenBeforeDestroy} to
* {@code true} if config changed.
* @param deferResume Whether to defer resume while updating config.
+ * @return 'true' if starting activity was kept or wasn't provided, 'false' if it was relaunched
+ * because of configuration update.
*/
boolean ensureVisibilityAndConfig(ActivityRecord starting, int displayId,
boolean markFrozenIfConfigChanged, boolean deferResume) {
@@ -1649,6 +1650,11 @@
ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */,
false /* preserveWindows */, false /* notifyClients */);
+ if (displayId == INVALID_DISPLAY) {
+ // The caller didn't provide a valid display id, skip updating config.
+ return true;
+ }
+
// Force-update the orientation from the WindowManager, since we need the true configuration
// to send to the client now.
final Configuration config = mWindowManager.updateOrientationFromAppTokens(
@@ -1661,7 +1667,7 @@
}
// Update the configuration of the activities on the display.
- return mService.mAm.updateDisplayOverrideConfigurationLocked(config, starting, deferResume,
+ return mService.updateDisplayOverrideConfigurationLocked(config, starting, deferResume,
displayId);
}
@@ -2122,7 +2128,7 @@
return r;
}
- boolean handleAppDiedLocked(ProcessRecord app) {
+ boolean handleAppDiedLocked(WindowProcessController app) {
boolean hasVisibleActivities = false;
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
@@ -2185,7 +2191,7 @@
// First, found out what is currently the foreground app, so that
// we don't blow away the previous app if this activity is being
// hosted by the process that is actually still the foreground.
- ProcessRecord fgApp = null;
+ WindowProcessController fgApp = null;
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
@@ -2204,11 +2210,11 @@
// Now set this one as the previous process, only if that really
// makes sense to.
- if (r.app != null && fgApp != null && r.app != fgApp
- && r.lastVisibleTime > mService.mAm.mPreviousProcessVisibleTime
- && r.app != mService.mAm.mHomeProcess) {
- mService.mAm.mPreviousProcess = r.app;
- mService.mAm.mPreviousProcessVisibleTime = r.lastVisibleTime;
+ if (r.hasProcess() && fgApp != null && r.app != fgApp
+ && r.lastVisibleTime > mService.mPreviousProcessVisibleTime
+ && r.app != mService.mHomeProcess) {
+ mService.mPreviousProcess = r.app;
+ mService.mPreviousProcessVisibleTime = r.lastVisibleTime;
}
}
@@ -2254,7 +2260,7 @@
* @param reason Reason to perform this action.
* @return The task that was finished in this stack, {@code null} if haven't found any.
*/
- TaskRecord finishTopCrashedActivitiesLocked(ProcessRecord app, String reason) {
+ TaskRecord finishTopCrashedActivitiesLocked(WindowProcessController app, String reason) {
TaskRecord finishedTask = null;
ActivityStack focusedStack = getFocusedStack();
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
@@ -2347,9 +2353,9 @@
if (options == null || options.getLaunchBounds() == null) {
return false;
}
- return (mService.mAm.mSupportsPictureInPicture
+ return (mService.mSupportsPictureInPicture
&& options.getLaunchWindowingMode() == WINDOWING_MODE_PINNED)
- || mService.mAm.mSupportsFreeformWindowManagement;
+ || mService.mSupportsFreeformWindowManagement;
}
LaunchParamsController getLaunchParamsController() {
@@ -3104,36 +3110,34 @@
// Determine if the process(es) for this task should be killed.
final String pkg = component.getPackageName();
- ArrayList<ProcessRecord> procsToKill = new ArrayList<>();
- ArrayMap<String, SparseArray<ProcessRecord>> pmap = mService.mAm.mProcessNames.getMap();
+ ArrayList<Object> procsToKill = new ArrayList<>();
+ ArrayMap<String, SparseArray<WindowProcessController>> pmap =
+ mService.mProcessNames.getMap();
for (int i = 0; i < pmap.size(); i++) {
- SparseArray<ProcessRecord> uids = pmap.valueAt(i);
+ SparseArray<WindowProcessController> uids = pmap.valueAt(i);
for (int j = 0; j < uids.size(); j++) {
- ProcessRecord proc = uids.valueAt(j);
- if (proc.userId != tr.userId) {
+ WindowProcessController proc = uids.valueAt(j);
+ if (proc.mUserId != tr.userId) {
// Don't kill process for a different user.
continue;
}
- if (proc == mService.mAm.mHomeProcess) {
+ if (proc == mService.mHomeProcess) {
// Don't kill the home process along with tasks from the same package.
continue;
}
- if (!proc.pkgList.containsKey(pkg)) {
+ if (!proc.mPkgList.contains(pkg)) {
// Don't kill process that is not associated with this task.
continue;
}
- for (int k = 0; k < proc.activities.size(); k++) {
- TaskRecord otherTask = proc.activities.get(k).getTask();
- if (tr.taskId != otherTask.taskId && otherTask.inRecents) {
- // Don't kill process(es) that has an activity in a different task that is
- // also in recents.
- return;
- }
+ if (!proc.shouldKillProcessForRemovedTask(tr)) {
+ // Don't kill process(es) that has an activity in a different task that is also
+ // in recents.
+ return;
}
- if (proc.foregroundServices) {
+ if (proc.hasForegroundServices()) {
// Don't kill process(es) with foreground service.
return;
}
@@ -3143,17 +3147,12 @@
}
}
- // Kill the running processes.
- for (int i = 0; i < procsToKill.size(); i++) {
- ProcessRecord pr = procsToKill.get(i);
- if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND
- && pr.curReceivers.isEmpty()) {
- pr.kill("remove task", true);
- } else {
- // We delay killing processes that are not in the background or running a receiver.
- pr.waitingToKill = "remove task";
- }
- }
+ // Kill the running processes. Post on handle since we don't want to hold the service lock
+ // while calling into AM.
+ final Runnable r = PooledLambda.obtainRunnable(
+ ActivityManagerInternal::killProcessesForRemovedTask, mService.mAmInternal,
+ procsToKill);
+ mService.mH.post(r);
}
/**
@@ -3258,21 +3257,21 @@
// Ensure that we aren't trying to move into a multi-window stack without multi-window
// support
- if (inMultiWindowMode && !mService.mAm.mSupportsMultiWindow) {
+ if (inMultiWindowMode && !mService.mSupportsMultiWindow) {
throw new IllegalArgumentException("Device doesn't support multi-window, can not"
+ " reparent task=" + task + " to stack=" + stack);
}
// Ensure that we're not moving a task to a dynamic stack if device doesn't support
// multi-display.
- if (stack.mDisplayId != DEFAULT_DISPLAY && !mService.mAm.mSupportsMultiDisplay) {
+ if (stack.mDisplayId != DEFAULT_DISPLAY && !mService.mSupportsMultiDisplay) {
throw new IllegalArgumentException("Device doesn't support multi-display, can not"
+ " reparent task=" + task + " to stackId=" + stackId);
}
// Ensure that we aren't trying to move into a freeform stack without freeform support
if (stack.getWindowingMode() == WINDOWING_MODE_FREEFORM
- && !mService.mAm.mSupportsFreeformWindowManagement) {
+ && !mService.mSupportsFreeformWindowManagement) {
throw new IllegalArgumentException("Device doesn't support freeform, can not reparent"
+ " task=" + task);
}
@@ -3305,7 +3304,7 @@
return false;
}
- if (!mService.mAm.mForceResizableActivities && !r.supportsPictureInPicture()) {
+ if (!mService.mForceResizableActivities && !r.supportsPictureInPicture()) {
Slog.w(TAG,
"moveTopStackActivityToPinnedStackLocked: Picture-In-Picture not supported for "
+ " r=" + r);
@@ -3656,7 +3655,7 @@
return false;
}
- void handleAppCrashLocked(ProcessRecord app) {
+ void handleAppCrashLocked(WindowProcessController app) {
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
@@ -3758,7 +3757,7 @@
}
}
- void scheduleDestroyAllActivities(ProcessRecord app, String reason) {
+ void scheduleDestroyAllActivities(WindowProcessController app, String reason) {
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
@@ -3768,44 +3767,9 @@
}
}
- void releaseSomeActivitiesLocked(ProcessRecord app, String reason) {
- // Examine all activities currently running in the process.
- TaskRecord firstTask = null;
+ void releaseSomeActivitiesLocked(WindowProcessController app, String reason) {
// Tasks is non-null only if two or more tasks are found.
- ArraySet<TaskRecord> tasks = null;
- if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Trying to release some activities in " + app);
- for (int i = 0; i < app.activities.size(); i++) {
- ActivityRecord r = app.activities.get(i);
- // First, if we find an activity that is in the process of being destroyed,
- // then we just aren't going to do anything for now; we want things to settle
- // down before we try to prune more activities.
- if (r.finishing || r.isState(DESTROYING, DESTROYED)) {
- if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Abort release; already destroying: " + r);
- return;
- }
- // Don't consider any activies that are currently not in a state where they
- // can be destroyed.
- if (r.visible || !r.stopped || !r.haveState
- || r.isState(RESUMED, PAUSING, PAUSED, STOPPING)) {
- if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Not releasing in-use activity: " + r);
- continue;
- }
-
- final TaskRecord task = r.getTask();
- if (task != null) {
- if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Collecting release task " + task
- + " from " + r);
- if (firstTask == null) {
- firstTask = task;
- } else if (firstTask != task) {
- if (tasks == null) {
- tasks = new ArraySet<>();
- tasks.add(firstTask);
- }
- tasks.add(task);
- }
- }
- }
+ ArraySet<TaskRecord> tasks = app.getReleaseSomeActivitiesTasks();
if (tasks == null) {
if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Didn't find two or more tasks to release");
return;
@@ -3935,6 +3899,10 @@
stops = new ArrayList<>();
}
stops.add(s);
+
+ // Make sure to remove it in all cases in case we entered this block with
+ // shouldSleepOrShutDown
+ mActivitiesWaitingForVisibleActivity.remove(s);
mStoppingActivities.remove(activityNdx);
}
}
@@ -4198,16 +4166,16 @@
pw.print(innerPrefix); pw.println(r.app);
}
}
- if (client && r.app != null && r.app.thread != null) {
+ if (client && r.attachedToProcess()) {
// flush anything that is already in the PrintWriter since the thread is going
// to write to the file descriptor directly
pw.flush();
try {
TransferPipe tp = new TransferPipe();
try {
- r.app.thread.dumpActivity(tp.getWriteFd(), r.appToken, innerPrefix, args);
- // Short timeout, since blocking here can
- // deadlock with the application.
+ r.app.getThread().dumpActivity(
+ tp.getWriteFd(), r.appToken, innerPrefix, args);
+ // Short timeout, since blocking here can deadlock with the application.
tp.go(fd, 2000);
} finally {
tp.kill();
@@ -4567,7 +4535,7 @@
for (int i = task.mActivities.size() - 1; i >= 0; i--) {
final ActivityRecord r = task.mActivities.get(i);
- if (r.app != null && r.app.thread != null) {
+ if (r.attachedToProcess()) {
mMultiWindowModeChangedActivities.add(r);
}
}
@@ -4590,7 +4558,7 @@
void scheduleUpdatePictureInPictureModeIfNeeded(TaskRecord task, Rect targetStackBounds) {
for (int i = task.mActivities.size() - 1; i >= 0; i--) {
final ActivityRecord r = task.mActivities.get(i);
- if (r.app != null && r.app.thread != null) {
+ if (r.attachedToProcess()) {
mPipModeChangedActivities.add(r);
// If we are scheduling pip change, then remove this activity from multi-window
// change list as the processing of pip change will make sure multi-window changed
@@ -4609,7 +4577,7 @@
mHandler.removeMessages(REPORT_PIP_MODE_CHANGED_MSG);
for (int i = task.mActivities.size() - 1; i >= 0; i--) {
final ActivityRecord r = task.mActivities.get(i);
- if (r.app != null && r.app.thread != null) {
+ if (r.attachedToProcess()) {
r.updatePictureInPictureMode(targetStackBounds, forceUpdate);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStartController.java b/services/core/java/com/android/server/am/ActivityStartController.java
index fa001df..f7ea4b2 100644
--- a/services/core/java/com/android/server/am/ActivityStartController.java
+++ b/services/core/java/com/android/server/am/ActivityStartController.java
@@ -21,7 +21,7 @@
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.am.ActivityManagerService.ALLOW_FULL_ONLY;
+import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import android.app.IApplicationThread;
import android.content.ComponentName;
@@ -237,8 +237,8 @@
int checkTargetUser(int targetUserId, boolean validateIncomingUser,
int realCallingPid, int realCallingUid, String reason) {
if (validateIncomingUser) {
- return mService.mAm.mUserController.handleIncomingUser(realCallingPid, realCallingUid,
- targetUserId, false, ALLOW_FULL_ONLY, reason, null);
+ return mService.handleIncomingUser(
+ realCallingPid, realCallingUid, targetUserId, reason);
} else {
mService.mAm.mUserController.ensureNotSpecialUser(targetUserId);
return targetUserId;
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index f50bb37..dac7715 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -720,24 +720,25 @@
abort |= !mService.mAm.mIntentFirewall.checkStartActivity(intent, callingUid,
callingPid, resolvedType, aInfo.applicationInfo);
+ final WindowProcessController callerWpc =
+ callerApp != null ? callerApp.getWindowProcessController() : null;
// Merge the two options bundles, while realCallerOptions takes precedence.
ActivityOptions checkedOptions = options != null
- ? options.getOptions(intent, aInfo, callerApp, mSupervisor)
- : null;
+ ? options.getOptions(intent, aInfo, callerWpc, mSupervisor) : null;
if (allowPendingRemoteAnimationRegistryLookup) {
checkedOptions = mService.getActivityStartController()
.getPendingRemoteAnimationRegistry()
.overrideOptionsIfNeeded(callingPackage, checkedOptions);
}
- if (mService.mAm.mController != null) {
+ if (mService.mController != null) {
try {
// The Intent we give to the watcher has the extra data
// stripped off, since it can contain private information.
Intent watchIntent = intent.cloneFilter();
- abort |= !mService.mAm.mController.activityStarting(watchIntent,
+ abort |= !mService.mController.activityStarting(watchIntent,
aInfo.applicationInfo.packageName);
} catch (RemoteException e) {
- mService.mAm.mController = null;
+ mService.mController = null;
}
}
@@ -844,26 +845,16 @@
// one, check whether app switches are allowed.
if (voiceSession == null && (stack.getResumedActivity() == null
|| stack.getResumedActivity().info.applicationInfo.uid != realCallingUid)) {
- if (!mService.mAm.checkAppSwitchAllowedLocked(callingPid, callingUid,
+ if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
realCallingPid, realCallingUid, "Activity start")) {
mController.addPendingActivityLaunch(new PendingActivityLaunch(r,
- sourceRecord, startFlags, stack, callerApp));
+ sourceRecord, startFlags, stack, callerWpc));
ActivityOptions.abort(checkedOptions);
return ActivityManager.START_SWITCHES_CANCELED;
}
}
- if (mService.mAm.mDidAppSwitch) {
- // This is the second allowed switch since we stopped switches,
- // so now just generally allow switches. Use case: user presses
- // home (switches disabled, switch to home, mDidAppSwitch now true);
- // user taps a home icon (coming from home so allowed, we hit here
- // and now allow anyone to switch again).
- mService.mAm.mAppSwitchesAllowedTime = 0;
- } else {
- mService.mAm.mDidAppSwitch = true;
- }
-
+ mService.onStartActivitySetDidAppSwitch();
mController.doPendingActivityLaunches(false);
return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
@@ -1067,13 +1058,8 @@
}
newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT,
new IntentSender(target));
- if (heavy.activities.size() > 0) {
- ActivityRecord hist = heavy.activities.get(0);
- newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP,
- hist.packageName);
- newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK,
- hist.getTask().taskId);
- }
+ heavy.getWindowProcessController().updateIntentForHeavyWeightActivity(
+ newIntent);
newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,
aInfo.packageName);
newIntent.setFlags(intent.getFlags());
@@ -1110,12 +1096,12 @@
// do so now. This allows a clean switch, as we are waiting
// for the current activity to pause (so we will not destroy
// it), and have not yet started the next activity.
- mService.mAm.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
+ mService.mAmInternal.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
"updateConfiguration()");
stack.mConfigWillChange = false;
if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Updating to new configuration after starting activity.");
- mService.mAm.updateConfigurationLocked(globalConfig, null, false);
+ mService.updateConfigurationLocked(globalConfig, null, false);
}
if (outResult != null) {
@@ -1374,7 +1360,7 @@
final boolean dontStart = top != null && mStartActivity.resultTo == null
&& top.realActivity.equals(mStartActivity.realActivity)
&& top.userId == mStartActivity.userId
- && top.app != null && top.app.thread != null
+ && top.attachedToProcess()
&& ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
|| isLaunchModeOneOf(LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK));
if (dontStart) {
@@ -1821,7 +1807,7 @@
}
// Get the virtual display id from ActivityManagerService.
- int displayId = mService.mAm.mVr2dDisplayId;
+ int displayId = mService.mVr2dDisplayId;
if (displayId != INVALID_DISPLAY) {
if (DEBUG_STACK) {
Slog.d(TAG, "getSourceDisplayId :" + displayId);
diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
index 90097fd..d47fb44 100644
--- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
@@ -24,14 +24,17 @@
import static android.Manifest.permission.READ_FRAME_BUFFER;
import static android.Manifest.permission.REMOVE_TASKS;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
+import static android.Manifest.permission.STOP_APP_SWITCHES;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
-import static android.app.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT;
-import static android.app.ActivityTaskManagerInternal.ASSIST_KEY_DATA;
-import static android.app.ActivityTaskManagerInternal.ASSIST_KEY_RECEIVER_EXTRAS;
-import static android.app.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE;
+import static com.android.server.am.ActivityManagerService.dumpStackTraces;
+import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT;
+import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_DATA;
+import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_RECEIVER_EXTRAS;
+import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE;
import static android.app.ActivityTaskManager.INVALID_STACK_ID;
import static android.app.ActivityTaskManager.RESIZE_MODE_PRESERVE_WINDOW;
import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
+import static android.app.AppOpsManager.OP_NONE;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
@@ -42,8 +45,17 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.pm.PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS;
+import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
+import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.content.res.Configuration.UI_MODE_TYPE_TELEVISION;
+import static android.os.Build.VERSION_CODES.N;
import static android.os.Process.SYSTEM_UID;
+import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
+import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
+import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
+import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RTL;
import static android.service.voice.VoiceInteractionSession.SHOW_SOURCE_APPLICATION;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
@@ -60,7 +72,9 @@
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBILITY;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_FOCUS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_IMMERSIVE;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
@@ -69,10 +83,13 @@
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.am.ActivityManagerService.ALLOW_FULL_ONLY;
+import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static com.android.server.am.ActivityManagerService.ANIMATE;
-import static com.android.server.am.ActivityManagerService.DISPATCH_SCREEN_KEYGUARD_MSG;
+import static com.android.server.am.ActivityManagerService.MY_PID;
+import static com.android.server.am.ActivityManagerService.SEND_LOCALE_TO_MOUNT_DAEMON_MSG;
import static com.android.server.am.ActivityManagerService.STOCK_PM_FLAGS;
+import static com.android.server.am.ActivityManagerService.UPDATE_CONFIGURATION_MSG;
+import static com.android.server.am.ActivityManagerService.checkComponentPermission;
import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME;
import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_ONLY;
@@ -88,14 +105,17 @@
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
import android.Manifest;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.Activity;
import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
-import android.app.ActivityTaskManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal;
import android.app.AppGlobals;
+import android.app.IActivityController;
import android.app.IActivityTaskManager;
import android.app.IApplicationThread;
import android.app.IAssistDataReceiver;
@@ -108,24 +128,30 @@
import android.app.admin.DevicePolicyCache;
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
+import android.app.servertransaction.ConfigurationChangeItem;
import android.app.usage.UsageEvents;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.IIntentSender;
import android.content.Intent;
import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.Rect;
import android.metrics.LogMaker;
import android.net.Uri;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
+import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
import android.os.LocaleList;
@@ -134,29 +160,42 @@
import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
-import android.os.TransactionTooLargeException;
+import android.os.StrictMode;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UpdateLock;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.voice.IVoiceInteractionSession;
import android.service.voice.VoiceInteractionManagerInternal;
import android.telecom.TelecomManager;
import android.text.TextUtils;
+import android.text.format.Time;
+import android.util.ArrayMap;
+import android.util.EventLog;
+import android.util.Log;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.SparseIntArray;
+import android.util.StatsLog;
+import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import android.view.IRecentsAnimationRunner;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationDefinition;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.AssistUtils;
import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.app.ProcessMap;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.os.logging.MetricsLoggerWrapper;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.KeyguardDismissCallback;
import com.android.internal.util.Preconditions;
+import com.android.server.AttributeCache;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.Watchdog;
@@ -165,9 +204,13 @@
import com.android.server.wm.WindowManagerService;
import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
import java.io.PrintWriter;
+import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
/**
* System service for managing activities and their containers (task, stacks, displays,... ).
@@ -182,14 +225,29 @@
private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
+ private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
Context mContext;
H mH;
+ UiHandler mUiHandler;
ActivityManagerService mAm;
+ ActivityManagerInternal mAmInternal;
/* Global service lock used by the package the owns this service. */
Object mGlobalLock;
ActivityStackSupervisor mStackSupervisor;
WindowManagerService mWindowManager;
+ /** All processes currently running that might have a window organized by name. */
+ final ProcessMap<WindowProcessController> mProcessNames = new ProcessMap<>();
+ /** This is the process holding what we currently consider to be the "home" activity. */
+ WindowProcessController mHomeProcess;
+ /**
+ * This is the process holding the activity the user last visited that is in a different process
+ * from the one they are currently in.
+ */
+ WindowProcessController mPreviousProcess;
+ /** The time at which the previous process was last visible. */
+ long mPreviousProcessVisibleTime;
+
/** List of intents that were used to start the most recent tasks. */
private RecentTasks mRecentTasks;
/** State of external calls telling us if the device is awake or asleep. */
@@ -245,14 +303,77 @@
}
/** Current sequencing integer of the configuration, for skipping old configurations. */
- int mConfigurationSeq;
+ private int mConfigurationSeq;
+ // To cache the list of supported system locales
+ private String[] mSupportedSystemLocales = null;
/**
* Temp object used when global and/or display override configuration is updated. It is also
* sent to outer world instead of {@link #getGlobalConfiguration} because we don't trust
* anyone...
*/
- Configuration mTempConfig = new Configuration();
+ private Configuration mTempConfig = new Configuration();
+
+ // Amount of time after a call to stopAppSwitches() during which we will
+ // prevent further untrusted switches from happening.
+ private static final long APP_SWITCH_DELAY_TIME = 5 * 1000;
+
+ /**
+ * The time at which we will allow normal application switches again,
+ * after a call to {@link #stopAppSwitches()}.
+ */
+ long mAppSwitchesAllowedTime;
+ /**
+ * This is set to true after the first switch after mAppSwitchesAllowedTime
+ * is set; any switches after that will clear the time.
+ */
+ boolean mDidAppSwitch;
+
+ IActivityController mController = null;
+ boolean mControllerIsAMonkey = false;
+
+ /**
+ * Used to retain an update lock when the foreground activity is in
+ * immersive mode.
+ */
+ final UpdateLock mUpdateLock = new UpdateLock("immersive");
+
+ /**
+ * Packages that are being allowed to perform unrestricted app switches. Mapping is
+ * User -> Type -> uid.
+ */
+ final SparseArray<ArrayMap<String, Integer>> mAllowAppSwitchUids = new SparseArray<>();
+
+ /** The dimensions of the thumbnails in the Recents UI. */
+ int mThumbnailWidth;
+ int mThumbnailHeight;
+ float mFullscreenThumbnailScale;
+
+ /**
+ * Flag that indicates if multi-window is enabled.
+ *
+ * For any particular form of multi-window to be enabled, generic multi-window must be enabled
+ * in {@link com.android.internal.R.bool#config_supportsMultiWindow} config or
+ * {@link Settings.Global#DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES} development option set.
+ * At least one of the forms of multi-window must be enabled in order for this flag to be
+ * initialized to 'true'.
+ *
+ * @see #mSupportsSplitScreenMultiWindow
+ * @see #mSupportsFreeformWindowManagement
+ * @see #mSupportsPictureInPicture
+ * @see #mSupportsMultiDisplay
+ */
+ boolean mSupportsMultiWindow;
+ boolean mSupportsSplitScreenMultiWindow;
+ boolean mSupportsFreeformWindowManagement;
+ boolean mSupportsPictureInPicture;
+ boolean mSupportsMultiDisplay;
+ boolean mForceResizableActivities;
+
+ final List<ActivityTaskManagerInternal.ScreenObserver> mScreenObservers = new ArrayList<>();
+
+ // VR Vr2d Display Id.
+ int mVr2dDisplayId = INVALID_DISPLAY;
ActivityTaskManagerService(Context context) {
mContext = context;
@@ -265,11 +386,86 @@
mRecentTasks.onSystemReadyLocked();
}
+ void retrieveSettings(ContentResolver resolver) {
+ final boolean freeformWindowManagement =
+ mContext.getPackageManager().hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT)
+ || Settings.Global.getInt(
+ resolver, DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0;
+
+ final boolean supportsMultiWindow = ActivityTaskManager.supportsMultiWindow(mContext);
+ final boolean supportsPictureInPicture = supportsMultiWindow &&
+ mContext.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
+ final boolean supportsSplitScreenMultiWindow =
+ ActivityTaskManager.supportsSplitScreenMultiWindow(mContext);
+ final boolean supportsMultiDisplay = mContext.getPackageManager()
+ .hasSystemFeature(FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS);
+ final boolean alwaysFinishActivities =
+ Settings.Global.getInt(resolver, ALWAYS_FINISH_ACTIVITIES, 0) != 0;
+ final boolean forceRtl = Settings.Global.getInt(resolver, DEVELOPMENT_FORCE_RTL, 0) != 0;
+ final boolean forceResizable = Settings.Global.getInt(
+ resolver, DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0;
+
+ // Transfer any global setting for forcing RTL layout, into a System Property
+ SystemProperties.set(DEVELOPMENT_FORCE_RTL, forceRtl ? "1":"0");
+
+ final Configuration configuration = new Configuration();
+ Settings.System.getConfiguration(resolver, configuration);
+ if (forceRtl) {
+ // This will take care of setting the correct layout direction flags
+ configuration.setLayoutDirection(configuration.locale);
+ }
+
+ synchronized (mGlobalLock) {
+ mForceResizableActivities = forceResizable;
+ final boolean multiWindowFormEnabled = freeformWindowManagement
+ || supportsSplitScreenMultiWindow
+ || supportsPictureInPicture
+ || supportsMultiDisplay;
+ if ((supportsMultiWindow || forceResizable) && multiWindowFormEnabled) {
+ mSupportsMultiWindow = true;
+ mSupportsFreeformWindowManagement = freeformWindowManagement;
+ mSupportsSplitScreenMultiWindow = supportsSplitScreenMultiWindow;
+ mSupportsPictureInPicture = supportsPictureInPicture;
+ mSupportsMultiDisplay = supportsMultiDisplay;
+ } else {
+ mSupportsMultiWindow = false;
+ mSupportsFreeformWindowManagement = false;
+ mSupportsSplitScreenMultiWindow = false;
+ mSupportsPictureInPicture = false;
+ mSupportsMultiDisplay = false;
+ }
+ mWindowManager.setForceResizableTasks(mForceResizableActivities);
+ mWindowManager.setSupportsPictureInPicture(mSupportsPictureInPicture);
+ // This happens before any activities are started, so we can change global configuration
+ // in-place.
+ updateConfigurationLocked(configuration, null, true);
+ final Configuration globalConfig = getGlobalConfiguration();
+ if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Initial config: " + globalConfig);
+
+ // Load resources only after the current configuration has been set.
+ final Resources res = mContext.getResources();
+ mThumbnailWidth = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.thumbnail_width);
+ mThumbnailHeight = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.thumbnail_height);
+
+ if ((globalConfig.uiMode & UI_MODE_TYPE_TELEVISION) == UI_MODE_TYPE_TELEVISION) {
+ mFullscreenThumbnailScale = (float) res
+ .getInteger(com.android.internal.R.integer.thumbnail_width_tv) /
+ (float) globalConfig.screenWidthDp;
+ } else {
+ mFullscreenThumbnailScale = res.getFraction(
+ com.android.internal.R.fraction.thumbnail_fullscreen_scale, 1, 1);
+ }
+ }
+ }
+
// TODO: Will be converted to WM lock once transition is complete.
void setActivityManagerService(ActivityManagerService am) {
mAm = am;
mGlobalLock = mAm;
mH = new H(mAm.mHandlerThread.getLooper());
+ mUiHandler = new UiHandler();
mTempConfig.setToDefaults();
mTempConfig.setLocales(LocaleList.getDefault());
@@ -278,15 +474,19 @@
mStackSupervisor.onConfigurationChanged(mTempConfig);
mTaskChangeNotificationController =
- new TaskChangeNotificationController(mAm, mStackSupervisor, mH);
+ new TaskChangeNotificationController(mGlobalLock, mStackSupervisor, mH);
mLockTaskController = new LockTaskController(mContext, mStackSupervisor, mH);
mActivityStartController = new ActivityStartController(this);
mRecentTasks = createRecentTasks();
mStackSupervisor.setRecentTasks(mRecentTasks);
- mVrController = new VrController(mAm);
+ mVrController = new VrController(mGlobalLock);
mKeyguardController = mStackSupervisor.getKeyguardController();
}
+ void onActivityManagerInternalAdded() {
+ mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
+ }
+
protected ActivityStackSupervisor createStackSupervisor() {
final ActivityStackSupervisor supervisor = new ActivityStackSupervisor(this, mH.getLooper());
supervisor.initialize();
@@ -359,9 +559,8 @@
Intent[] intents, String[] resolvedTypes, IBinder resultTo, Bundle bOptions,
int userId) {
final String reason = "startActivities";
- mAm.enforceNotIsolatedCaller(reason);
- userId = mAm.mUserController.handleIncomingUser(Binder.getCallingPid(),
- Binder.getCallingUid(), userId, false, ALLOW_FULL_ONLY, reason, null);
+ enforceNotIsolatedCaller(reason);
+ userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, reason);
// TODO: Switch to user app stacks here.
return getActivityStartController().startActivities(caller, -1, callingPackage, intents,
resolvedTypes, resultTo, SafeActivityOptions.fromBundle(bOptions), userId, reason);
@@ -380,7 +579,7 @@
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
boolean validateIncomingUser) {
- mAm.enforceNotIsolatedCaller("startActivityAsUser");
+ enforceNotIsolatedCaller("startActivityAsUser");
userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
@@ -404,9 +603,8 @@
@Override
public int startActivityIntentSender(IApplicationThread caller, IIntentSender target,
IBinder whitelistToken, Intent fillInIntent, String resolvedType, IBinder resultTo,
- String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle bOptions)
- throws TransactionTooLargeException {
- mAm.enforceNotIsolatedCaller("startActivityIntentSender");
+ String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle bOptions) {
+ enforceNotIsolatedCaller("startActivityIntentSender");
// Refuse possible leaked file descriptors
if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Intent");
@@ -421,15 +619,14 @@
synchronized (mGlobalLock) {
// If this is coming from the currently resumed activity, it is
// effectively saying that app switches are allowed at this point.
- final ActivityStack stack = mAm.getFocusedStack();
+ final ActivityStack stack = getFocusedStack();
if (stack.mResumedActivity != null &&
stack.mResumedActivity.info.applicationInfo.uid == Binder.getCallingUid()) {
- mAm.mAppSwitchesAllowedTime = 0;
+ mAppSwitchesAllowedTime = 0;
}
}
- int ret = pir.sendInner(0, fillInIntent, resolvedType, whitelistToken, null, null,
+ return pir.sendInner(0, fillInIntent, resolvedType, whitelistToken, null, null,
resultTo, resultWho, requestCode, flagsMask, flagsValues, bOptions);
- return ret;
}
@Override
@@ -447,7 +644,7 @@
SafeActivityOptions.abort(options);
return false;
}
- if (r.app == null || r.app.thread == null) {
+ if (!r.attachedToProcess()) {
// The caller is not running... d'oh!
SafeActivityOptions.abort(options);
return false;
@@ -527,7 +724,7 @@
// TODO(b/64750076): Check if calling pid should really be -1.
final int res = getActivityStartController()
.obtainStarter(intent, "startNextMatchingActivity")
- .setCaller(r.app.thread)
+ .setCaller(r.app.getThread())
.setResolvedType(r.resolvedType)
.setActivityInfo(aInfo)
.setResultTo(resultTo != null ? resultTo.appToken : null)
@@ -556,10 +753,9 @@
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
final WaitResult res = new WaitResult();
synchronized (mGlobalLock) {
- mAm.enforceNotIsolatedCaller("startActivityAndWait");
- userId = mAm.mUserController.handleIncomingUser(Binder.getCallingPid(),
- Binder.getCallingUid(), userId, false, ALLOW_FULL_ONLY,
- "startActivityAndWait", null);
+ enforceNotIsolatedCaller("startActivityAndWait");
+ userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+ userId, "startActivityAndWait");
// TODO: Switch to user app stacks here.
getActivityStartController().obtainStarter(intent, "startActivityAndWait")
.setCaller(caller)
@@ -583,10 +779,9 @@
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, Configuration config, Bundle bOptions, int userId) {
synchronized (mGlobalLock) {
- mAm.enforceNotIsolatedCaller("startActivityWithConfig");
- userId = mAm.mUserController.handleIncomingUser(Binder.getCallingPid(),
- Binder.getCallingUid(), userId, false, ALLOW_FULL_ONLY,
- "startActivityWithConfig", null);
+ enforceNotIsolatedCaller("startActivityWithConfig");
+ userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
+ "startActivityWithConfig");
// TODO: Switch to user app stacks here.
return getActivityStartController().obtainStarter(intent, "startActivityWithConfig")
.setCaller(caller)
@@ -632,12 +827,12 @@
if (sourceRecord.app == null) {
throw new SecurityException("Called without a process attached to activity");
}
- if (UserHandle.getAppId(sourceRecord.app.uid) != SYSTEM_UID) {
+ if (UserHandle.getAppId(sourceRecord.app.mUid) != SYSTEM_UID) {
// This is still okay, as long as this activity is running under the
// uid of the original calling activity.
- if (sourceRecord.app.uid != sourceRecord.launchedFromUid) {
+ if (sourceRecord.app.mUid != sourceRecord.launchedFromUid) {
throw new SecurityException(
- "Calling activity in uid " + sourceRecord.app.uid
+ "Calling activity in uid " + sourceRecord.app.mUid
+ " must be system uid or original calling uid "
+ sourceRecord.launchedFromUid);
}
@@ -658,7 +853,7 @@
}
if (userId == UserHandle.USER_NULL) {
- userId = UserHandle.getUserId(sourceRecord.app.uid);
+ userId = UserHandle.getUserId(sourceRecord.app.mUid);
}
// TODO: Switch to user app stacks here.
@@ -692,17 +887,21 @@
}
}
+ int handleIncomingUser(int callingPid, int callingUid, int userId, String name) {
+ return mAmInternal.handleIncomingUser(callingPid, callingUid, userId, false /* allowAll */,
+ ALLOW_FULL_ONLY, name, null /* callerPackage */);
+ }
+
@Override
public int startVoiceActivity(String callingPackage, int callingPid, int callingUid,
Intent intent, String resolvedType, IVoiceInteractionSession session,
IVoiceInteractor interactor, int startFlags, ProfilerInfo profilerInfo,
Bundle bOptions, int userId) {
- mAm.enforceCallingPermission(BIND_VOICE_INTERACTION, "startVoiceActivity()");
+ mAmInternal.enforceCallingPermission(BIND_VOICE_INTERACTION, "startVoiceActivity()");
if (session == null || interactor == null) {
throw new NullPointerException("null session or interactor");
}
- userId = mAm.mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
- ALLOW_FULL_ONLY, "startVoiceActivity", null);
+ userId = handleIncomingUser(callingPid, callingUid, userId, "startVoiceActivity");
// TODO: Switch to user app stacks here.
return getActivityStartController().obtainStarter(intent, "startVoiceActivity")
.setCallingUid(callingUid)
@@ -720,9 +919,8 @@
@Override
public int startAssistantActivity(String callingPackage, int callingPid, int callingUid,
Intent intent, String resolvedType, Bundle bOptions, int userId) {
- mAm.enforceCallingPermission(BIND_VOICE_INTERACTION, "startAssistantActivity()");
- userId = mAm.mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
- ALLOW_FULL_ONLY, "startAssistantActivity", null);
+ mAmInternal.enforceCallingPermission(BIND_VOICE_INTERACTION, "startAssistantActivity()");
+ userId = handleIncomingUser(callingPid, callingUid, userId, "startAssistantActivity");
return getActivityStartController().obtainStarter(intent, "startAssistantActivity")
.setCallingUid(callingUid)
@@ -736,7 +934,7 @@
@Override
public void startRecentsActivity(Intent intent, IAssistDataReceiver assistDataReceiver,
IRecentsAnimationRunner recentsAnimationRunner) {
- mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "startRecentsActivity()");
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "startRecentsActivity()");
final int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
try {
@@ -745,9 +943,8 @@
final int recentsUid = mRecentTasks.getRecentsComponentUid();
// Start a new recents animation
- final RecentsAnimation anim = new RecentsAnimation(mAm, mStackSupervisor,
- getActivityStartController(), mAm.mWindowManager, mAm.mUserController,
- callingPid);
+ final RecentsAnimation anim = new RecentsAnimation(this, mStackSupervisor,
+ getActivityStartController(), mWindowManager, callingPid);
anim.startRecentsActivity(intent, recentsAnimationRunner, recentsComponent,
recentsUid, assistDataReceiver);
}
@@ -758,7 +955,7 @@
@Override
public final int startActivityFromRecents(int taskId, Bundle bOptions) {
- mAm.enforceCallerIsRecentsOrHasPermission(START_TASKS_FROM_RECENTS,
+ enforceCallerIsRecentsOrHasPermission(START_TASKS_FROM_RECENTS,
"startActivityFromRecents()");
final int callingPid = Binder.getCallingPid();
@@ -810,16 +1007,18 @@
return false;
}
- if (mAm.mController != null) {
+ // TODO: There is a dup. of this block of code in ActivityStack.navigateUpToLocked
+ // We should consolidate.
+ if (mController != null) {
// Find the first activity that is not finishing.
ActivityRecord next = r.getStack().topRunningActivityLocked(token, 0);
if (next != null) {
// ask watcher if this is allowed
boolean resumeOK = true;
try {
- resumeOK = mAm.mController.activityResuming(next.packageName);
+ resumeOK = mController.activityResuming(next.packageName);
} catch (RemoteException e) {
- mAm.mController = null;
+ mController = null;
Watchdog.getInstance().setActivityController(null);
}
@@ -886,20 +1085,25 @@
@Override
public final void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {
final long origId = Binder.clearCallingIdentity();
- synchronized (mGlobalLock) {
- ActivityStack stack = ActivityRecord.getStackLocked(token);
- if (stack != null) {
- ActivityRecord r =
- mStackSupervisor.activityIdleInternalLocked(token, false /* fromTimeout */,
- false /* processPausingActivities */, config);
- if (stopProfiling) {
- if ((mAm.mProfileProc == r.app) && mAm.mProfilerInfo != null) {
- mAm.clearProfilerLocked();
- }
+ try {
+ WindowProcessController proc = null;
+ synchronized (mGlobalLock) {
+ ActivityStack stack = ActivityRecord.getStackLocked(token);
+ if (stack == null) {
+ return;
+ }
+ final ActivityRecord r = mStackSupervisor.activityIdleInternalLocked(token,
+ false /* fromTimeout */, false /* processPausingActivities */, config);
+ if (r != null) {
+ proc = r.app;
+ }
+ if (stopProfiling && proc != null) {
+ proc.clearProfilerIfNeeded();
}
}
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
- Binder.restoreCallingIdentity(origId);
}
@Override
@@ -907,7 +1111,7 @@
final long origId = Binder.clearCallingIdentity();
synchronized (mGlobalLock) {
ActivityRecord.activityResumedLocked(token);
- mAm.mWindowManager.notifyAppResumedFinished(token);
+ mWindowManager.notifyAppResumedFinished(token);
}
Binder.restoreCallingIdentity(origId);
}
@@ -943,7 +1147,7 @@
}
}
- mAm.trimApplications();
+ mAmInternal.trimApplications();
Binder.restoreCallingIdentity(origId);
}
@@ -1022,11 +1226,30 @@
// update associated state if we're frontmost
if (r == mStackSupervisor.getResumedActivityLocked()) {
if (DEBUG_IMMERSIVE) Slog.d(TAG_IMMERSIVE, "Frontmost changed immersion: "+ r);
- mAm.applyUpdateLockStateLocked(r);
+ applyUpdateLockStateLocked(r);
}
}
}
+ void applyUpdateLockStateLocked(ActivityRecord r) {
+ // Modifications to the UpdateLock state are done on our handler, outside
+ // the activity manager's locks. The new state is determined based on the
+ // state *now* of the relevant activity record. The object is passed to
+ // the handler solely for logging detail, not to be consulted/modified.
+ final boolean nextState = r != null && r.immersive;
+ mH.post(() -> {
+ if (mUpdateLock.isHeld() != nextState) {
+ if (DEBUG_IMMERSIVE) Slog.d(TAG_IMMERSIVE,
+ "Applying new update lock state '" + nextState + "' for " + r);
+ if (nextState) {
+ mUpdateLock.acquire();
+ } else {
+ mUpdateLock.release();
+ }
+ }
+ });
+ }
+
@Override
public boolean isImmersive(IBinder token) {
synchronized (mGlobalLock) {
@@ -1040,9 +1263,9 @@
@Override
public boolean isTopActivityImmersive() {
- mAm.enforceNotIsolatedCaller("isTopActivityImmersive");
+ enforceNotIsolatedCaller("isTopActivityImmersive");
synchronized (mGlobalLock) {
- final ActivityRecord r = mAm.getFocusedStack().topRunningActivityLocked();
+ final ActivityRecord r = getFocusedStack().topRunningActivityLocked();
return (r != null) ? r.immersive : false;
}
}
@@ -1060,7 +1283,7 @@
if (self.isState(
ActivityStack.ActivityState.RESUMED, ActivityStack.ActivityState.PAUSING)) {
- mAm.mWindowManager.overridePendingAppTransition(packageName,
+ mWindowManager.overridePendingAppTransition(packageName,
enterAnim, exitAnim, null);
}
@@ -1070,19 +1293,34 @@
@Override
public int getFrontActivityScreenCompatMode() {
- mAm.enforceNotIsolatedCaller("getFrontActivityScreenCompatMode");
+ enforceNotIsolatedCaller("getFrontActivityScreenCompatMode");
+ ApplicationInfo ai;
synchronized (mGlobalLock) {
- return mAm.mCompatModePackages.getFrontActivityScreenCompatModeLocked();
+ final ActivityRecord r = getFocusedStack().topRunningActivityLocked();
+ if (r == null) {
+ return ActivityManager.COMPAT_MODE_UNKNOWN;
+ }
+ ai = r.info.applicationInfo;
}
+
+ return mAmInternal.getPackageScreenCompatMode(ai);
}
@Override
public void setFrontActivityScreenCompatMode(int mode) {
- mAm.enforceCallingPermission(android.Manifest.permission.SET_SCREEN_COMPATIBILITY,
+ mAmInternal.enforceCallingPermission(android.Manifest.permission.SET_SCREEN_COMPATIBILITY,
"setFrontActivityScreenCompatMode");
+ ApplicationInfo ai;
synchronized (mGlobalLock) {
- mAm.mCompatModePackages.setFrontActivityScreenCompatModeLocked(mode);
+ final ActivityRecord r = getFocusedStack().topRunningActivityLocked();
+ if (r == null) {
+ Slog.w(TAG, "setFrontActivityScreenCompatMode failed: no top activity");
+ return;
+ }
+ ai = r.info.applicationInfo;
}
+
+ mAmInternal.setPackageScreenCompatMode(ai, mode);
}
@Override
@@ -1122,7 +1360,7 @@
if (translucentChanged) {
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
- mAm.mWindowManager.setAppFullscreen(token, true);
+ mWindowManager.setAppFullscreen(token, true);
return translucentChanged;
}
} finally {
@@ -1151,7 +1389,7 @@
r.getStack().convertActivityToTranslucent(r);
}
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
- mAm.mWindowManager.setAppFullscreen(token, false);
+ mWindowManager.setAppFullscreen(token, false);
return translucentChanged;
}
} finally {
@@ -1194,11 +1432,11 @@
@Override
public ActivityManager.StackInfo getFocusedStackInfo() throws RemoteException {
- mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getStackInfo()");
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getStackInfo()");
long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
- ActivityStack focusedStack = mAm.getFocusedStack();
+ ActivityStack focusedStack = getFocusedStack();
if (focusedStack != null) {
return mStackSupervisor.getStackInfo(focusedStack.mStackId);
}
@@ -1211,7 +1449,7 @@
@Override
public void setFocusedStack(int stackId) {
- mAm.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "setFocusedStack()");
+ mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "setFocusedStack()");
if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedStack: stackId=" + stackId);
final long callingId = Binder.clearCallingIdentity();
try {
@@ -1234,7 +1472,7 @@
@Override
public void setFocusedTask(int taskId) {
- mAm.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "setFocusedTask()");
+ mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "setFocusedTask()");
if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedTask: taskId=" + taskId);
final long callingId = Binder.clearCallingIdentity();
try {
@@ -1255,7 +1493,7 @@
@Override
public boolean removeTask(int taskId) {
- mAm.enforceCallerIsRecentsOrHasPermission(REMOVE_TASKS, "removeTask()");
+ enforceCallerIsRecentsOrHasPermission(REMOVE_TASKS, "removeTask()");
synchronized (mGlobalLock) {
final long ident = Binder.clearCallingIdentity();
try {
@@ -1312,7 +1550,7 @@
*/
@Override
public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
- mAm.enforceNotIsolatedCaller("moveActivityTaskToBack");
+ enforceNotIsolatedCaller("moveActivityTaskToBack");
synchronized (mGlobalLock) {
final long origId = Binder.clearCallingIdentity();
try {
@@ -1330,7 +1568,7 @@
@Override
public Rect getTaskBounds(int taskId) {
- mAm.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "getTaskBounds()");
+ mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "getTaskBounds()");
long ident = Binder.clearCallingIdentity();
Rect rect = new Rect();
try {
@@ -1364,7 +1602,7 @@
@Override
public ActivityManager.TaskDescription getTaskDescription(int id) {
synchronized (mGlobalLock) {
- mAm.enforceCallerIsRecentsOrHasPermission(
+ enforceCallerIsRecentsOrHasPermission(
MANAGE_ACTIVITY_STACKS, "getTaskDescription()");
final TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(id,
MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
@@ -1382,7 +1620,7 @@
toTop, ANIMATE, null /* initialBounds */, true /* showRecents */);
return;
}
- mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "setTaskWindowingMode()");
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "setTaskWindowingMode()");
synchronized (mGlobalLock) {
final long ident = Binder.clearCallingIdentity();
try {
@@ -1414,7 +1652,7 @@
@Override
public String getCallingPackage(IBinder token) {
- synchronized (this) {
+ synchronized (mGlobalLock) {
ActivityRecord r = getCallingRecordLocked(token);
return r != null ? r.info.packageName : null;
}
@@ -1422,7 +1660,7 @@
@Override
public ComponentName getCallingActivity(IBinder token) {
- synchronized (this) {
+ synchronized (mGlobalLock) {
ActivityRecord r = getCallingRecordLocked(token);
return r != null ? r.intent.getComponent() : null;
}
@@ -1438,12 +1676,12 @@
@Override
public void unhandledBack() {
- mAm.enforceCallingPermission(android.Manifest.permission.FORCE_BACK, "unhandledBack()");
+ mAmInternal.enforceCallingPermission(android.Manifest.permission.FORCE_BACK, "unhandledBack()");
synchronized (mGlobalLock) {
final long origId = Binder.clearCallingIdentity();
try {
- mAm.getFocusedStack().unhandledBackLocked();
+ getFocusedStack().unhandledBackLocked();
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -1455,7 +1693,7 @@
*/
@Override
public void moveTaskToFront(int taskId, int flags, Bundle bOptions) {
- mAm.enforceCallingPermission(android.Manifest.permission.REORDER_TASKS, "moveTaskToFront()");
+ mAmInternal.enforceCallingPermission(android.Manifest.permission.REORDER_TASKS, "moveTaskToFront()");
if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToFront: moving taskId=" + taskId);
synchronized (mGlobalLock) {
@@ -1467,7 +1705,7 @@
void moveTaskToFrontLocked(int taskId, int flags, SafeActivityOptions options,
boolean fromRecents) {
- if (!mAm.checkAppSwitchAllowedLocked(Binder.getCallingPid(),
+ if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
Binder.getCallingUid(), -1, -1, "Task to front")) {
SafeActivityOptions.abort(options);
return;
@@ -1503,6 +1741,69 @@
SafeActivityOptions.abort(options);
}
+ boolean checkAppSwitchAllowedLocked(int sourcePid, int sourceUid,
+ int callingPid, int callingUid, String name) {
+ if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
+ return true;
+ }
+
+ if (getRecentTasks().isCallerRecents(sourceUid)) {
+ return true;
+ }
+
+ int perm = checkComponentPermission(STOP_APP_SWITCHES, sourcePid, sourceUid, -1, true);
+ if (perm == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
+ if (checkAllowAppSwitchUid(sourceUid)) {
+ return true;
+ }
+
+ // If the actual IPC caller is different from the logical source, then
+ // also see if they are allowed to control app switches.
+ if (callingUid != -1 && callingUid != sourceUid) {
+ perm = checkComponentPermission(STOP_APP_SWITCHES, callingPid, callingUid, -1, true);
+ if (perm == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
+ if (checkAllowAppSwitchUid(callingUid)) {
+ return true;
+ }
+ }
+
+ Slog.w(TAG, name + " request from " + sourceUid + " stopped");
+ return false;
+ }
+
+ private boolean checkAllowAppSwitchUid(int uid) {
+ ArrayMap<String, Integer> types = mAllowAppSwitchUids.get(UserHandle.getUserId(uid));
+ if (types != null) {
+ for (int i = types.size() - 1; i >= 0; i--) {
+ if (types.valueAt(i).intValue() == uid) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void setActivityController(IActivityController controller, boolean imAMonkey) {
+ mAmInternal.enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
+ "setActivityController()");
+ synchronized (mGlobalLock) {
+ mController = controller;
+ mControllerIsAMonkey = imAMonkey;
+ Watchdog.getInstance().setActivityController(controller);
+ }
+ }
+
+ boolean isControllerAMonkey() {
+ synchronized (mGlobalLock) {
+ return mController != null && mControllerIsAMonkey;
+ }
+ }
+
@Override
public int getTaskForActivity(IBinder token, boolean onlyRoot) {
synchronized (mGlobalLock) {
@@ -1525,7 +1826,7 @@
synchronized (mGlobalLock) {
if (DEBUG_ALL) Slog.v(TAG, "getTasks: max=" + maxNum);
- final boolean allowed = mAm.isGetTasksAllowed("getTasks", Binder.getCallingPid(),
+ final boolean allowed = isGetTasksAllowed("getTasks", Binder.getCallingPid(),
callingUid);
mStackSupervisor.getRunningTasks(maxNum, list, ignoreActivityType,
ignoreWindowingMode, callingUid, allowed);
@@ -1548,7 +1849,7 @@
@Override
public boolean willActivityBeVisible(IBinder token) {
- synchronized(this) {
+ synchronized (mGlobalLock) {
ActivityStack stack = ActivityRecord.getStackLocked(token);
if (stack != null) {
return stack.willActivityBeVisibleLocked(token);
@@ -1559,7 +1860,7 @@
@Override
public void moveTaskToStack(int taskId, int stackId, boolean toTop) {
- mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToStack()");
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToStack()");
synchronized (mGlobalLock) {
final long ident = Binder.clearCallingIdentity();
try {
@@ -1582,7 +1883,7 @@
+ taskId + " to stack " + stackId);
}
if (stack.inSplitScreenPrimaryWindowingMode()) {
- mAm.mWindowManager.setDockedStackCreateState(
+ mWindowManager.setDockedStackCreateState(
SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, null /* initialBounds */);
}
task.reparent(stack, toTop, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME,
@@ -1596,7 +1897,7 @@
@Override
public void resizeStack(int stackId, Rect destBounds, boolean allowResizeInDockedMode,
boolean preserveWindows, boolean animate, int animationDuration) {
- mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "resizeStack()");
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "resizeStack()");
final long ident = Binder.clearCallingIdentity();
try {
@@ -1648,7 +1949,7 @@
@Override
public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode,
boolean toTop, boolean animate, Rect initialBounds, boolean showRecents) {
- mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
"setTaskWindowingModeSplitScreenPrimary()");
synchronized (mGlobalLock) {
final long ident = Binder.clearCallingIdentity();
@@ -1666,7 +1967,7 @@
+ " non-standard task " + taskId + " to split-screen windowing mode");
}
- mAm.mWindowManager.setDockedStackCreateState(createMode, initialBounds);
+ mWindowManager.setDockedStackCreateState(createMode, initialBounds);
final int windowingMode = task.getWindowingMode();
final ActivityStack stack = task.getStack();
if (toTop) {
@@ -1687,7 +1988,7 @@
*/
@Override
public void removeStacksInWindowingModes(int[] windowingModes) {
- mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
"removeStacksInWindowingModes()");
synchronized (mGlobalLock) {
@@ -1702,7 +2003,7 @@
@Override
public void removeStacksWithActivityTypes(int[] activityTypes) {
- mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
"removeStacksWithActivityTypes()");
synchronized (mGlobalLock) {
@@ -1719,12 +2020,12 @@
public ParceledListSlice<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum, int flags,
int userId) {
final int callingUid = Binder.getCallingUid();
- userId = mAm.mUserController.handleIncomingUser(Binder.getCallingPid(), callingUid, userId,
- false, ALLOW_FULL_ONLY, "getRecentTasks", null);
- final boolean allowed = mAm.isGetTasksAllowed("getRecentTasks", Binder.getCallingPid(),
+ userId = handleIncomingUser(Binder.getCallingPid(), callingUid, userId, "getRecentTasks");
+ final boolean allowed = isGetTasksAllowed("getRecentTasks", Binder.getCallingPid(),
callingUid);
- final boolean detailed = mAm.checkCallingPermission(
- android.Manifest.permission.GET_DETAILED_TASKS)
+ final boolean detailed = checkGetTasksPermission(
+ android.Manifest.permission.GET_DETAILED_TASKS, Binder.getCallingPid(),
+ UserHandle.getAppId(callingUid))
== PackageManager.PERMISSION_GRANTED;
synchronized (mGlobalLock) {
@@ -1735,7 +2036,7 @@
@Override
public List<ActivityManager.StackInfo> getAllStackInfos() {
- mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getAllStackInfos()");
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getAllStackInfos()");
long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -1748,7 +2049,7 @@
@Override
public ActivityManager.StackInfo getStackInfo(int windowingMode, int activityType) {
- mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getStackInfo()");
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getStackInfo()");
long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -1761,13 +2062,13 @@
@Override
public void cancelRecentsAnimation(boolean restoreHomeStackPosition) {
- mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "cancelRecentsAnimation()");
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "cancelRecentsAnimation()");
final long callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
// Cancel the recents animation synchronously (do not hold the WM lock)
- mAm.mWindowManager.cancelRecentsAnimationSynchronously(restoreHomeStackPosition
+ mWindowManager.cancelRecentsAnimationSynchronously(restoreHomeStackPosition
? REORDER_MOVE_TO_ORIGINAL_POSITION
: REORDER_KEEP_IN_PLACE, "cancelRecentsAnimation/uid=" + callingUid);
}
@@ -1789,7 +2090,7 @@
@Override
public void startSystemLockTaskMode(int taskId) throws RemoteException {
- mAm.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "startSystemLockTaskMode");
+ mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "startSystemLockTaskMode");
// This makes inner call to look as if it was initiated by system.
long ident = Binder.clearCallingIdentity();
try {
@@ -1822,7 +2123,7 @@
*/
@Override
public void stopSystemLockTaskMode() throws RemoteException {
- mAm.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "stopSystemLockTaskMode");
+ mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "stopSystemLockTaskMode");
stopLockTaskModeInternal(null, true /* isSystemCaller */);
}
@@ -1964,9 +2265,9 @@
mH.post(() -> {
synchronized (mGlobalLock) {
ActivityRecord r = ActivityRecord.forTokenLocked(token);
- if (r != null && r.app != null && r.app.thread != null) {
+ if (r != null && r.attachedToProcess()) {
try {
- r.app.thread.scheduleEnterAnimationComplete(r.appToken);
+ r.app.getThread().scheduleEnterAnimationComplete(r.appToken);
} catch (RemoteException e) {
}
}
@@ -1979,7 +2280,7 @@
@Override
public void reportAssistContextExtras(IBinder token, Bundle extras, AssistStructure structure,
AssistContent content, Uri referrer) {
- PendingAssistExtras pae = (PendingAssistExtras)token;
+ PendingAssistExtras pae = (PendingAssistExtras) token;
synchronized (pae) {
pae.result = extras;
pae.structure = structure;
@@ -2003,13 +2304,13 @@
synchronized (mGlobalLock) {
buildAssistBundleLocked(pae, extras);
boolean exists = mPendingAssistExtras.remove(pae);
- mAm.mUiHandler.removeCallbacks(pae);
+ mUiHandler.removeCallbacks(pae);
if (!exists) {
// Timed out.
return;
}
- if ((sendReceiver=pae.receiver) != null) {
+ if ((sendReceiver = pae.receiver) != null) {
// Caller wants result sent back to them.
sendBundle = new Bundle();
sendBundle.putBundle(ASSIST_KEY_DATA, pae.extras);
@@ -2037,7 +2338,7 @@
pae.intent.setFlags(FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_SINGLE_TOP
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
- mAm.closeSystemDialogs("assist");
+ mAmInternal.closeSystemDialogs("assist");
try {
mContext.startActivityAsUser(pae.intent, new UserHandle(pae.userHandle));
@@ -2068,11 +2369,11 @@
throw new IllegalArgumentException("Intent " + intent
+ " must specify explicit component");
}
- if (thumbnail.getWidth() != mAm.mThumbnailWidth
- || thumbnail.getHeight() != mAm.mThumbnailHeight) {
+ if (thumbnail.getWidth() != mThumbnailWidth
+ || thumbnail.getHeight() != mThumbnailHeight) {
throw new IllegalArgumentException("Bad thumbnail size: got "
+ thumbnail.getWidth() + "x" + thumbnail.getHeight() + ", require "
- + mAm.mThumbnailWidth + "x" + mAm.mThumbnailHeight);
+ + mThumbnailWidth + "x" + mThumbnailHeight);
}
if (intent.getSelector() != null) {
intent.setSelector(null);
@@ -2118,7 +2419,7 @@
@Override
public Point getAppTaskThumbnailSize() {
synchronized (mGlobalLock) {
- return new Point(mAm.mThumbnailWidth, mAm.mThumbnailHeight);
+ return new Point(mThumbnailWidth, mThumbnailHeight);
}
}
@@ -2137,7 +2438,7 @@
@Override
public void resizeTask(int taskId, Rect bounds, int resizeMode) {
- mAm.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "resizeTask()");
+ mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "resizeTask()");
long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -2204,7 +2505,8 @@
synchronized (mGlobalLock) {
final long origId = Binder.clearCallingIdentity();
try {
- ProcessRecord app = mAm.getRecordForAppLocked(appInt);
+ WindowProcessController app =
+ mAm.getRecordForAppLocked(appInt).getWindowProcessController();
mStackSupervisor.releaseSomeActivitiesLocked(app, "low-mem");
} finally {
Binder.restoreCallingIdentity(origId);
@@ -2215,7 +2517,7 @@
@Override
public void setLockScreenShown(boolean keyguardShowing, boolean aodShowing,
int secondaryDisplayShowing) {
- if (mAm.checkCallingPermission(android.Manifest.permission.DEVICE_POWER)
+ if (checkCallingPermission(android.Manifest.permission.DEVICE_POWER)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires permission "
+ android.Manifest.permission.DEVICE_POWER);
@@ -2235,14 +2537,25 @@
}
}
- mAm.mHandler.obtainMessage(DISPATCH_SCREEN_KEYGUARD_MSG, keyguardShowing ? 1 : 0, 0)
- .sendToTarget();
+ mH.post(() -> {
+ for (int i = mScreenObservers.size() - 1; i >= 0; i--) {
+ mScreenObservers.get(i).onKeyguardStateChanged(keyguardShowing);
+ }
+ });
+ }
+
+ void onScreenAwakeChanged(boolean isAwake) {
+ mH.post(() -> {
+ for (int i = mScreenObservers.size() - 1; i >= 0; i--) {
+ mScreenObservers.get(i).onAwakeStateChanged(isAwake);
+ }
+ });
}
@Override
public Bitmap getTaskDescriptionIcon(String filePath, int userId) {
- userId = mAm.mUserController.handleIncomingUser(Binder.getCallingPid(),
- Binder.getCallingUid(), userId, false, ALLOW_FULL_ONLY, "getTaskDescriptionIcon", null);
+ userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+ userId, "getTaskDescriptionIcon");
final File passedIconFile = new File(filePath);
final File legitIconFile = new File(TaskPersister.getUserImagesDir(userId),
@@ -2256,8 +2569,7 @@
}
@Override
- public void startInPlaceAnimationOnFrontMostApplication(Bundle opts)
- throws RemoteException {
+ public void startInPlaceAnimationOnFrontMostApplication(Bundle opts) {
final SafeActivityOptions safeOptions = SafeActivityOptions.fromBundle(opts);
final ActivityOptions activityOptions = safeOptions != null
? safeOptions.getOptions(mStackSupervisor)
@@ -2268,15 +2580,15 @@
throw new IllegalArgumentException("Expected in-place ActivityOption " +
"with valid animation");
}
- mAm.mWindowManager.prepareAppTransition(TRANSIT_TASK_IN_PLACE, false);
- mAm.mWindowManager.overridePendingAppTransitionInPlace(activityOptions.getPackageName(),
+ mWindowManager.prepareAppTransition(TRANSIT_TASK_IN_PLACE, false);
+ mWindowManager.overridePendingAppTransitionInPlace(activityOptions.getPackageName(),
activityOptions.getCustomInPlaceResId());
- mAm.mWindowManager.executeAppTransition();
+ mWindowManager.executeAppTransition();
}
@Override
public void removeStack(int stackId) {
- mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "removeStack()");
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "removeStack()");
synchronized (mGlobalLock) {
final long ident = Binder.clearCallingIdentity();
try {
@@ -2298,7 +2610,7 @@
@Override
public void moveStackToDisplay(int stackId, int displayId) {
- mAm.enforceCallingPermission(INTERNAL_SYSTEM_WINDOW, "moveStackToDisplay()");
+ mAmInternal.enforceCallingPermission(INTERNAL_SYSTEM_WINDOW, "moveStackToDisplay()");
synchronized (mGlobalLock) {
final long ident = Binder.clearCallingIdentity();
@@ -2314,7 +2626,7 @@
@Override
public int createStackOnDisplay(int displayId) {
- mAm.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "createStackOnDisplay()");
+ mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "createStackOnDisplay()");
synchronized (mGlobalLock) {
final ActivityDisplay display =
mStackSupervisor.getActivityDisplayOrCreateLocked(displayId);
@@ -2356,7 +2668,7 @@
/** Sets the task stack listener that gets callbacks when a task stack changes. */
@Override
public void registerTaskStackListener(ITaskStackListener listener) {
- mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
"registerTaskStackListener()");
mTaskChangeNotificationController.registerTaskStackListener(listener);
}
@@ -2364,7 +2676,7 @@
/** Unregister a task stack listener so that it stops receiving callbacks. */
@Override
public void unregisterTaskStackListener(ITaskStackListener listener) {
- mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
"unregisterTaskStackListener()");
mTaskChangeNotificationController.unregisterTaskStackListener(listener);
}
@@ -2418,25 +2730,83 @@
synchronized (mGlobalLock) {
buildAssistBundleLocked(pae, pae.result);
mPendingAssistExtras.remove(pae);
- mAm.mUiHandler.removeCallbacks(pae);
+ mUiHandler.removeCallbacks(pae);
}
return pae.extras;
}
+ /**
+ * Binder IPC calls go through the public entry point.
+ * This can be called with or without the global lock held.
+ */
+ private static int checkCallingPermission(String permission) {
+ return checkPermission(
+ permission, Binder.getCallingPid(), UserHandle.getAppId(Binder.getCallingUid()));
+ }
+
+ /** This can be called with or without the global lock held. */
+ void enforceCallerIsRecentsOrHasPermission(String permission, String func) {
+ if (!getRecentTasks().isCallerRecents(Binder.getCallingUid())) {
+ mAmInternal.enforceCallingPermission(permission, func);
+ }
+ }
+
+ @VisibleForTesting
+ int checkGetTasksPermission(String permission, int pid, int uid) {
+ return checkPermission(permission, pid, uid);
+ }
+
+ static int checkPermission(String permission, int pid, int uid) {
+ if (permission == null) {
+ return PackageManager.PERMISSION_DENIED;
+ }
+ return checkComponentPermission(permission, pid, uid, -1, true);
+ }
+
+ boolean isGetTasksAllowed(String caller, int callingPid, int callingUid) {
+ if (getRecentTasks().isCallerRecents(callingUid)) {
+ // Always allow the recents component to get tasks
+ return true;
+ }
+
+ boolean allowed = checkGetTasksPermission(android.Manifest.permission.REAL_GET_TASKS,
+ callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
+ if (!allowed) {
+ if (checkGetTasksPermission(android.Manifest.permission.GET_TASKS,
+ callingPid, callingUid) == PackageManager.PERMISSION_GRANTED) {
+ // Temporary compatibility: some existing apps on the system image may
+ // still be requesting the old permission and not switched to the new
+ // one; if so, we'll still allow them full access. This means we need
+ // to see if they are holding the old permission and are a system app.
+ try {
+ if (AppGlobals.getPackageManager().isUidPrivileged(callingUid)) {
+ allowed = true;
+ if (DEBUG_TASKS) Slog.w(TAG, caller + ": caller " + callingUid
+ + " is using old GET_TASKS but privileged; allowing");
+ }
+ } catch (RemoteException e) {
+ }
+ }
+ if (DEBUG_TASKS) Slog.w(TAG, caller + ": caller " + callingUid
+ + " does not hold REAL_GET_TASKS; limiting output");
+ }
+ return allowed;
+ }
+
private PendingAssistExtras enqueueAssistContext(int requestType, Intent intent, String hint,
IAssistDataReceiver receiver, Bundle receiverExtras, IBinder activityToken,
boolean focused, boolean newSessionId, int userHandle, Bundle args, long timeout,
int flags) {
- mAm.enforceCallingPermission(android.Manifest.permission.GET_TOP_ACTIVITY_INFO,
+ mAmInternal.enforceCallingPermission(android.Manifest.permission.GET_TOP_ACTIVITY_INFO,
"enqueueAssistContext()");
synchronized (mGlobalLock) {
- ActivityRecord activity = mAm.getFocusedStack().getTopActivity();
+ ActivityRecord activity = getFocusedStack().getTopActivity();
if (activity == null) {
Slog.w(TAG, "getAssistContextExtras failed: no top activity");
return null;
}
- if (activity.app == null || activity.app.thread == null) {
+ if (!activity.attachedToProcess()) {
Slog.w(TAG, "getAssistContextExtras failed: no process for " + activity);
return null;
}
@@ -2456,7 +2826,7 @@
+ " couldn't be found");
return null;
}
- if (activity.app == null || activity.app.thread == null) {
+ if (!activity.attachedToProcess()) {
Slog.w(TAG, "enqueueAssistContext failed: no process for " + activity);
return null;
}
@@ -2468,7 +2838,7 @@
extras.putAll(args);
}
extras.putString(Intent.EXTRA_ASSIST_PACKAGE, activity.packageName);
- extras.putInt(Intent.EXTRA_ASSIST_UID, activity.app.uid);
+ extras.putInt(Intent.EXTRA_ASSIST_UID, activity.app.mUid);
pae = new PendingAssistExtras(activity, extras, intent, hint, receiver, receiverExtras,
userHandle);
@@ -2479,10 +2849,10 @@
mViSessionId++;
}
try {
- activity.app.thread.requestAssistContextExtras(activity.appToken, pae, requestType,
- mViSessionId, flags);
+ activity.app.getThread().requestAssistContextExtras(activity.appToken, pae,
+ requestType, mViSessionId, flags);
mPendingAssistExtras.add(pae);
- mAm.mUiHandler.postDelayed(pae, timeout);
+ mUiHandler.postDelayed(pae, timeout);
} catch (RemoteException e) {
Slog.w(TAG, "getAssistContextExtras failed: crash calling " + activity);
return null;
@@ -2559,7 +2929,7 @@
public boolean isAssistDataAllowedOnCurrentActivity() {
int userId;
synchronized (mGlobalLock) {
- final ActivityStack focusedStack = mAm.getFocusedStack();
+ final ActivityStack focusedStack = getFocusedStack();
if (focusedStack == null || focusedStack.isActivityTypeAssistant()) {
return false;
}
@@ -2579,7 +2949,7 @@
try {
synchronized (mGlobalLock) {
ActivityRecord caller = ActivityRecord.forTokenLocked(token);
- ActivityRecord top = mAm.getFocusedStack().getTopActivity();
+ ActivityRecord top = getFocusedStack().getTopActivity();
if (top != caller) {
Slog.w(TAG, "showAssistFromActivity failed: caller " + caller
+ " is not current top " + top);
@@ -2644,7 +3014,7 @@
@Override
public void keyguardGoingAway(int flags) {
- mAm.enforceNotIsolatedCaller("keyguardGoingAway");
+ enforceNotIsolatedCaller("keyguardGoingAway");
final long token = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -2662,7 +3032,7 @@
*/
@Override
public void positionTaskInStack(int taskId, int stackId, int position) {
- mAm.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "positionTaskInStack()");
+ mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "positionTaskInStack()");
synchronized (mGlobalLock) {
long ident = Binder.clearCallingIdentity();
try {
@@ -2723,7 +3093,7 @@
*/
@Override
public void dismissSplitScreenMode(boolean toTop) {
- mAm.enforceCallerIsRecentsOrHasPermission(
+ enforceCallerIsRecentsOrHasPermission(
MANAGE_ACTIVITY_STACKS, "dismissSplitScreenMode()");
final long ident = Binder.clearCallingIdentity();
try {
@@ -2765,7 +3135,7 @@
*/
@Override
public void dismissPip(boolean animate, int animationDuration) {
- mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "dismissPip()");
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "dismissPip()");
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -2793,7 +3163,7 @@
@Override
public void suppressResizeConfigChanges(boolean suppress) throws RemoteException {
- mAm.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "suppressResizeConfigChanges()");
+ mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "suppressResizeConfigChanges()");
synchronized (mGlobalLock) {
mSuppressResizeConfigChanges = suppress;
}
@@ -2807,7 +3177,7 @@
@Override
// TODO: API should just be about changing windowing modes...
public void moveTasksToFullscreenStack(int fromStackId, boolean onTop) {
- mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
"moveTasksToFullscreenStack()");
synchronized (mGlobalLock) {
final long origId = Binder.clearCallingIdentity();
@@ -2837,10 +3207,10 @@
*/
@Override
public boolean moveTopActivityToPinnedStack(int stackId, Rect bounds) {
- mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
"moveTopActivityToPinnedStack()");
synchronized (mGlobalLock) {
- if (!mAm.mSupportsPictureInPicture) {
+ if (!mSupportsPictureInPicture) {
throw new IllegalStateException("moveTopActivityToPinnedStack:"
+ "Device doesn't support picture-in-picture mode");
}
@@ -2942,8 +3312,8 @@
// device is currently locked).
dismissKeyguard(token, new KeyguardDismissCallback() {
@Override
- public void onDismissSucceeded() throws RemoteException {
- mAm.mHandler.post(enterPipRunnable);
+ public void onDismissSucceeded() {
+ mH.post(enterPipRunnable);
}
}, null /* message */);
} else {
@@ -3012,7 +3382,7 @@
*/
private ActivityRecord ensureValidPictureInPictureActivityParamsLocked(String caller,
IBinder token, PictureInPictureParams params) {
- if (!mAm.mSupportsPictureInPicture) {
+ if (!mSupportsPictureInPicture) {
throw new IllegalStateException(caller
+ ": Device doesn't support picture-in-picture mode.");
}
@@ -3029,7 +3399,7 @@
}
if (params.hasSetAspectRatio()
- && !mAm.mWindowManager.isValidPictureInPictureAspectRatio(r.getStack().mDisplayId,
+ && !mWindowManager.isValidPictureInPictureAspectRatio(r.getStack().mDisplayId,
params.getAspectRatio())) {
final float minAspectRatio = mContext.getResources().getFloat(
com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
@@ -3048,7 +3418,7 @@
@Override
public IBinder getUriPermissionOwnerForActivity(IBinder activityToken) {
- mAm.enforceNotIsolatedCaller("getUriPermissionOwnerForActivity");
+ enforceNotIsolatedCaller("getUriPermissionOwnerForActivity");
synchronized (mGlobalLock) {
ActivityRecord r = ActivityRecord.isInStackLocked(activityToken);
if (r == null) {
@@ -3063,7 +3433,7 @@
public void resizeDockedStack(Rect dockedBounds, Rect tempDockedTaskBounds,
Rect tempDockedTaskInsetBounds,
Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds) {
- mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "resizeDockedStack()");
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "resizeDockedStack()");
long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -3078,7 +3448,7 @@
@Override
public void setSplitScreenResizing(boolean resizing) {
- mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "setSplitScreenResizing()");
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "setSplitScreenResizing()");
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -3089,9 +3459,20 @@
}
}
+ /**
+ * Check that we have the features required for VR-related API calls, and throw an exception if
+ * not.
+ */
+ void enforceSystemHasVrFeature() {
+ if (!mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE)) {
+ throw new UnsupportedOperationException("VR mode not supported on this device!");
+ }
+ }
+
@Override
public int setVrMode(IBinder token, boolean enabled, ComponentName packageName) {
- mAm.enforceSystemHasVrFeature();
+ enforceSystemHasVrFeature();
final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
@@ -3131,7 +3512,7 @@
public void startLocalVoiceInteraction(IBinder callingActivity, Bundle options) {
Slog.i(TAG, "Activity tried to startLocalVoiceInteraction");
synchronized (mGlobalLock) {
- ActivityRecord activity = mAm.getFocusedStack().getTopActivity();
+ ActivityRecord activity = getFocusedStack().getTopActivity();
if (ActivityRecord.forTokenLocked(callingActivity) != activity) {
throw new SecurityException("Only focused activity can call startVoiceInteraction");
}
@@ -3176,7 +3557,7 @@
@Override
public void resizePinnedStack(Rect pinnedBounds, Rect tempPinnedTaskBounds) {
- mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "resizePinnedStack()");
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "resizePinnedStack()");
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -3189,7 +3570,7 @@
@Override
public boolean updateDisplayOverrideConfiguration(Configuration values, int displayId) {
- mAm.enforceCallingPermission(CHANGE_CONFIGURATION, "updateDisplayOverrideConfiguration()");
+ mAmInternal.enforceCallingPermission(CHANGE_CONFIGURATION, "updateDisplayOverrideConfiguration()");
synchronized (mGlobalLock) {
// Check if display is initialized in AM.
@@ -3202,14 +3583,14 @@
return false;
}
- if (values == null && mAm.mWindowManager != null) {
+ if (values == null && mWindowManager != null) {
// sentinel: fetch the current configuration from the window manager
- values = mAm.mWindowManager.computeNewConfiguration(displayId);
+ values = mWindowManager.computeNewConfiguration(displayId);
}
- if (mAm.mWindowManager != null) {
+ if (mWindowManager != null) {
// Update OOM levels based on display size.
- mAm.mProcessList.applyDisplaySize(mAm.mWindowManager);
+ mAm.mProcessList.applyDisplaySize(mWindowManager);
}
final long origId = Binder.clearCallingIdentity();
@@ -3217,7 +3598,7 @@
if (values != null) {
Settings.System.clearConfiguration(values);
}
- mAm.updateDisplayOverrideConfigurationLocked(values, null /* starting */,
+ updateDisplayOverrideConfigurationLocked(values, null /* starting */,
false /* deferResume */, displayId, mTmpUpdateConfigurationResult);
return mTmpUpdateConfigurationResult.changes != 0;
} finally {
@@ -3228,17 +3609,17 @@
@Override
public boolean updateConfiguration(Configuration values) {
- mAm.enforceCallingPermission(CHANGE_CONFIGURATION, "updateConfiguration()");
+ mAmInternal.enforceCallingPermission(CHANGE_CONFIGURATION, "updateConfiguration()");
synchronized (mGlobalLock) {
- if (values == null && mAm.mWindowManager != null) {
+ if (values == null && mWindowManager != null) {
// sentinel: fetch the current configuration from the window manager
- values = mAm.mWindowManager.computeNewConfiguration(DEFAULT_DISPLAY);
+ values = mWindowManager.computeNewConfiguration(DEFAULT_DISPLAY);
}
- if (mAm.mWindowManager != null) {
+ if (mWindowManager != null) {
// Update OOM levels based on display size.
- mAm.mProcessList.applyDisplaySize(mAm.mWindowManager);
+ mAm.mProcessList.applyDisplaySize(mWindowManager);
}
final long origId = Binder.clearCallingIdentity();
@@ -3246,7 +3627,7 @@
if (values != null) {
Settings.System.clearConfiguration(values);
}
- mAm.updateConfigurationLocked(values, null, false, false /* persistent */,
+ updateConfigurationLocked(values, null, false, false /* persistent */,
UserHandle.USER_NULL, false /* deferResume */,
mTmpUpdateConfigurationResult);
return mTmpUpdateConfigurationResult.changes != 0;
@@ -3260,7 +3641,7 @@
public void dismissKeyguard(IBinder token, IKeyguardDismissCallback callback,
CharSequence message) {
if (message != null) {
- mAm.enforceCallingPermission(
+ mAmInternal.enforceCallingPermission(
Manifest.permission.SHOW_KEYGUARD_MESSAGE, "dismissKeyguard()");
}
final long callingId = Binder.clearCallingIdentity();
@@ -3275,7 +3656,7 @@
@Override
public void cancelTaskWindowTransition(int taskId) {
- mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
"cancelTaskWindowTransition()");
final long ident = Binder.clearCallingIdentity();
try {
@@ -3295,7 +3676,7 @@
@Override
public ActivityManager.TaskSnapshot getTaskSnapshot(int taskId, boolean reducedResolution) {
- mAm.enforceCallerIsRecentsOrHasPermission(READ_FRAME_BUFFER, "getTaskSnapshot()");
+ enforceCallerIsRecentsOrHasPermission(READ_FRAME_BUFFER, "getTaskSnapshot()");
final long ident = Binder.clearCallingIdentity();
try {
final TaskRecord task;
@@ -3336,11 +3717,11 @@
@Override
public @UserIdInt
int getLastResumedActivityUserId() {
- mAm.enforceCallingPermission(
+ mAmInternal.enforceCallingPermission(
Manifest.permission.INTERACT_ACROSS_USERS_FULL, "getLastResumedActivityUserId()");
synchronized (mGlobalLock) {
if (mAm.mLastResumedActivity == null) {
- return mAm.mUserController.getCurrentUserId();
+ return getCurrentUserId();
}
return mAm.mLastResumedActivity.userId;
}
@@ -3350,7 +3731,7 @@
public void updateLockTaskFeatures(int userId, int flags) {
final int callingUid = Binder.getCallingUid();
if (callingUid != 0 && callingUid != SYSTEM_UID) {
- mAm.enforceCallingPermission(android.Manifest.permission.UPDATE_LOCK_TASK_PACKAGES,
+ mAmInternal.enforceCallingPermission(android.Manifest.permission.UPDATE_LOCK_TASK_PACKAGES,
"updateLockTaskFeatures()");
}
synchronized (mGlobalLock) {
@@ -3394,7 +3775,7 @@
@Override
public void registerRemoteAnimations(IBinder token, RemoteAnimationDefinition definition) {
- mAm.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
+ mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
"registerRemoteAnimations");
definition.setCallingPid(Binder.getCallingPid());
synchronized (mGlobalLock) {
@@ -3414,7 +3795,7 @@
@Override
public void registerRemoteAnimationForNextActivityStart(String packageName,
RemoteAnimationAdapter adapter) {
- mAm.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
+ mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
"registerRemoteAnimationForNextActivityStart");
adapter.setCallingPid(Binder.getCallingPid());
synchronized (mGlobalLock) {
@@ -3443,19 +3824,19 @@
@Override
public void setVrThread(int tid) {
- mAm.enforceSystemHasVrFeature();
+ enforceSystemHasVrFeature();
synchronized (mGlobalLock) {
synchronized (mAm.mPidsSelfLocked) {
final int pid = Binder.getCallingPid();
final ProcessRecord proc = mAm.mPidsSelfLocked.get(pid);
- mVrController.setVrThreadLocked(tid, pid, proc);
+ mVrController.setVrThreadLocked(tid, pid, proc.getWindowProcessController());
}
}
}
@Override
public void setPersistentVrThread(int tid) {
- if (mAm.checkCallingPermission(Manifest.permission.RESTRICTED_VR_ACCESS)
+ if (checkCallingPermission(Manifest.permission.RESTRICTED_VR_ACCESS)
!= PERMISSION_GRANTED) {
final String msg = "Permission Denial: setPersistentVrThread() from pid="
+ Binder.getCallingPid()
@@ -3464,7 +3845,7 @@
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
- mAm.enforceSystemHasVrFeature();
+ enforceSystemHasVrFeature();
synchronized (mGlobalLock) {
synchronized (mAm.mPidsSelfLocked) {
final int pid = Binder.getCallingPid();
@@ -3474,9 +3855,41 @@
}
}
- /**
- * @return whether the system should disable UI modes incompatible with VR mode.
- */
+ @Override
+ public void stopAppSwitches() {
+ enforceCallerIsRecentsOrHasPermission(STOP_APP_SWITCHES, "stopAppSwitches");
+ synchronized (mGlobalLock) {
+ mAppSwitchesAllowedTime = SystemClock.uptimeMillis() + APP_SWITCH_DELAY_TIME;
+ mDidAppSwitch = false;
+ getActivityStartController().schedulePendingActivityLaunches(APP_SWITCH_DELAY_TIME);
+ }
+ }
+
+ @Override
+ public void resumeAppSwitches() {
+ enforceCallerIsRecentsOrHasPermission(STOP_APP_SWITCHES, "resumeAppSwitches");
+ synchronized (mGlobalLock) {
+ // Note that we don't execute any pending app switches... we will
+ // let those wait until either the timeout, or the next start
+ // activity request.
+ mAppSwitchesAllowedTime = 0;
+ }
+ }
+
+ void onStartActivitySetDidAppSwitch() {
+ if (mDidAppSwitch) {
+ // This is the second allowed switch since we stopped switches, so now just generally
+ // allow switches. Use case:
+ // - user presses home (switches disabled, switch to home, mDidAppSwitch now true);
+ // - user taps a home icon (coming from home so allowed, we hit here and now allow
+ // anyone to switch again).
+ mAppSwitchesAllowedTime = 0;
+ } else {
+ mDidAppSwitch = true;
+ }
+ }
+
+ /** @return whether the system should disable UI modes incompatible with VR mode. */
boolean shouldDisableNonVrUiLocked() {
return mVrController.shouldDisableNonVrUiLocked();
}
@@ -3512,12 +3925,16 @@
});
}
+ ActivityStack getFocusedStack() {
+ return mStackSupervisor.getFocusedStack();
+ }
+
/** Pokes the task persister. */
void notifyTaskPersisterLocked(TaskRecord task, boolean flush) {
mRecentTasks.notifyTaskPersisterLocked(task, flush);
}
- void onTopProcChangedLocked(ProcessRecord proc) {
+ void onTopProcChangedLocked(WindowProcessController proc) {
mVrController.onTopProcChangedLocked(proc);
}
@@ -3540,12 +3957,457 @@
mVrController.writeToProto(proto, fieldId);
}
+ int getCurrentUserId() {
+ return mAmInternal.getCurrentUserId();
+ }
+
+ private void enforceNotIsolatedCaller(String caller) {
+ if (UserHandle.isIsolated(Binder.getCallingUid())) {
+ throw new SecurityException("Isolated process not allowed to call " + caller);
+ }
+ }
+
+ /**
+ * Current global configuration information. Contains general settings for the entire system,
+ * also corresponds to the merged configuration of the default display.
+ */
+ Configuration getGlobalConfiguration() {
+ return mStackSupervisor.getConfiguration();
+ }
+
+ boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
+ boolean initLocale) {
+ return updateConfigurationLocked(values, starting, initLocale, false /* deferResume */);
+ }
+
+ boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
+ boolean initLocale, boolean deferResume) {
+ // pass UserHandle.USER_NULL as userId because we don't persist configuration for any user
+ return updateConfigurationLocked(values, starting, initLocale, false /* persistent */,
+ UserHandle.USER_NULL, deferResume);
+ }
+
+ void updatePersistentConfiguration(Configuration values, @UserIdInt int userId) {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ updateConfigurationLocked(values, null, false, true, userId,
+ false /* deferResume */);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ void updateUserConfiguration() {
+ synchronized (mGlobalLock) {
+ final Configuration configuration = new Configuration(getGlobalConfiguration());
+ final int currentUserId = mAmInternal.getCurrentUserId();
+ Settings.System.adjustConfigurationForUser(mContext.getContentResolver(), configuration,
+ currentUserId, Settings.System.canWrite(mContext));
+ updateConfigurationLocked(configuration, null /* starting */, false /* initLocale */,
+ false /* persistent */, currentUserId, false /* deferResume */);
+ }
+ }
+
+ private boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
+ boolean initLocale, boolean persistent, int userId, boolean deferResume) {
+ return updateConfigurationLocked(values, starting, initLocale, persistent, userId,
+ deferResume, null /* result */);
+ }
+
+ /**
+ * Do either or both things: (1) change the current configuration, and (2)
+ * make sure the given activity is running with the (now) current
+ * configuration. Returns true if the activity has been left running, or
+ * false if <var>starting</var> is being destroyed to match the new
+ * configuration.
+ *
+ * @param userId is only used when persistent parameter is set to true to persist configuration
+ * for that particular user
+ */
+ boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
+ boolean initLocale, boolean persistent, int userId, boolean deferResume,
+ ActivityTaskManagerService.UpdateConfigurationResult result) {
+ int changes = 0;
+ boolean kept = true;
+
+ if (mWindowManager != null) {
+ mWindowManager.deferSurfaceLayout();
+ }
+ try {
+ if (values != null) {
+ changes = updateGlobalConfigurationLocked(values, initLocale, persistent, userId,
+ deferResume);
+ }
+
+ kept = ensureConfigAndVisibilityAfterUpdate(starting, changes);
+ } finally {
+ if (mWindowManager != null) {
+ mWindowManager.continueSurfaceLayout();
+ }
+ }
+
+ if (result != null) {
+ result.changes = changes;
+ result.activityRelaunched = !kept;
+ }
+ return kept;
+ }
+
+ /**
+ * Returns true if this configuration change is interesting enough to send an
+ * {@link Intent#ACTION_SPLIT_CONFIGURATION_CHANGED} broadcast.
+ */
+ private static boolean isSplitConfigurationChange(int configDiff) {
+ return (configDiff & (ActivityInfo.CONFIG_LOCALE | ActivityInfo.CONFIG_DENSITY)) != 0;
+ }
+
+ /** Update default (global) configuration and notify listeners about changes. */
+ private int updateGlobalConfigurationLocked(@NonNull Configuration values, boolean initLocale,
+ boolean persistent, int userId, boolean deferResume) {
+ mTempConfig.setTo(getGlobalConfiguration());
+ final int changes = mTempConfig.updateFrom(values);
+ if (changes == 0) {
+ // Since calling to Activity.setRequestedOrientation leads to freezing the window with
+ // setting WindowManagerService.mWaitingForConfig to true, it is important that we call
+ // performDisplayOverrideConfigUpdate in order to send the new display configuration
+ // (even if there are no actual changes) to unfreeze the window.
+ performDisplayOverrideConfigUpdate(values, deferResume, DEFAULT_DISPLAY);
+ return 0;
+ }
+
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.i(TAG_CONFIGURATION,
+ "Updating global configuration to: " + values);
+
+ EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
+ StatsLog.write(StatsLog.RESOURCE_CONFIGURATION_CHANGED,
+ values.colorMode,
+ values.densityDpi,
+ values.fontScale,
+ values.hardKeyboardHidden,
+ values.keyboard,
+ values.keyboardHidden,
+ values.mcc,
+ values.mnc,
+ values.navigation,
+ values.navigationHidden,
+ values.orientation,
+ values.screenHeightDp,
+ values.screenLayout,
+ values.screenWidthDp,
+ values.smallestScreenWidthDp,
+ values.touchscreen,
+ values.uiMode);
+
+
+ if (!initLocale && !values.getLocales().isEmpty() && values.userSetLocale) {
+ final LocaleList locales = values.getLocales();
+ int bestLocaleIndex = 0;
+ if (locales.size() > 1) {
+ if (mSupportedSystemLocales == null) {
+ mSupportedSystemLocales = Resources.getSystem().getAssets().getLocales();
+ }
+ bestLocaleIndex = Math.max(0, locales.getFirstMatchIndex(mSupportedSystemLocales));
+ }
+ SystemProperties.set("persist.sys.locale",
+ locales.get(bestLocaleIndex).toLanguageTag());
+ LocaleList.setDefault(locales, bestLocaleIndex);
+ mAm.mHandler.sendMessage(mAm.mHandler.obtainMessage(SEND_LOCALE_TO_MOUNT_DAEMON_MSG,
+ locales.get(bestLocaleIndex)));
+ }
+
+ mConfigurationSeq = Math.max(++mConfigurationSeq, 1);
+ mTempConfig.seq = mConfigurationSeq;
+
+ // Update stored global config and notify everyone about the change.
+ mStackSupervisor.onConfigurationChanged(mTempConfig);
+
+ Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + mTempConfig);
+ // TODO(multi-display): Update UsageEvents#Event to include displayId.
+ mAm.mUsageStatsService.reportConfigurationChange(
+ mTempConfig, mAmInternal.getCurrentUserId());
+
+ // TODO: If our config changes, should we auto dismiss any currently showing dialogs?
+ mAm.updateShouldShowDialogsLocked(mTempConfig);
+
+ AttributeCache ac = AttributeCache.instance();
+ if (ac != null) {
+ ac.updateConfiguration(mTempConfig);
+ }
+
+ // Make sure all resources in our process are updated right now, so that anyone who is going
+ // to retrieve resource values after we return will be sure to get the new ones. This is
+ // especially important during boot, where the first config change needs to guarantee all
+ // resources have that config before following boot code is executed.
+ mAm.mSystemThread.applyConfigurationToResources(mTempConfig);
+
+ // We need another copy of global config because we're scheduling some calls instead of
+ // running them in place. We need to be sure that object we send will be handled unchanged.
+ final Configuration configCopy = new Configuration(mTempConfig);
+ if (persistent && Settings.System.hasInterestingConfigurationChanges(changes)) {
+ Message msg = mAm.mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
+ msg.obj = configCopy;
+ msg.arg1 = userId;
+ mAm.mHandler.sendMessage(msg);
+ }
+
+ for (int i = mAm.mLruProcesses.size() - 1; i >= 0; i--) {
+ ProcessRecord app = mAm.mLruProcesses.get(i);
+ try {
+ if (app.thread != null) {
+ if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Sending to proc "
+ + app.processName + " new config " + configCopy);
+ getLifecycleManager().scheduleTransaction(app.thread,
+ ConfigurationChangeItem.obtain(configCopy));
+ }
+ } catch (Exception e) {
+ Slog.e(TAG_CONFIGURATION, "Failed to schedule configuration change", e);
+ }
+ }
+
+ Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_REPLACE_PENDING
+ | Intent.FLAG_RECEIVER_FOREGROUND
+ | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
+ mAm.broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
+ OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
+ UserHandle.USER_ALL);
+ if ((changes & ActivityInfo.CONFIG_LOCALE) != 0) {
+ intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND
+ | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
+ | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
+ if (initLocale || !mAm.mProcessesReady) {
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ }
+ mAm.broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
+ OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
+ UserHandle.USER_ALL);
+ }
+
+ // Send a broadcast to PackageInstallers if the configuration change is interesting
+ // for the purposes of installing additional splits.
+ if (!initLocale && isSplitConfigurationChange(changes)) {
+ intent = new Intent(Intent.ACTION_SPLIT_CONFIGURATION_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
+ | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+
+ // Typically only app stores will have this permission.
+ String[] permissions = new String[] { android.Manifest.permission.INSTALL_PACKAGES };
+ mAm.broadcastIntentLocked(null, null, intent, null, null, 0, null, null, permissions,
+ OP_NONE, null, false, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
+ }
+
+ // Override configuration of the default display duplicates global config, so we need to
+ // update it also. This will also notify WindowManager about changes.
+ performDisplayOverrideConfigUpdate(mStackSupervisor.getConfiguration(), deferResume,
+ DEFAULT_DISPLAY);
+
+ return changes;
+ }
+
+ boolean updateDisplayOverrideConfigurationLocked(Configuration values, ActivityRecord starting,
+ boolean deferResume, int displayId) {
+ return updateDisplayOverrideConfigurationLocked(values, starting, deferResume /* deferResume */,
+ displayId, null /* result */);
+ }
+
+ /**
+ * Updates override configuration specific for the selected display. If no config is provided,
+ * new one will be computed in WM based on current display info.
+ */
+ boolean updateDisplayOverrideConfigurationLocked(Configuration values,
+ ActivityRecord starting, boolean deferResume, int displayId,
+ ActivityTaskManagerService.UpdateConfigurationResult result) {
+ int changes = 0;
+ boolean kept = true;
+
+ if (mWindowManager != null) {
+ mWindowManager.deferSurfaceLayout();
+ }
+ try {
+ if (values != null) {
+ if (displayId == DEFAULT_DISPLAY) {
+ // Override configuration of the default display duplicates global config, so
+ // we're calling global config update instead for default display. It will also
+ // apply the correct override config.
+ changes = updateGlobalConfigurationLocked(values, false /* initLocale */,
+ false /* persistent */, UserHandle.USER_NULL /* userId */, deferResume);
+ } else {
+ changes = performDisplayOverrideConfigUpdate(values, deferResume, displayId);
+ }
+ }
+
+ kept = ensureConfigAndVisibilityAfterUpdate(starting, changes);
+ } finally {
+ if (mWindowManager != null) {
+ mWindowManager.continueSurfaceLayout();
+ }
+ }
+
+ if (result != null) {
+ result.changes = changes;
+ result.activityRelaunched = !kept;
+ }
+ return kept;
+ }
+
+ private int performDisplayOverrideConfigUpdate(Configuration values, boolean deferResume,
+ int displayId) {
+ mTempConfig.setTo(mStackSupervisor.getDisplayOverrideConfiguration(displayId));
+ final int changes = mTempConfig.updateFrom(values);
+ if (changes != 0) {
+ Slog.i(TAG, "Override config changes=" + Integer.toHexString(changes) + " "
+ + mTempConfig + " for displayId=" + displayId);
+ mStackSupervisor.setDisplayOverrideConfiguration(mTempConfig, displayId);
+
+ final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0;
+ if (isDensityChange && displayId == DEFAULT_DISPLAY) {
+ mAm.mAppWarnings.onDensityChanged();
+
+ mAm.killAllBackgroundProcessesExcept(N,
+ ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
+ }
+ }
+
+ // Update the configuration with WM first and check if any of the stacks need to be resized
+ // due to the configuration change. If so, resize the stacks now and do any relaunches if
+ // necessary. This way we don't need to relaunch again afterwards in
+ // ensureActivityConfiguration().
+ if (mWindowManager != null) {
+ final int[] resizedStacks =
+ mWindowManager.setNewDisplayOverrideConfiguration(mTempConfig, displayId);
+ if (resizedStacks != null) {
+ for (int stackId : resizedStacks) {
+ resizeStackWithBoundsFromWindowManager(stackId, deferResume);
+ }
+ }
+ }
+
+ return changes;
+ }
+
+ /** Helper method that requests bounds from WM and applies them to stack. */
+ private void resizeStackWithBoundsFromWindowManager(int stackId, boolean deferResume) {
+ final Rect newStackBounds = new Rect();
+ final ActivityStack stack = mStackSupervisor.getStack(stackId);
+
+ // TODO(b/71548119): Revert CL introducing below once cause of mismatch is found.
+ if (stack == null) {
+ final StringWriter writer = new StringWriter();
+ final PrintWriter printWriter = new PrintWriter(writer);
+ mStackSupervisor.dumpDisplays(printWriter);
+ printWriter.flush();
+
+ Log.wtf(TAG, "stack not found:" + stackId + " displays:" + writer);
+ }
+
+ stack.getBoundsForNewConfiguration(newStackBounds);
+ mStackSupervisor.resizeStackLocked(
+ stack, !newStackBounds.isEmpty() ? newStackBounds : null /* bounds */,
+ null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
+ false /* preserveWindows */, false /* allowResizeInDockedMode */, deferResume);
+ }
+
+ /** Applies latest configuration and/or visibility updates if needed. */
+ private boolean ensureConfigAndVisibilityAfterUpdate(ActivityRecord starting, int changes) {
+ boolean kept = true;
+ final ActivityStack mainStack = mStackSupervisor.getFocusedStack();
+ // mainStack is null during startup.
+ if (mainStack != null) {
+ if (changes != 0 && starting == null) {
+ // If the configuration changed, and the caller is not already
+ // in the process of starting an activity, then find the top
+ // activity to check if its configuration needs to change.
+ starting = mainStack.topRunningActivityLocked();
+ }
+
+ if (starting != null) {
+ kept = starting.ensureActivityConfiguration(changes,
+ false /* preserveWindow */);
+ // And we need to make sure at this point that all other activities
+ // are made visible with the correct configuration.
+ mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes,
+ !PRESERVE_WINDOWS);
+ }
+ }
+
+ return kept;
+ }
+
+ void logAppTooSlow(WindowProcessController app, long startTime, String msg) {
+ if (true || Build.IS_USER) {
+ return;
+ }
+
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+ StrictMode.allowThreadDiskWrites();
+ try {
+ File tracesDir = new File("/data/anr");
+ File tracesFile = null;
+ try {
+ tracesFile = File.createTempFile("app_slow", null, tracesDir);
+
+ StringBuilder sb = new StringBuilder();
+ Time tobj = new Time();
+ tobj.set(System.currentTimeMillis());
+ sb.append(tobj.format("%Y-%m-%d %H:%M:%S"));
+ sb.append(": ");
+ TimeUtils.formatDuration(SystemClock.uptimeMillis()-startTime, sb);
+ sb.append(" since ");
+ sb.append(msg);
+ FileOutputStream fos = new FileOutputStream(tracesFile);
+ fos.write(sb.toString().getBytes());
+ if (app == null) {
+ fos.write("\n*** No application process!".getBytes());
+ }
+ fos.close();
+ FileUtils.setPermissions(tracesFile.getPath(), 0666, -1, -1); // -rw-rw-rw-
+ } catch (IOException e) {
+ Slog.w(TAG, "Unable to prepare slow app traces file: " + tracesFile, e);
+ return;
+ }
+
+ if (app != null && app.getPid() > 0) {
+ ArrayList<Integer> firstPids = new ArrayList<Integer>();
+ firstPids.add(app.getPid());
+ dumpStackTraces(tracesFile.getAbsolutePath(), firstPids, null, null);
+ }
+
+ File lastTracesFile = null;
+ File curTracesFile = null;
+ for (int i=9; i>=0; i--) {
+ String name = String.format(Locale.US, "slow%02d.txt", i);
+ curTracesFile = new File(tracesDir, name);
+ if (curTracesFile.exists()) {
+ if (lastTracesFile != null) {
+ curTracesFile.renameTo(lastTracesFile);
+ } else {
+ curTracesFile.delete();
+ }
+ }
+ lastTracesFile = curTracesFile;
+ }
+ tracesFile.renameTo(curTracesFile);
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
+ }
+ }
+
final class H extends Handler {
public H(Looper looper) {
super(looper, null, true);
}
}
+ final class UiHandler extends Handler {
+
+ public UiHandler() {
+ super(com.android.server.UiThread.get().getLooper(), null, true);
+ }
+ }
+
final class LocalService extends ActivityTaskManagerInternal {
@Override
public SleepToken acquireSleepToken(String tag, int displayId) {
@@ -3657,9 +4519,9 @@
// We might change the visibilities here, so prepare an empty app transition which
// might be overridden later if we actually change visibilities.
final boolean wasTransitionSet =
- mAm.mWindowManager.getPendingAppTransition() != TRANSIT_NONE;
+ mWindowManager.getPendingAppTransition() != TRANSIT_NONE;
if (!wasTransitionSet) {
- mAm.mWindowManager.prepareAppTransition(TRANSIT_NONE,
+ mWindowManager.prepareAppTransition(TRANSIT_NONE,
false /* alwaysKeepCurrent */);
}
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
@@ -3667,7 +4529,7 @@
// If there was a transition set already we don't want to interfere with it as we
// might be starting it too early.
if (!wasTransitionSet) {
- mAm.mWindowManager.executeAppTransition();
+ mWindowManager.executeAppTransition();
}
}
if (callback != null) {
@@ -3693,7 +4555,7 @@
public void setVr2dDisplayId(int vr2dDisplayId) {
if (DEBUG_STACK) Slog.d(TAG, "setVr2dDisplayId called for: " + vr2dDisplayId);
synchronized (mGlobalLock) {
- mAm.mVr2dDisplayId = vr2dDisplayId;
+ mVr2dDisplayId = vr2dDisplayId;
}
}
@@ -3713,28 +4575,8 @@
}
@Override
- public boolean hasRunningActivity(int uid, @Nullable String packageName) {
- if (packageName == null) return false;
-
- synchronized (mGlobalLock) {
- for (int i = 0; i < mAm.mLruProcesses.size(); i++) {
- final ProcessRecord processRecord = mAm.mLruProcesses.get(i);
- if (processRecord.uid == uid) {
- for (int j = 0; j < processRecord.activities.size(); j++) {
- final ActivityRecord activityRecord = processRecord.activities.get(j);
- if (packageName.equals(activityRecord.packageName)) {
- return true;
- }
- }
- }
- }
- }
- return false;
- }
-
- @Override
public void registerScreenObserver(ScreenObserver observer) {
- mAm.mScreenObservers.add(observer);
+ mScreenObservers.add(observer);
}
@Override
@@ -3754,7 +4596,7 @@
@Override
public void enforceCallerIsRecentsOrHasPermission(String permission, String func) {
- mAm.enforceCallerIsRecentsOrHasPermission(permission, func);
+ ActivityTaskManagerService.this.enforceCallerIsRecentsOrHasPermission(permission, func);
}
@Override
@@ -3763,5 +4605,69 @@
mActiveVoiceInteractionServiceComponent = component;
}
}
+
+ @Override
+ public void setAllowAppSwitches(@NonNull String type, int uid, int userId) {
+ if (!mAmInternal.isUserRunning(userId, ActivityManager.FLAG_OR_STOPPED)) {
+ return;
+ }
+ synchronized (mGlobalLock) {
+ ArrayMap<String, Integer> types = mAllowAppSwitchUids.get(userId);
+ if (types == null) {
+ if (uid < 0) {
+ return;
+ }
+ types = new ArrayMap<>();
+ mAllowAppSwitchUids.put(userId, types);
+ }
+ if (uid < 0) {
+ types.remove(type);
+ } else {
+ types.put(type, uid);
+ }
+ }
+ }
+
+ @Override
+ public void onUserStopped(int userId) {
+ synchronized (mGlobalLock) {
+ getRecentTasks().unloadUserDataFromMemoryLocked(userId);
+ mAllowAppSwitchUids.remove(userId);
+ }
+ }
+
+ @Override
+ public boolean isGetTasksAllowed(String caller, int callingPid, int callingUid) {
+ synchronized (mGlobalLock) {
+ return ActivityTaskManagerService.this.isGetTasksAllowed(
+ caller, callingPid, callingUid);
+ }
+ }
+
+ @Override
+ public void onProcessAdded(WindowProcessController proc) {
+ synchronized (mGlobalLock) {
+ mProcessNames.put(proc.mName, proc.mUid, proc);
+ }
+ }
+
+ @Override
+ public void onProcessRemoved(String name, int uid) {
+ synchronized (mGlobalLock) {
+ mProcessNames.remove(name, uid);
+ }
+ }
+
+ @Override
+ public void onCleanUpApplicationRecord(WindowProcessController proc) {
+ synchronized (mGlobalLock) {
+ if (proc == mHomeProcess) {
+ mHomeProcess = null;
+ }
+ if (proc == mPreviousProcess) {
+ mPreviousProcess = null;
+ }
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/am/AppErrorDialog.java b/services/core/java/com/android/server/am/AppErrorDialog.java
index 68c63a2..cde633d 100644
--- a/services/core/java/com/android/server/am/AppErrorDialog.java
+++ b/services/core/java/com/android/server/am/AppErrorDialog.java
@@ -92,7 +92,7 @@
attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR
| WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
getWindow().setAttributes(attrs);
- if (mProc.persistent) {
+ if (mProc.isPersistent()) {
getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
}
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index eac3501..7db98b3 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -25,7 +25,6 @@
import android.app.ActivityManager;
import android.app.ActivityOptions;
-import android.app.ActivityThread;
import android.app.AppOpsManager;
import android.app.ApplicationErrorReport;
import android.app.Dialog;
@@ -45,7 +44,6 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.EventLog;
-import android.util.Log;
import android.util.Slog;
import android.util.StatsLog;
import android.util.SparseArray;
@@ -57,7 +55,6 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.HashMap;
import java.util.Set;
import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
@@ -314,9 +311,9 @@
}
void killAppAtUserRequestLocked(ProcessRecord app, Dialog fromDialog) {
- app.crashing = false;
+ app.setCrashing(false);
app.crashingReport = null;
- app.notResponding = false;
+ app.setNotResponding(false);
app.notRespondingReport = null;
if (app.anrDialog == fromDialog) {
app.anrDialog = null;
@@ -409,7 +406,7 @@
// If a persistent app is stuck in a crash loop, the device isn't very
// usable, so we want to consider sending out a rescue party.
- if (r != null && r.persistent) {
+ if (r != null && r.isPersistent()) {
RescueParty.notePersistentAppCrash(mContext, r.uid);
}
@@ -493,8 +490,8 @@
long orig = Binder.clearCallingIdentity();
try {
// Kill it with fire!
- mService.mStackSupervisor.handleAppCrashLocked(r);
- if (!r.persistent) {
+ mService.mStackSupervisor.handleAppCrashLocked(r.getWindowProcessController());
+ if (!r.isPersistent()) {
mService.removeProcessLocked(r, false, false, "crash");
mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
@@ -532,7 +529,7 @@
String shortMsg, String longMsg,
String stackTrace, long timeMillis,
int callingPid, int callingUid) {
- if (mService.mController == null) {
+ if (mService.mActivityTaskManager.mController == null) {
return false;
}
@@ -540,7 +537,7 @@
String name = r != null ? r.processName : null;
int pid = r != null ? r.pid : callingPid;
int uid = r != null ? r.info.uid : callingUid;
- if (!mService.mController.appCrashed(name, pid,
+ if (!mService.mActivityTaskManager.mController.appCrashed(name, pid,
shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) {
if ("1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"))
&& "Native crash".equals(crashInfo.exceptionClassName)) {
@@ -563,7 +560,7 @@
return true;
}
} catch (RemoteException e) {
- mService.mController = null;
+ mService.mActivityTaskManager.mController = null;
Watchdog.getInstance().setActivityController(null);
}
return false;
@@ -571,11 +568,11 @@
private boolean makeAppCrashingLocked(ProcessRecord app,
String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {
- app.crashing = true;
+ app.setCrashing(true);
app.crashingReport = generateProcessError(app,
ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace);
startAppProblemLocked(app);
- app.stopFreezingAllLocked();
+ app.getWindowProcessController().stopFreezingActivities();
return handleAppCrashLocked(app, "force-crash" /*reason*/, shortMsg, longMsg, stackTrace,
data);
}
@@ -643,7 +640,7 @@
return null;
}
- if (!r.crashing && !r.notResponding && !r.forceCrashReport) {
+ if (!r.isCrashing() && !r.isNotResponding() && !r.forceCrashReport) {
return null;
}
@@ -654,10 +651,10 @@
report.time = timeMillis;
report.systemApp = (r.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
- if (r.crashing || r.forceCrashReport) {
+ if (r.isCrashing() || r.forceCrashReport) {
report.type = ApplicationErrorReport.TYPE_CRASH;
report.crashInfo = crashInfo;
- } else if (r.notResponding) {
+ } else if (r.isNotResponding()) {
report.type = ApplicationErrorReport.TYPE_ANR;
report.anrInfo = new ApplicationErrorReport.AnrInfo();
@@ -715,8 +712,8 @@
+ " has crashed too many times: killing!");
EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
app.userId, app.info.processName, app.uid);
- mService.mStackSupervisor.handleAppCrashLocked(app);
- if (!app.persistent) {
+ mService.mStackSupervisor.handleAppCrashLocked(app.getWindowProcessController());
+ if (!app.isPersistent()) {
// We don't want to start this process again until the user
// explicitly does so... but for persistent process, we really
// need to keep it running. If a persistent process is actually
@@ -744,7 +741,7 @@
mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
} else {
final TaskRecord affectedTask =
- mService.mStackSupervisor.finishTopCrashedActivitiesLocked(app, reason);
+ mService.mStackSupervisor.finishTopCrashedActivitiesLocked(app.getWindowProcessController(), reason);
if (data != null) {
data.task = affectedTask;
}
@@ -762,21 +759,11 @@
// replaced by a third-party app, clear the package preferred activities from packages
// with a home activity running in the process to prevent a repeatedly crashing app
// from blocking the user to manually clear the list.
- final ArrayList<ActivityRecord> activities = app.activities;
- if (app == mService.mHomeProcess && activities.size() > 0
- && (mService.mHomeProcess.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
- for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = activities.get(activityNdx);
- if (r.isActivityTypeHome()) {
- Log.i(TAG, "Clearing package preferred activities from " + r.packageName);
- try {
- ActivityThread.getPackageManager()
- .clearPackagePreferredActivities(r.packageName);
- } catch (RemoteException c) {
- // pm is in same process, this will never happen.
- }
- }
- }
+ final WindowProcessController proc = app.getWindowProcessController();
+ final WindowProcessController homeProc = mService.mActivityTaskManager.mHomeProcess;
+ if (proc == homeProc && proc.hasActivities()
+ && (homeProc.mInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+ proc.clearPackagePreferredForHomeActivities();
}
if (!app.isolated) {
@@ -887,16 +874,16 @@
ArrayList<Integer> firstPids = new ArrayList<Integer>(5);
SparseArray<Boolean> lastPids = new SparseArray<Boolean>(20);
- if (mService.mController != null) {
+ if (mService.mActivityTaskManager.mController != null) {
try {
// 0 == continue, -1 = kill process immediately
- int res = mService.mController.appEarlyNotResponding(
+ int res = mService.mActivityTaskManager.mController.appEarlyNotResponding(
app.processName, app.pid, annotation);
if (res < 0 && app.pid != MY_PID) {
app.kill("anr", true);
}
} catch (RemoteException e) {
- mService.mController = null;
+ mService.mActivityTaskManager.mController = null;
Watchdog.getInstance().setActivityController(null);
}
}
@@ -917,10 +904,10 @@
if (mService.mShuttingDown) {
Slog.i(TAG, "During shutdown skipping ANR: " + app + " " + annotation);
return;
- } else if (app.notResponding) {
+ } else if (app.isNotResponding()) {
Slog.i(TAG, "Skipping duplicate ANR: " + app + " " + annotation);
return;
- } else if (app.crashing) {
+ } else if (app.isCrashing()) {
Slog.i(TAG, "Crashing app skipping ANR: " + app + " " + annotation);
return;
} else if (app.killedByAm) {
@@ -933,7 +920,7 @@
// In case we come through here for the same app before completing
// this one, mark as anring now so we will bail out.
- app.notResponding = true;
+ app.setNotResponding(true);
// Log the ANR to the event log.
EventLog.writeEvent(EventLogTags.AM_ANR, app.userId, app.pid,
@@ -946,8 +933,8 @@
isSilentANR = !showBackground && !isInterestingForBackgroundTraces(app);
if (!isSilentANR) {
int parentPid = app.pid;
- if (parent != null && parent.app != null && parent.app.pid > 0) {
- parentPid = parent.app.pid;
+ if (parent != null && parent.app != null && parent.app.getPid() > 0) {
+ parentPid = parent.app.getPid();
}
if (parentPid != app.pid) firstPids.add(parentPid);
@@ -958,7 +945,7 @@
if (r != null && r.thread != null) {
int pid = r.pid;
if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) {
- if (r.persistent) {
+ if (r.isPersistent()) {
firstPids.add(pid);
if (DEBUG_ANR) Slog.i(TAG, "Adding persistent proc: " + r);
} else if (r.treatLikeActivity) {
@@ -1054,10 +1041,10 @@
mService.addErrorToDropBox("anr", app, app.processName, activity, parent, annotation,
cpuInfo, tracesFile, null);
- if (mService.mController != null) {
+ if (mService.mActivityTaskManager.mController != null) {
try {
// 0 == show dialog, 1 = keep waiting, -1 = kill process immediately
- int res = mService.mController.appNotResponding(
+ int res = mService.mActivityTaskManager.mController.appNotResponding(
app.processName, app.pid, info.toString());
if (res != 0) {
if (res < 0 && app.pid != MY_PID) {
@@ -1070,7 +1057,7 @@
return;
}
} catch (RemoteException e) {
- mService.mController = null;
+ mService.mActivityTaskManager.mController = null;
Watchdog.getInstance().setActivityController(null);
}
}
@@ -1100,12 +1087,12 @@
private void makeAppNotRespondingLocked(ProcessRecord app,
String activity, String shortMsg, String longMsg) {
- app.notResponding = true;
+ app.setNotResponding(true);
app.notRespondingReport = generateProcessError(app,
ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING,
activity, shortMsg, longMsg, null);
startAppProblemLocked(app);
- app.stopFreezingAllLocked();
+ app.getWindowProcessController().stopFreezingActivities();
}
void handleShowAnrUi(Message msg) {
diff --git a/services/core/java/com/android/server/am/AppNotRespondingDialog.java b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
index 8a88a69..7c983ff 100644
--- a/services/core/java/com/android/server/am/AppNotRespondingDialog.java
+++ b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
@@ -157,7 +157,7 @@
System.currentTimeMillis(), null);
}
- app.notResponding = false;
+ app.setNotResponding(false);
app.notRespondingReport = null;
if (app.anrDialog == AppNotRespondingDialog.this) {
app.anrDialog = null;
diff --git a/services/core/java/com/android/server/am/AppTaskImpl.java b/services/core/java/com/android/server/am/AppTaskImpl.java
index 953d3b8..c22dedc 100644
--- a/services/core/java/com/android/server/am/AppTaskImpl.java
+++ b/services/core/java/com/android/server/am/AppTaskImpl.java
@@ -20,7 +20,6 @@
import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
import android.app.ActivityManager;
-import android.app.ActivityOptions;
import android.app.IAppTask;
import android.app.IApplicationThread;
import android.content.Intent;
diff --git a/services/core/java/com/android/server/am/AssistDataRequester.java b/services/core/java/com/android/server/am/AssistDataRequester.java
index b54441a..395b0da 100644
--- a/services/core/java/com/android/server/am/AssistDataRequester.java
+++ b/services/core/java/com/android/server/am/AssistDataRequester.java
@@ -17,13 +17,12 @@
package com.android.server.am;
import static android.app.ActivityManager.ASSIST_CONTEXT_FULL;
-import static android.app.ActivityTaskManagerInternal.ASSIST_KEY_RECEIVER_EXTRAS;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.OP_NONE;
+import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_RECEIVER_EXTRAS;
import android.app.ActivityTaskManager;
import android.app.AppOpsManager;
-import android.app.IActivityManager;
import android.app.IAssistDataReceiver;
import android.content.Context;
import android.graphics.Bitmap;
@@ -49,7 +48,6 @@
public static final String KEY_RECEIVER_EXTRA_COUNT = "count";
public static final String KEY_RECEIVER_EXTRA_INDEX = "index";
- private IActivityManager mService;
private IWindowManager mWindowManager;
private Context mContext;
private AppOpsManager mAppOpsManager;
@@ -118,14 +116,13 @@
* This can be {@link AppOpsManager#OP_NONE} to indicate that
* screenshots should never be fetched.
*/
- public AssistDataRequester(Context context, IActivityManager service,
+ public AssistDataRequester(Context context,
IWindowManager windowManager, AppOpsManager appOpsManager,
AssistDataRequesterCallbacks callbacks, Object callbacksLock,
int requestStructureAppOps, int requestScreenshotAppOps) {
mCallbacks = callbacks;
mCallbacksLock = callbacksLock;
mWindowManager = windowManager;
- mService = service;
mContext = context;
mAppOpsManager = appOpsManager;
mRequestStructureAppOps = requestStructureAppOps;
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index c9a26cb..a9fd51d 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -304,7 +304,7 @@
app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
- app.repProcState);
+ app.getReportedProcState());
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Process cur broadcast " + r + " DELIVERED for app " + app);
started = true;
@@ -492,7 +492,7 @@
// correctly ordered with other one-way calls.
try {
app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
- data, extras, ordered, sticky, sendingUser, app.repProcState);
+ data, extras, ordered, sticky, sendingUser, app.getReportedProcState());
// TODO: Uncomment this when (b/28322359) is fixed and we aren't getting
// DeadObjectException when the process isn't actually dead.
//} catch (DeadObjectException ex) {
@@ -618,7 +618,7 @@
}
if (!skip && (filter.receiverList.app == null || filter.receiverList.app.killed
- || filter.receiverList.app.crashing)) {
+ || filter.receiverList.app.isCrashing())) {
Slog.w(TAG, "Skipping deliver [" + mQueueName + "] " + r
+ " to " + filter.receiverList + ": process gone or crashing");
skip = true;
@@ -885,7 +885,7 @@
synchronized (mService.mPidsSelfLocked) {
ProcessRecord proc = mService.mPidsSelfLocked.get(
mPendingBroadcast.curApp.pid);
- isDead = proc == null || proc.crashing;
+ isDead = proc == null || proc.isCrashing();
}
} else {
final ProcessRecord proc = mService.mProcessNames.get(
@@ -1210,7 +1210,7 @@
+ " (uid " + r.callingUid + ")");
skip = true;
}
- if (r.curApp != null && r.curApp.crashing) {
+ if (r.curApp != null && r.curApp.isCrashing()) {
// If the target process is crashing, just skip it.
Slog.w(TAG, "Skipping deliver ordered [" + mQueueName + "] " + r
+ " to " + r.curApp + ": process crashing");
diff --git a/services/core/java/com/android/server/am/CompatModePackages.java b/services/core/java/com/android/server/am/CompatModePackages.java
index c6947ab..38254b8 100644
--- a/services/core/java/com/android/server/am/CompatModePackages.java
+++ b/services/core/java/com/android/server/am/CompatModePackages.java
@@ -219,25 +219,10 @@
: ActivityManager.COMPAT_MODE_DISABLED;
}
- public boolean getFrontActivityAskCompatModeLocked() {
- ActivityRecord r = mService.getFocusedStack().topRunningActivityLocked();
- if (r == null) {
- return false;
- }
- return getPackageAskCompatModeLocked(r.packageName);
- }
-
public boolean getPackageAskCompatModeLocked(String packageName) {
return (getPackageFlags(packageName)&COMPAT_FLAG_DONT_ASK) == 0;
}
- public void setFrontActivityAskCompatModeLocked(boolean ask) {
- ActivityRecord r = mService.getFocusedStack().topRunningActivityLocked();
- if (r != null) {
- setPackageAskCompatModeLocked(r.packageName, ask);
- }
- }
-
public void setPackageAskCompatModeLocked(String packageName, boolean ask) {
setPackageFlagLocked(packageName, COMPAT_FLAG_DONT_ASK, ask);
}
@@ -255,23 +240,6 @@
}
}
- public int getFrontActivityScreenCompatModeLocked() {
- ActivityRecord r = mService.getFocusedStack().topRunningActivityLocked();
- if (r == null) {
- return ActivityManager.COMPAT_MODE_UNKNOWN;
- }
- return computeCompatModeLocked(r.info.applicationInfo);
- }
-
- public void setFrontActivityScreenCompatModeLocked(int mode) {
- ActivityRecord r = mService.getFocusedStack().topRunningActivityLocked();
- if (r == null) {
- Slog.w(TAG, "setFrontActivityScreenCompatMode failed: no top activity");
- return;
- }
- setPackageScreenCompatModeLocked(r.info.applicationInfo, mode);
- }
-
public int getPackageScreenCompatModeLocked(String packageName) {
ApplicationInfo ai = null;
try {
@@ -297,7 +265,7 @@
setPackageScreenCompatModeLocked(ai, mode);
}
- private void setPackageScreenCompatModeLocked(ApplicationInfo ai, int mode) {
+ void setPackageScreenCompatModeLocked(ApplicationInfo ai, int mode) {
final String packageName = ai.packageName;
int curFlags = getPackageFlags(packageName);
@@ -349,7 +317,7 @@
scheduleWrite();
- final ActivityStack stack = mService.getFocusedStack();
+ final ActivityStack stack = mService.mActivityTaskManager.getFocusedStack();
ActivityRecord starting = stack.restartPackage(packageName);
// Tell all processes that loaded this package about the change.
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index fb55a47..657e0eb 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -19,6 +19,13 @@
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
+import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
+import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
+import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
+import static android.view.WindowManager.TRANSIT_UNSET;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
@@ -27,15 +34,7 @@
import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.am.KeyguardControllerProto.KEYGUARD_OCCLUDED;
import static com.android.server.am.KeyguardControllerProto.KEYGUARD_SHOWING;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
-import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
-import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
-import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
-import static android.view.WindowManager.TRANSIT_UNSET;
-import android.app.ActivityTaskManagerInternal.SleepToken;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.Trace;
@@ -44,6 +43,7 @@
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.wm.ActivityTaskManagerInternal.SleepToken;
import com.android.server.wm.WindowManagerService;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/am/LaunchParamsController.java b/services/core/java/com/android/server/am/LaunchParamsController.java
index 4330d2c..6415c3e 100644
--- a/services/core/java/com/android/server/am/LaunchParamsController.java
+++ b/services/core/java/com/android/server/am/LaunchParamsController.java
@@ -38,7 +38,7 @@
* registered {@link LaunchParamsModifier}s.
*/
class LaunchParamsController {
- private final ActivityManagerService mService;
+ private final ActivityTaskManagerService mService;
private final List<LaunchParamsModifier> mModifiers = new ArrayList<>();
// Temporary {@link LaunchParams} for internal calculations. This is kept separate from
@@ -48,7 +48,7 @@
private final LaunchParams mTmpCurrent = new LaunchParams();
private final LaunchParams mTmpResult = new LaunchParams();
- LaunchParamsController(ActivityManagerService service) {
+ LaunchParamsController(ActivityTaskManagerService service) {
mService = service;
}
@@ -125,7 +125,7 @@
try {
if (mTmpParams.hasPreferredDisplay()
&& mTmpParams.mPreferredDisplayId != task.getStack().getDisplay().mDisplayId) {
- mService.mActivityTaskManager.moveStackToDisplay(task.getStackId(), mTmpParams.mPreferredDisplayId);
+ mService.moveStackToDisplay(task.getStackId(), mTmpParams.mPreferredDisplayId);
}
if (mTmpParams.hasWindowingMode()
diff --git a/services/core/java/com/android/server/am/NativeCrashListener.java b/services/core/java/com/android/server/am/NativeCrashListener.java
index 9348023..6e42aee 100644
--- a/services/core/java/com/android/server/am/NativeCrashListener.java
+++ b/services/core/java/com/android/server/am/NativeCrashListener.java
@@ -29,7 +29,6 @@
import java.io.File;
import java.io.FileDescriptor;
import java.io.InterruptedIOException;
-import java.net.InetSocketAddress;
/**
* Set up a Unix domain socket that debuggerd will connect() to in
@@ -226,7 +225,7 @@
}
if (pr != null) {
// Don't attempt crash reporting for persistent apps
- if (pr.persistent) {
+ if (pr.isPersistent()) {
if (DEBUG) {
Slog.v(TAG, "Skipping report for persistent app " + pr);
}
@@ -260,7 +259,7 @@
// even though the process will vanish as soon as we let
// debuggerd proceed.
synchronized (mAm) {
- pr.crashing = true;
+ pr.setCrashing(true);
pr.forceCrashReport = true;
}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index caf52e3..5a44ab6 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -54,7 +54,7 @@
* Full information about a particular process that
* is currently running.
*/
-final class ProcessRecord {
+final class ProcessRecord implements WindowProcessListener {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ProcessRecord" : TAG_AM;
private final ActivityManagerService mService; // where we came from
@@ -65,7 +65,37 @@
final int userId; // user of process.
final String processName; // name of the process
// List of packages running in the process
- final ArrayMap<String, ProcessStats.ProcessStateHolder> pkgList = new ArrayMap<>();
+ final PackageList pkgList = new PackageList();
+ final class PackageList {
+ final ArrayMap<String, ProcessStats.ProcessStateHolder> mPkgList = new ArrayMap<>();
+
+ ProcessStats.ProcessStateHolder put(String key, ProcessStats.ProcessStateHolder value) {
+ mWindowProcessController.addPackage(key);
+ return mPkgList.put(key, value);
+ }
+
+ void clear() {
+ mPkgList.clear();
+ mWindowProcessController.clearPackageList();
+ }
+
+ int size() {
+ return mPkgList.size();
+ }
+
+ String keyAt(int index) {
+ return mPkgList.keyAt(index);
+ }
+
+ public ProcessStats.ProcessStateHolder valueAt(int index) {
+ return mPkgList.valueAt(index);
+ }
+
+ boolean containsKey(Object key) {
+ return mPkgList.containsKey(key);
+ }
+ }
+
final ProcessList.ProcStateMemTracker procStateMemTracker
= new ProcessList.ProcStateMemTracker();
UidRecord uidRecord; // overall state of process's uid.
@@ -78,7 +108,7 @@
int pid; // The process of this application; 0 if none
String procStatFile; // path to /proc/<pid>/stat
int[] gids; // The gids this process was launched with
- String requiredAbi; // The ABI this process was launched with
+ private String mRequiredAbi;// The ABI this process was launched with
String instructionSet; // The instruction set this process was launched with
boolean starting; // True if the process is being started
long lastActivityTime; // For managing the LRU list
@@ -96,12 +126,11 @@
int curAdj; // Current OOM adjustment for this process
int setAdj; // Last set OOM adjustment for this process
int verifiedAdj; // The last adjustment that was verified as actually being set
- int curSchedGroup; // Currently desired scheduling class
+ private int mCurSchedGroup; // Currently desired scheduling class
int setSchedGroup; // Last set to background scheduling class
- int vrThreadTid; // Thread currently set for VR scheduling
int trimMemoryLevel; // Last selected memory trimming level
int curProcState = PROCESS_STATE_NONEXISTENT; // Currently computed process state
- int repProcState = PROCESS_STATE_NONEXISTENT; // Last reported process state
+ private int mRepProcState = PROCESS_STATE_NONEXISTENT; // Last reported process state
int setProcState = PROCESS_STATE_NONEXISTENT; // Last set process state in process tracker
int pssProcState = PROCESS_STATE_NONEXISTENT; // Currently requesting pss for
int pssStatType; // The type of stat collection that we are currently requesting
@@ -112,7 +141,7 @@
boolean notCachedSinceIdle; // Has this process not been in a cached state since last idle?
boolean hasClientActivities; // Are there any client services with activities?
boolean hasStartedServices; // Are there any started services running in this process?
- boolean foregroundServices; // Running any services that are foreground?
+ private boolean mHasForegroundServices; // Running any services that are foreground?
boolean foregroundActivities; // Running any activities that are foreground?
boolean repForegroundActivities; // Last reported foreground activities.
boolean systemNoUi; // This is a system process, but not currently showing UI.
@@ -173,10 +202,8 @@
Object adjTarget; // Debugging: target component impacting oom_adj.
Runnable crashHandler; // Optional local handler to be invoked in the process crash.
- // all activities running in the process
- final ArrayList<ActivityRecord> activities = new ArrayList<>();
- // any tasks this process had run root activities in
- final ArrayList<TaskRecord> recentTasks = new ArrayList<>();
+ // Controller for driving the process state on the window manager side.
+ final private WindowProcessController mWindowProcessController;
// all ServiceRecord running in this process
final ArraySet<ServiceRecord> services = new ArraySet<>();
// services that are currently executing code (need to remain foreground).
@@ -194,11 +221,11 @@
String[] isolatedEntryPointArgs; // Arguments to pass to isolatedEntryPoint's main().
boolean execServicesFg; // do we need to be executing services in the foreground?
- boolean persistent; // always keep this application running?
- boolean crashing; // are we in the process of crashing?
+ private boolean mPersistent;// always keep this application running?
+ private boolean mCrashing; // are we in the process of crashing?
Dialog crashDialog; // dialog being displayed due to crash.
boolean forceCrashReport; // suppress normal auto-dismiss of crash dialog & report UI?
- boolean notResponding; // does the app have a not responding dialog?
+ private boolean mNotResponding; // does the app have a not responding dialog?
Dialog anrDialog; // dialog being displayed due to app not resp.
boolean removed; // has app package been removed from device?
boolean debugging; // was app launched for debugging?
@@ -259,7 +286,7 @@
}
}
pw.println("}");
- pw.print(prefix); pw.print("requiredAbi="); pw.print(requiredAbi);
+ pw.print(prefix); pw.print("mRequiredAbi="); pw.print(mRequiredAbi);
pw.print(" instructionSet="); pw.println(instructionSet);
if (info.className != null) {
pw.print(prefix); pw.print("class="); pw.println(info.className);
@@ -324,15 +351,12 @@
pw.print(" setRaw="); pw.print(setRawAdj);
pw.print(" cur="); pw.print(curAdj);
pw.print(" set="); pw.println(setAdj);
- pw.print(prefix); pw.print("curSchedGroup="); pw.print(curSchedGroup);
+ pw.print(prefix); pw.print("mCurSchedGroup="); pw.print(mCurSchedGroup);
pw.print(" setSchedGroup="); pw.print(setSchedGroup);
pw.print(" systemNoUi="); pw.print(systemNoUi);
pw.print(" trimMemoryLevel="); pw.println(trimMemoryLevel);
- if (vrThreadTid != 0) {
- pw.print(prefix); pw.print("vrThreadTid="); pw.println(vrThreadTid);
- }
pw.print(prefix); pw.print("curProcState="); pw.print(curProcState);
- pw.print(" repProcState="); pw.print(repProcState);
+ pw.print(" mRepProcState="); pw.print(mRepProcState);
pw.print(" pssProcState="); pw.print(pssProcState);
pw.print(" setProcState="); pw.print(setProcState);
pw.print(" lastStateTime=");
@@ -349,8 +373,8 @@
pw.print(" hasOverlayUi="); pw.print(hasOverlayUi);
pw.print(" runningRemoteAnimation="); pw.println(runningRemoteAnimation);
}
- if (foregroundServices || forcingToImportant != null) {
- pw.print(prefix); pw.print("foregroundServices="); pw.print(foregroundServices);
+ if (mHasForegroundServices || forcingToImportant != null) {
+ pw.print(prefix); pw.print("mHasForegroundServices="); pw.print(mHasForegroundServices);
pw.print(" forcingToImportant="); pw.println(forcingToImportant);
}
if (reportedInteraction || fgInteractionTime != 0) {
@@ -366,8 +390,8 @@
}
pw.println();
}
- if (persistent || removed) {
- pw.print(prefix); pw.print("persistent="); pw.print(persistent);
+ if (mPersistent || removed) {
+ pw.print(prefix); pw.print("persistent="); pw.print(mPersistent);
pw.print(" removed="); pw.println(removed);
}
if (hasClientActivities || foregroundActivities || repForegroundActivities) {
@@ -407,16 +431,16 @@
pw.print(" killedByAm="); pw.print(killedByAm);
pw.print(" waitingToKill="); pw.println(waitingToKill);
}
- if (debugging || crashing || crashDialog != null || notResponding
+ if (debugging || mCrashing || crashDialog != null || mNotResponding
|| anrDialog != null || bad) {
pw.print(prefix); pw.print("debugging="); pw.print(debugging);
- pw.print(" crashing="); pw.print(crashing);
+ pw.print(" mCrashing="); pw.print(mCrashing);
pw.print(" "); pw.print(crashDialog);
- pw.print(" notResponding="); pw.print(notResponding);
+ pw.print(" mNotResponding="); pw.print(mNotResponding);
pw.print(" " ); pw.print(anrDialog);
pw.print(" bad="); pw.print(bad);
- // crashing or notResponding is always set before errorReportReceiver
+ // mCrashing or mNotResponding is always set before errorReportReceiver
if (errorReportReceiver != null) {
pw.print(" errorReportReceiver=");
pw.print(errorReportReceiver.flattenToShortString());
@@ -431,18 +455,7 @@
pw.print(prefix); pw.print("isolatedEntryPointArgs=");
pw.println(Arrays.toString(isolatedEntryPointArgs));
}
- if (activities.size() > 0) {
- pw.print(prefix); pw.println("Activities:");
- for (int i=0; i<activities.size(); i++) {
- pw.print(prefix); pw.print(" - "); pw.println(activities.get(i));
- }
- }
- if (recentTasks.size() > 0) {
- pw.print(prefix); pw.println("Recent Tasks:");
- for (int i=0; i<recentTasks.size(); i++) {
- pw.print(prefix); pw.print(" - "); pw.println(recentTasks.get(i));
- }
- }
+ mWindowProcessController.dump(pw, prefix);
if (services.size() > 0) {
pw.print(prefix); pw.println("Services:");
for (int i=0; i<services.size(); i++) {
@@ -498,17 +511,20 @@
uid = _uid;
userId = UserHandle.getUserId(_uid);
processName = _processName;
- pkgList.put(_info.packageName, new ProcessStats.ProcessStateHolder(_info.longVersionCode));
maxAdj = ProcessList.UNKNOWN_ADJ;
curRawAdj = setRawAdj = ProcessList.INVALID_ADJ;
curAdj = setAdj = verifiedAdj = ProcessList.INVALID_ADJ;
- persistent = false;
+ mPersistent = false;
removed = false;
lastStateTime = lastPssTime = nextPssTime = SystemClock.uptimeMillis();
+ mWindowProcessController = new WindowProcessController(
+ mService.mActivityTaskManager, info, processName, uid, userId, this, this);
+ pkgList.put(_info.packageName, new ProcessStats.ProcessStateHolder(_info.longVersionCode));
}
public void setPid(int _pid) {
pid = _pid;
+ mWindowProcessController.setPid(pid);
procStatFile = null;
shortStringName = null;
stringName = null;
@@ -519,7 +535,7 @@
final ProcessState origBase = baseProcessTracker;
if (origBase != null) {
origBase.setState(ProcessStats.STATE_NOTHING,
- tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList);
+ tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList.mPkgList);
origBase.makeInactive();
}
baseProcessTracker = tracker.getProcessStateLocked(info.packageName, uid,
@@ -538,15 +554,17 @@
}
}
thread = _thread;
+ mWindowProcessController.setThread(thread);
}
public void makeInactive(ProcessStatsService tracker) {
thread = null;
+ mWindowProcessController.setThread(null);
final ProcessState origBase = baseProcessTracker;
if (origBase != null) {
if (origBase != null) {
origBase.setState(ProcessStats.STATE_NOTHING,
- tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList);
+ tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList.mPkgList);
origBase.makeInactive();
}
baseProcessTracker = null;
@@ -560,11 +578,24 @@
}
}
- public void clearRecentTasks() {
- for (int i = recentTasks.size() - 1; i >= 0; i--) {
- recentTasks.get(i).clearRootProcess();
- }
- recentTasks.clear();
+ boolean hasActivities() {
+ return mWindowProcessController.hasActivities();
+ }
+
+ void clearActivities() {
+ mWindowProcessController.clearActivities();
+ }
+
+ boolean hasActivitiesOrRecentTasks() {
+ return mWindowProcessController.hasActivitiesOrRecentTasks();
+ }
+
+ boolean hasRecentTasks() {
+ return mWindowProcessController.hasRecentTasks();
+ }
+
+ void clearRecentTasks() {
+ mWindowProcessController.clearRecentTasks();
}
/**
@@ -572,12 +603,8 @@
* to the user. See HistoryRecord.isInterestingToUserLocked()
*/
public boolean isInterestingToUserLocked() {
- final int size = activities.size();
- for (int i = 0 ; i < size ; i++) {
- ActivityRecord r = activities.get(i);
- if (r.isInterestingToUserLocked()) {
- return true;
- }
+ if (mWindowProcessController.isInterestingToUser()) {
+ return true;
}
final int servicesSize = services.size();
@@ -590,14 +617,6 @@
return false;
}
- public void stopFreezingAllLocked() {
- int i = activities.size();
- while (i > 0) {
- i--;
- activities.get(i).stopFreezingScreenLocked(true);
- }
- }
-
public void unlinkDeathRecipient() {
if (deathRecipient != null && thread != null) {
thread.asBinder().unlinkToDeath(deathRecipient, 0);
@@ -676,7 +695,7 @@
} else {
pendingStart = false;
}
- if (!persistent) {
+ if (!mPersistent) {
killed = true;
killedByAm = true;
}
@@ -697,7 +716,7 @@
proto.write(ProcessRecordProto.ISOLATED_APP_ID, UserHandle.getAppId(uid));
}
}
- proto.write(ProcessRecordProto.PERSISTENT, persistent);
+ proto.write(ProcessRecordProto.PERSISTENT, mPersistent);
proto.end(token);
}
@@ -806,8 +825,8 @@
}
public void forceProcessStateUpTo(int newState) {
- if (repProcState > newState) {
- curProcState = repProcState = newState;
+ if (mRepProcState > newState) {
+ curProcState = mRepProcState = newState;
}
}
@@ -819,7 +838,7 @@
if (baseProcessTracker != null) {
long now = SystemClock.uptimeMillis();
baseProcessTracker.setState(ProcessStats.STATE_NOTHING,
- tracker.getMemFactorLocked(), now, pkgList);
+ tracker.getMemFactorLocked(), now, pkgList.mPkgList);
if (N != 1) {
for (int i=0; i<N; i++) {
ProcessStats.ProcessStateHolder holder = pkgList.valueAt(i);
@@ -856,4 +875,128 @@
}
return list;
}
+
+ WindowProcessController getWindowProcessController() {
+ return mWindowProcessController;
+ }
+
+ void setCurrentSchedulingGroup(int curSchedGroup) {
+ mCurSchedGroup = curSchedGroup;
+ mWindowProcessController.setCurrentSchedulingGroup(curSchedGroup);
+ }
+
+ int getCurrentSchedulingGroup() {
+ return mCurSchedGroup;
+ }
+
+ void setReportedProcState(int repProcState) {
+ mRepProcState = repProcState;
+ mWindowProcessController.setReportedProcState(repProcState);
+ }
+
+ int getReportedProcState() {
+ return mRepProcState;
+ }
+
+ void setCrashing(boolean crashing) {
+ mCrashing = crashing;
+ mWindowProcessController.setCrashing(crashing);
+ }
+
+ boolean isCrashing() {
+ return mCrashing;
+ }
+
+ void setNotResponding(boolean notResponding) {
+ mNotResponding = notResponding;
+ mWindowProcessController.setNotResponding(notResponding);
+ }
+
+ boolean isNotResponding() {
+ return mNotResponding;
+ }
+
+ void setPersistent(boolean persistent) {
+ mPersistent = persistent;
+ mWindowProcessController.setPersistent(persistent);
+ }
+
+ boolean isPersistent() {
+ return mPersistent;
+ }
+
+ public void setRequiredAbi(String requiredAbi) {
+ mRequiredAbi = requiredAbi;
+ mWindowProcessController.setRequiredAbi(requiredAbi);
+ }
+
+ String getRequiredAbi() {
+ return mRequiredAbi;
+ }
+
+ void setHasForegroundServices(boolean hasForegroundServices) {
+ mHasForegroundServices = hasForegroundServices;
+ mWindowProcessController.setHasForegroundServices(hasForegroundServices);
+ }
+
+ boolean hasForegroundServices() {
+ return mHasForegroundServices;
+ }
+
+ @Override
+ public void clearProfilerIfNeeded() {
+ synchronized (mService) {
+ if (mService.mProfileProc == null || mService.mProfilerInfo == null
+ || mService.mProfileProc != this) {
+ return;
+ }
+ mService.clearProfilerLocked();
+ }
+ }
+
+ @Override
+ public void updateServiceConnectionActivities() {
+ synchronized (mService) {
+ mService.mServices.updateServiceConnectionActivitiesLocked(this);
+ }
+ }
+
+ @Override
+ public void setPendingUiClean(boolean pendingUiClean) {
+ synchronized (mService) {
+ this.pendingUiClean = true;
+ }
+ }
+
+ @Override
+ public void setPendingUiCleanAndForceProcessStateUpTo(int newState) {
+ synchronized (mService) {
+ pendingUiClean = true;
+ forceProcessStateUpTo(newState);
+ }
+ }
+
+ @Override
+ public void updateProcessInfo(boolean updateServiceConnectionActivities, boolean updateLru,
+ boolean activityChange, boolean updateOomAdj) {
+ synchronized (mService) {
+ if (updateServiceConnectionActivities) {
+ mService.mServices.updateServiceConnectionActivitiesLocked(this);
+ }
+ if (updateLru) {
+ mService.updateLruProcessLocked(this, activityChange, null);
+ }
+ if (updateOomAdj) {
+ mService.updateOomAdjLocked();
+ }
+ }
+ }
+
+ @Override
+ public void setRemoved(boolean removed) {
+ synchronized (mService) {
+ this.removed = removed;
+ }
+ }
+
}
diff --git a/services/core/java/com/android/server/am/ProviderMap.java b/services/core/java/com/android/server/am/ProviderMap.java
index 2f52002..29c1657 100644
--- a/services/core/java/com/android/server/am/ProviderMap.java
+++ b/services/core/java/com/android/server/am/ProviderMap.java
@@ -32,7 +32,6 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
@@ -203,7 +202,7 @@
&& (filterByClasses == null
|| filterByClasses.contains(provider.name.getClassName())));
if (sameComponent
- && (provider.proc == null || evenPersistent || !provider.proc.persistent)) {
+ && (provider.proc == null || evenPersistent || !provider.proc.isPersistent())) {
if (!doit) {
return true;
}
diff --git a/services/core/java/com/android/server/am/RecentsAnimation.java b/services/core/java/com/android/server/am/RecentsAnimation.java
index bd49bd1..1c7ad3f 100644
--- a/services/core/java/com/android/server/am/RecentsAnimation.java
+++ b/services/core/java/com/android/server/am/RecentsAnimation.java
@@ -54,11 +54,10 @@
private static final String TAG = RecentsAnimation.class.getSimpleName();
private static final boolean DEBUG = false;
- private final ActivityManagerService mService;
+ private final ActivityTaskManagerService mService;
private final ActivityStackSupervisor mStackSupervisor;
private final ActivityStartController mActivityStartController;
private final WindowManagerService mWindowManager;
- private final UserController mUserController;
private final ActivityDisplay mDefaultDisplay;
private final int mCallingPid;
@@ -68,15 +67,14 @@
// The stack to restore the target stack behind when the animation is finished
private ActivityStack mRestoreTargetBehindStack;
- RecentsAnimation(ActivityManagerService am, ActivityStackSupervisor stackSupervisor,
+ RecentsAnimation(ActivityTaskManagerService atm, ActivityStackSupervisor stackSupervisor,
ActivityStartController activityStartController, WindowManagerService wm,
- UserController userController, int callingPid) {
- mService = am;
+ int callingPid) {
+ mService = atm;
mStackSupervisor = stackSupervisor;
mDefaultDisplay = stackSupervisor.getDefaultDisplay();
mActivityStartController = activityStartController;
mWindowManager = wm;
- mUserController = userController;
mCallingPid = callingPid;
}
@@ -122,7 +120,7 @@
mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching();
- mService.setRunningRemoteAnimation(mCallingPid, true);
+ mService.mAmInternal.setRunningRemoteAnimation(mCallingPid, true);
mWindowManager.deferSurfaceLayout();
try {
@@ -132,7 +130,7 @@
mService.mContext.getSystemService(Context.APP_OPS_SERVICE);
final AssistDataReceiverProxy proxy = new AssistDataReceiverProxy(
assistDataReceiver, recentsComponent.getPackageName());
- mAssistDataRequester = new AssistDataRequester(mService.mContext, mService,
+ mAssistDataRequester = new AssistDataRequester(mService.mContext,
mWindowManager, appOpsManager, proxy, this, OP_ASSIST_STRUCTURE, OP_NONE);
mAssistDataRequester.requestAssistData(mStackSupervisor.getTopVisibleActivities(),
true /* fetchData */, false /* fetchScreenshots */,
@@ -165,7 +163,7 @@
.setCallingUid(recentsUid)
.setCallingPackage(recentsComponent.getPackageName())
.setActivityOptions(SafeActivityOptions.fromBundle(options.toBundle()))
- .setMayWait(mUserController.getCurrentUserId())
+ .setMayWait(mService.getCurrentUserId())
.execute();
mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
mWindowManager.executeAppTransition();
@@ -210,7 +208,7 @@
}
private void finishAnimation(@RecentsAnimationController.ReorderMode int reorderMode) {
- synchronized (mService) {
+ synchronized (mService.mGlobalLock) {
if (DEBUG) Slog.d(TAG, "onAnimationFinished(): controller="
+ mWindowManager.getRecentsAnimationController()
+ " reorderMode=" + reorderMode);
@@ -232,7 +230,7 @@
mStackSupervisor.sendPowerHintForLaunchEndIfNeeded();
}
- mService.setRunningRemoteAnimation(mCallingPid, false);
+ mService.mAmInternal.setRunningRemoteAnimation(mCallingPid, false);
mWindowManager.inSurfaceTransaction(() -> {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER,
@@ -317,7 +315,7 @@
if (runSychronously) {
finishAnimation(reorderMode);
} else {
- mService.mHandler.post(() -> finishAnimation(reorderMode));
+ mService.mH.post(() -> finishAnimation(reorderMode));
}
}
diff --git a/services/core/java/com/android/server/am/SafeActivityOptions.java b/services/core/java/com/android/server/am/SafeActivityOptions.java
index 778990b..fef3b86 100644
--- a/services/core/java/com/android/server/am/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/am/SafeActivityOptions.java
@@ -117,7 +117,7 @@
* @param callerApp The record of the caller.
*/
ActivityOptions getOptions(@Nullable Intent intent, @Nullable ActivityInfo aInfo,
- @Nullable ProcessRecord callerApp,
+ @Nullable WindowProcessController callerApp,
ActivityStackSupervisor supervisor) throws SecurityException {
if (mOriginalOptions != null) {
checkPermissions(intent, aInfo, callerApp, supervisor, mOriginalOptions,
@@ -186,13 +186,13 @@
}
private void checkPermissions(@Nullable Intent intent, @Nullable ActivityInfo aInfo,
- @Nullable ProcessRecord callerApp, ActivityStackSupervisor supervisor,
+ @Nullable WindowProcessController callerApp, ActivityStackSupervisor supervisor,
ActivityOptions options, int callingPid, int callingUid) {
// If a launch task id is specified, then ensure that the caller is the recents
// component or has the START_TASKS_FROM_RECENTS permission
if (options.getLaunchTaskId() != INVALID_TASK_ID
&& !supervisor.mRecentTasks.isCallerRecents(callingUid)) {
- final int startInTaskPerm = supervisor.mService.mAm.checkPermission(
+ final int startInTaskPerm = ActivityTaskManagerService.checkPermission(
START_TASKS_FROM_RECENTS, callingPid, callingUid);
if (startInTaskPerm == PERMISSION_DENIED) {
final String msg = "Permission Denial: starting " + getIntentString(intent)
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index 465fa67..481bb2b 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -655,7 +655,7 @@
synchronized (mService.mGlobalLock) {
if (DEBUG) Slog.d(TAG, "mRecents=" + mRecentTasks);
mRecentTasks.getPersistableTaskIds(persistentTaskIds);
- mService.mAm.mWindowManager.removeObsoleteTaskFiles(persistentTaskIds,
+ mService.mWindowManager.removeObsoleteTaskFiles(persistentTaskIds,
mRecentTasks.usersWithRecentsLoadedLocked());
}
removeObsoleteFiles(persistentTaskIds);
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 6eac4bc..05869bb 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -264,7 +264,7 @@
/** The process that had previously hosted the root activity of this task.
* Used to know that we should try harder to keep this process around, in case the
* user wants to return to it. */
- private ProcessRecord mRootProcess;
+ private WindowProcessController mRootProcess;
/** Takes on same value as first root activity */
boolean isPersistable = false;
@@ -542,8 +542,14 @@
if (r != null && !deferResume) {
kept = r.ensureActivityConfiguration(0 /* globalChanges */,
preserveWindow);
+ // Preserve other windows for resizing because if resizing happens when there
+ // is a dialog activity in the front, the activity that still shows some
+ // content to the user will become black and cause flickers. Note in most cases
+ // this won't cause tons of irrelevant windows being preserved because only
+ // activities in this task may experience a bounds change. Configs for other
+ // activities stay the same.
mService.mStackSupervisor.ensureActivitiesVisibleLocked(r, 0,
- !PRESERVE_WINDOWS);
+ preserveWindow);
if (!kept) {
mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
@@ -1131,7 +1137,7 @@
// activity
reportOut.numRunning = 0;
}
- if (r.app != null && r.app.thread != null) {
+ if (r.attachedToProcess()) {
// Increment the number of actually running activities
reportOut.numRunning++;
}
@@ -1494,7 +1500,7 @@
}
private boolean isResizeable(boolean checkSupportsPip) {
- return (mService.mAm.mForceResizableActivities || ActivityInfo.isResizeableMode(mResizeMode)
+ return (mService.mForceResizableActivities || ActivityInfo.isResizeableMode(mResizeMode)
|| (checkSupportsPip && mSupportsPictureInPicture));
}
@@ -1507,8 +1513,8 @@
// A task can not be docked even if it is considered resizeable because it only supports
// picture-in-picture mode but has a non-resizeable resizeMode
return super.supportsSplitScreenWindowingMode()
- && mService.mAm.mSupportsSplitScreenMultiWindow
- && (mService.mAm.mForceResizableActivities
+ && mService.mSupportsSplitScreenMultiWindow
+ && (mService.mForceResizableActivities
|| (isResizeable(false /* checkSupportsPip */)
&& !ActivityInfo.isPreserveOrientationMode(mResizeMode)));
}
@@ -1841,7 +1847,9 @@
final int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density);
// We're only overriding LONG, SIZE and COMPAT parts of screenLayout, so we start override
// calculation with partial default.
- final int sl = Configuration.SCREENLAYOUT_LONG_YES | Configuration.SCREENLAYOUT_SIZE_XLARGE;
+ // Reducing the screen layout starting from its parent config.
+ final int sl = parentConfig.screenLayout &
+ (Configuration.SCREENLAYOUT_LONG_MASK | Configuration.SCREENLAYOUT_SIZE_MASK);
final int longSize = Math.max(compatScreenHeightDp, compatScreenWidthDp);
final int shortSize = Math.min(compatScreenHeightDp, compatScreenWidthDp);
config.screenLayout = Configuration.reduceScreenLayout(sl, longSize, shortSize);
@@ -1909,18 +1917,18 @@
}
}
- void setRootProcess(ProcessRecord proc) {
+ void setRootProcess(WindowProcessController proc) {
clearRootProcess();
if (intent != null &&
(intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0) {
mRootProcess = proc;
- proc.recentTasks.add(this);
+ mRootProcess.addRecentTask(this);
}
}
void clearRootProcess() {
if (mRootProcess != null) {
- mRootProcess.recentTasks.remove(this);
+ mRootProcess.removeRecentTask(this);
mRootProcess = null;
}
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index b500bbf..992179a 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -28,9 +28,9 @@
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.am.ActivityManagerService.ALLOW_FULL_ONLY;
-import static com.android.server.am.ActivityManagerService.ALLOW_NON_FULL;
-import static com.android.server.am.ActivityManagerService.ALLOW_NON_FULL_IN_PROFILE;
+import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
+import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
+import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
import static com.android.server.am.ActivityManagerService.MY_PID;
import static com.android.server.am.UserState.STATE_BOOTING;
import static com.android.server.am.UserState.STATE_RUNNING_LOCKED;
@@ -41,6 +41,7 @@
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
+import com.android.server.wm.ActivityTaskManagerInternal;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.Dialog;
@@ -80,7 +81,6 @@
import android.text.format.DateUtils;
import android.util.ArraySet;
import android.util.IntArray;
-import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
@@ -88,7 +88,6 @@
import android.util.TimingsTraceLog;
import android.util.proto.ProtoOutputStream;
-import android.view.Window;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -2097,9 +2096,7 @@
return mService.mWindowManager;
}
void activityManagerOnUserStopped(int userId) {
- synchronized (mService) {
- mService.onUserStoppedLocked(userId);
- }
+ LocalServices.getService(ActivityTaskManagerInternal.class).onUserStopped(userId);
}
void systemServiceManagerCleanupUser(int userId) {
@@ -2174,9 +2171,7 @@
}
void updateUserConfiguration() {
- synchronized (mService) {
- mService.updateUserConfigurationLocked();
- }
+ mService.mActivityTaskManager.updateUserConfiguration();
}
void clearBroadcastQueueForUser(int userId) {
diff --git a/services/core/java/com/android/server/am/VrController.java b/services/core/java/com/android/server/am/VrController.java
index 45410d7..366f95a 100644
--- a/services/core/java/com/android/server/am/VrController.java
+++ b/services/core/java/com/android/server/am/VrController.java
@@ -147,14 +147,15 @@
*
* <p>Note: This must be called with the global ActivityManagerService lock held.
*
- * @param proc is the ProcessRecord of the process that entered or left the TOP_APP scheduling
- * group.
+ * @param proc is the WindowProcessController of the process that entered or left the TOP_APP
+ * scheduling group.
*/
- public void onTopProcChangedLocked(ProcessRecord proc) {
- if (proc.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
- setVrRenderThreadLocked(proc.vrThreadTid, proc.curSchedGroup, true);
+ public void onTopProcChangedLocked(WindowProcessController proc) {
+ final int curSchedGroup = proc.getCurrentSchedulingGroup();
+ if (curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
+ setVrRenderThreadLocked(proc.mVrThreadTid, curSchedGroup, true);
} else {
- if (proc.vrThreadTid == mVrRenderThreadTid) {
+ if (proc.mVrThreadTid == mVrRenderThreadTid) {
clearVrRenderThreadLocked(true);
}
}
@@ -190,7 +191,7 @@
changed = changeVrModeLocked(vrMode, record.app);
if (record.app != null) {
- processId = record.app.pid;
+ processId = record.app.getPid();
}
}
@@ -213,9 +214,9 @@
*
* @param tid the tid of the thread to set, or 0 to unset the current thread.
* @param pid the pid of the process owning the thread to set.
- * @param proc the ProcessRecord of the process owning the thread to set.
+ * @param proc the WindowProcessController of the process owning the thread to set.
*/
- public void setVrThreadLocked(int tid, int pid, ProcessRecord proc) {
+ public void setVrThreadLocked(int tid, int pid, WindowProcessController proc) {
if (hasPersistentVrFlagSet()) {
Slog.w(TAG, "VR thread cannot be set in persistent VR mode!");
return;
@@ -230,9 +231,9 @@
if (!inVrMode()) {
Slog.w(TAG, "VR thread cannot be set when not in VR mode!");
} else {
- setVrRenderThreadLocked(tid, proc.curSchedGroup, false);
+ setVrRenderThreadLocked(tid, proc.getCurrentSchedulingGroup(), false);
}
- proc.vrThreadTid = (tid > 0) ? tid : 0;
+ proc.mVrThreadTid = (tid > 0) ? tid : 0;
}
/**
@@ -280,11 +281,11 @@
* <p>Note: This must be called with the global ActivityManagerService lock held.
*
* @param vrMode {@code true} if the system VR mode is being enabled.
- * @param proc the ProcessRecord of the process enabling the system VR mode.
+ * @param proc the WindowProcessController of the process enabling the system VR mode.
*
* @return {@code true} if our state changed.
*/
- private boolean changeVrModeLocked(boolean vrMode, ProcessRecord proc) {
+ private boolean changeVrModeLocked(boolean vrMode, WindowProcessController proc) {
final int oldVrState = mVrState;
// This is the only place where mVrState should have its FLAG_VR_MODE setting
@@ -299,8 +300,9 @@
if (changed) {
if (proc != null) {
- if (proc.vrThreadTid > 0) {
- setVrRenderThreadLocked(proc.vrThreadTid, proc.curSchedGroup, false);
+ if (proc.mVrThreadTid > 0) {
+ setVrRenderThreadLocked(
+ proc.mVrThreadTid, proc.getCurrentSchedulingGroup(), false);
}
} else {
clearVrRenderThreadLocked(false);
diff --git a/services/core/java/com/android/server/am/WindowProcessController.java b/services/core/java/com/android/server/am/WindowProcessController.java
new file mode 100644
index 0000000..64a273e
--- /dev/null
+++ b/services/core/java/com/android/server/am/WindowProcessController.java
@@ -0,0 +1,526 @@
+/*
+ * Copyright (C) 2018 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.am;
+
+import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RELEASE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RELEASE;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityStack.ActivityState.DESTROYED;
+import static com.android.server.am.ActivityStack.ActivityState.DESTROYING;
+import static com.android.server.am.ActivityStack.ActivityState.PAUSED;
+import static com.android.server.am.ActivityStack.ActivityState.PAUSING;
+import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
+import static com.android.server.am.ActivityStack.ActivityState.STOPPING;
+
+import android.app.Activity;
+import android.app.ActivityTaskManager;
+import android.app.ActivityThread;
+import android.app.IApplicationThread;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.os.RemoteException;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.internal.app.HeavyWeightSwitcherActivity;
+import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.internal.util.function.pooled.PooledRunnable;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * The Activity Manager (AM) package manages the lifecycle of processes in the system through
+ * {@link ProcessRecord}. However, it is important for the Window Manager (WM) package to be aware
+ * of the processes and their state since it affects how WM manages windows and activities. This
+ * class that allows the {@link ProcessRecord} object in the AM package to communicate important
+ * changes to its state to the WM package in a structured way. WM package also uses
+ * {@link WindowProcessListener} to request changes to the process state on the AM side.
+ * Note that public calls into this class are assumed to be originating from outside the
+ * window manager so the window manager lock is held and appropriate permissions are checked before
+ * calls are allowed to proceed.
+ */
+public class WindowProcessController {
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowProcessController" : TAG_AM;
+ private static final String TAG_RELEASE = TAG + POSTFIX_RELEASE;
+
+ // all about the first app in the process
+ final ApplicationInfo mInfo;
+ final String mName;
+ final int mUid;
+ // The process of this application; 0 if none
+ private volatile int mPid;
+ // user of process.
+ final int mUserId;
+ // The owner of this window process controller object. Mainly for identification when we
+ // communicate back to the activity manager side.
+ public final Object mOwner;
+ // List of packages running in the process
+ final ArraySet<String> mPkgList = new ArraySet<>();
+ private final WindowProcessListener mListener;
+ private final ActivityTaskManagerService mAtm;
+ // The actual proc... may be null only if 'persistent' is true (in which case we are in the
+ // process of launching the app)
+ private volatile IApplicationThread mThread;
+ // Currently desired scheduling class
+ private volatile int mCurSchedGroup;
+ // Last reported process state;
+ private volatile int mRepProcState = PROCESS_STATE_NONEXISTENT;
+ // are we in the process of crashing?
+ private volatile boolean mCrashing;
+ // does the app have a not responding dialog?
+ private volatile boolean mNotResponding;
+ // always keep this application running?
+ private volatile boolean mPersistent;
+ // The ABI this process was launched with
+ private volatile String mRequiredAbi;
+ // Running any services that are foreground?
+ private volatile boolean mHasForegroundServices;
+
+ // Thread currently set for VR scheduling
+ int mVrThreadTid;
+
+ // all activities running in the process
+ private final ArrayList<ActivityRecord> mActivities = new ArrayList<>();
+ // any tasks this process had run root activities in
+ private final ArrayList<TaskRecord> mRecentTasks = new ArrayList<>();
+
+ WindowProcessController(ActivityTaskManagerService atm, ApplicationInfo info, String name,
+ int uid, int userId, Object owner, WindowProcessListener listener) {
+ mInfo = info;
+ mName = name;
+ mUid = uid;
+ mUserId = userId;
+ mOwner = owner;
+ mListener = listener;
+ mAtm = atm;
+ }
+
+ public void setPid(int pid) {
+ mPid = pid;
+ }
+
+ int getPid() {
+ return mPid;
+ }
+
+ public void setThread(IApplicationThread thread) {
+ mThread = thread;
+ }
+
+ IApplicationThread getThread() {
+ return mThread;
+ }
+
+ boolean hasThread() {
+ return mThread != null;
+ }
+
+ public void setCurrentSchedulingGroup(int curSchedGroup) {
+ mCurSchedGroup = curSchedGroup;
+ }
+
+ int getCurrentSchedulingGroup() {
+ return mCurSchedGroup;
+ }
+
+ public void setReportedProcState(int repProcState) {
+ mRepProcState = repProcState;
+ }
+
+ int getReportedProcState() {
+ return mRepProcState;
+ }
+
+ public void setCrashing(boolean crashing) {
+ mCrashing = crashing;
+ }
+
+ boolean isCrashing() {
+ return mCrashing;
+ }
+
+ public void setNotResponding(boolean notResponding) {
+ mNotResponding = notResponding;
+ }
+
+ boolean isNotResponding() {
+ return mNotResponding;
+ }
+
+ public void setPersistent(boolean persistent) {
+ mPersistent = persistent;
+ }
+
+ boolean isPersistent() {
+ return mPersistent;
+ }
+
+ public void setHasForegroundServices(boolean hasForegroundServices) {
+ mHasForegroundServices = hasForegroundServices;
+ }
+
+ boolean hasForegroundServices() {
+ return mHasForegroundServices;
+ }
+
+ public void setRequiredAbi(String requiredAbi) {
+ mRequiredAbi = requiredAbi;
+ }
+
+ String getRequiredAbi() {
+ return mRequiredAbi;
+ }
+
+ public void addPackage(String packageName) {
+ synchronized (mAtm.mGlobalLock) {
+ mPkgList.add(packageName);
+ }
+ }
+
+ public void clearPackageList() {
+ synchronized (mAtm.mGlobalLock) {
+ mPkgList.clear();
+ }
+ }
+
+ void addActivityIfNeeded(ActivityRecord r) {
+ if (mActivities.contains(r)) {
+ return;
+ }
+ mActivities.add(r);
+ }
+
+ void removeActivity(ActivityRecord r) {
+ mActivities.remove(r);
+ }
+
+ public void clearActivities() {
+ synchronized (mAtm.mGlobalLock) {
+ mActivities.clear();
+ }
+ }
+
+ public boolean hasActivities() {
+ synchronized (mAtm.mGlobalLock) {
+ return !mActivities.isEmpty();
+ }
+ }
+
+ public boolean hasVisibleActivities() {
+ synchronized (mAtm.mGlobalLock) {
+ for (int i = mActivities.size() - 1; i >= 0; --i) {
+ final ActivityRecord r = mActivities.get(i);
+ if (r.visible) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public boolean hasActivitiesOrRecentTasks() {
+ synchronized (mAtm.mGlobalLock) {
+ return !mActivities.isEmpty() || !mRecentTasks.isEmpty();
+ }
+ }
+
+ public void stopFreezingActivities() {
+ synchronized (mAtm.mGlobalLock) {
+ int i = mActivities.size();
+ while (i > 0) {
+ i--;
+ mActivities.get(i).stopFreezingScreenLocked(true);
+ }
+ }
+ }
+
+ public void finishActivities() {
+ synchronized (mAtm.mGlobalLock) {
+ ArrayList<ActivityRecord> activities = new ArrayList<>(mActivities);
+ for (int i = 0; i < activities.size(); i++) {
+ final ActivityRecord r = activities.get(i);
+ if (!r.finishing && r.isInStackLocked()) {
+ r.getStack().finishActivityLocked(r, Activity.RESULT_CANCELED,
+ null, "finish-heavy", true);
+ }
+ }
+ }
+ }
+
+ public boolean isInterestingToUser() {
+ synchronized (mAtm.mGlobalLock) {
+ final int size = mActivities.size();
+ for (int i = 0; i < size; i++) {
+ ActivityRecord r = mActivities.get(i);
+ if (r.isInterestingToUserLocked()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public boolean hasRunningActivity(String packageName) {
+ synchronized (mAtm.mGlobalLock) {
+ for (int i = mActivities.size() - 1; i >= 0; --i) {
+ final ActivityRecord r = mActivities.get(i);
+ if (packageName.equals(r.packageName)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public void clearPackagePreferredForHomeActivities() {
+ synchronized (mAtm.mGlobalLock) {
+ for (int i = mActivities.size() - 1; i >= 0; --i) {
+ final ActivityRecord r = mActivities.get(i);
+ if (r.isActivityTypeHome()) {
+ Log.i(TAG, "Clearing package preferred activities from " + r.packageName);
+ try {
+ ActivityThread.getPackageManager()
+ .clearPackagePreferredActivities(r.packageName);
+ } catch (RemoteException c) {
+ // pm is in same process, this will never happen.
+ }
+ }
+ }
+ }
+ }
+
+ boolean hasStartedActivity(ActivityRecord launchedActivity) {
+ for (int i = mActivities.size() - 1; i >= 0; i--) {
+ final ActivityRecord activity = mActivities.get(i);
+ if (launchedActivity == activity) {
+ continue;
+ }
+ if (!activity.stopped) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ public void updateIntentForHeavyWeightActivity(Intent intent) {
+ synchronized (mAtm.mGlobalLock) {
+ if (mActivities.isEmpty()) {
+ return;
+ }
+ ActivityRecord hist = mActivities.get(0);
+ intent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP, hist.packageName);
+ intent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK, hist.getTask().taskId);
+ }
+ }
+
+ boolean shouldKillProcessForRemovedTask(TaskRecord tr) {
+ for (int k = 0; k < mActivities.size(); k++) {
+ final TaskRecord otherTask = mActivities.get(k).getTask();
+ if (tr.taskId != otherTask.taskId && otherTask.inRecents) {
+ // Don't kill process(es) that has an activity in a different task that is
+ // also in recents.
+ return false;
+ }
+ }
+ return true;
+ }
+
+ ArraySet<TaskRecord> getReleaseSomeActivitiesTasks() {
+ // Examine all activities currently running in the process.
+ TaskRecord firstTask = null;
+ // Tasks is non-null only if two or more tasks are found.
+ ArraySet<TaskRecord> tasks = null;
+ if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Trying to release some activities in " + this);
+ for (int i = 0; i < mActivities.size(); i++) {
+ final ActivityRecord r = mActivities.get(i);
+ // First, if we find an activity that is in the process of being destroyed,
+ // then we just aren't going to do anything for now; we want things to settle
+ // down before we try to prune more activities.
+ if (r.finishing || r.isState(DESTROYING, DESTROYED)) {
+ if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Abort release; already destroying: " + r);
+ return null;
+ }
+ // Don't consider any activies that are currently not in a state where they
+ // can be destroyed.
+ if (r.visible || !r.stopped || !r.haveState
+ || r.isState(RESUMED, PAUSING, PAUSED, STOPPING)) {
+ if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Not releasing in-use activity: " + r);
+ continue;
+ }
+
+ final TaskRecord task = r.getTask();
+ if (task != null) {
+ if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Collecting release task " + task
+ + " from " + r);
+ if (firstTask == null) {
+ firstTask = task;
+ } else if (firstTask != task) {
+ if (tasks == null) {
+ tasks = new ArraySet<>();
+ tasks.add(firstTask);
+ }
+ tasks.add(task);
+ }
+ }
+ }
+
+ return tasks;
+ }
+
+ public interface ComputeOomAdjCallback {
+ void onVisibleActivity();
+ void onPausedActivity();
+ void onStoppingActivity(boolean finishing);
+ void onOtherActivity();
+ }
+
+ public int computeOomAdjFromActivities(int minTaskLayer, ComputeOomAdjCallback callback) {
+ synchronized (mAtm.mGlobalLock) {
+ final int activitiesSize = mActivities.size();
+ for (int j = 0; j < activitiesSize; j++) {
+ final ActivityRecord r = mActivities.get(j);
+ if (r.app != this) {
+ Log.e(TAG, "Found activity " + r + " in proc activity list using " + r.app
+ + " instead of expected " + this);
+ if (r.app == null || (r.app.mUid == mUid)) {
+ // Only fix things up when they look sane
+ r.setProcess(this);
+ } else {
+ continue;
+ }
+ }
+ if (r.visible) {
+ callback.onVisibleActivity();
+ final TaskRecord task = r.getTask();
+ if (task != null && minTaskLayer > 0) {
+ final int layer = task.mLayerRank;
+ if (layer >= 0 && minTaskLayer > layer) {
+ minTaskLayer = layer;
+ }
+ }
+ break;
+ } else if (r.isState(PAUSING, PAUSED)) {
+ callback.onPausedActivity();
+ } else if (r.isState(STOPPING)) {
+ callback.onStoppingActivity(r.finishing);
+ } else {
+ callback.onOtherActivity();
+ }
+ }
+ }
+
+ return minTaskLayer;
+ }
+
+ void clearProfilerIfNeeded() {
+ if (mListener == null) return;
+ // Posting on handler so WM lock isn't held when we call into AM.
+ mAtm.mH.post(() -> mListener.clearProfilerIfNeeded());
+ }
+
+ void updateProcessInfo(boolean updateServiceConnectionActivities, boolean updateLru,
+ boolean activityChange, boolean updateOomAdj) {
+ if (mListener == null) return;
+ // Posting on handler so WM lock isn't held when we call into AM.
+ final Runnable r = PooledLambda.obtainRunnable(WindowProcessListener::updateProcessInfo,
+ mListener, updateServiceConnectionActivities, updateLru, activityChange,
+ updateOomAdj);
+ mAtm.mH.post(r);
+ }
+
+ void updateServiceConnectionActivities() {
+ if (mListener == null) return;
+ // Posting on handler so WM lock isn't held when we call into AM.
+ mAtm.mH.post(() -> mListener.updateServiceConnectionActivities());
+ }
+
+ void setPendingUiClean(boolean pendingUiClean) {
+ if (mListener == null) return;
+ // Posting on handler so WM lock isn't held when we call into AM.
+ final Runnable r = PooledLambda.obtainRunnable(
+ WindowProcessListener::setPendingUiClean, mListener, pendingUiClean);
+ mAtm.mH.post(r);
+ }
+
+ void setPendingUiCleanAndForceProcessStateUpTo(int newState) {
+ if (mListener == null) return;
+ // Posting on handler so WM lock isn't held when we call into AM.
+ final Runnable r = PooledLambda.obtainRunnable(
+ WindowProcessListener::setPendingUiCleanAndForceProcessStateUpTo,
+ mListener, newState);
+ mAtm.mH.post(r);
+ }
+
+ void setRemoved(boolean removed) {
+ if (mListener == null) return;
+ // Posting on handler so WM lock isn't held when we call into AM.
+ final Runnable r = PooledLambda.obtainRunnable(
+ WindowProcessListener::setRemoved, mListener, removed);
+ mAtm.mH.post(r);
+ }
+
+ void addRecentTask(TaskRecord task) {
+ mRecentTasks.add(task);
+ }
+
+ void removeRecentTask(TaskRecord task) {
+ mRecentTasks.remove(task);
+ }
+
+ public boolean hasRecentTasks() {
+ synchronized (mAtm.mGlobalLock) {
+ return !mRecentTasks.isEmpty();
+ }
+ }
+
+ public void clearRecentTasks() {
+ synchronized (mAtm.mGlobalLock) {
+ for (int i = mRecentTasks.size() - 1; i >= 0; i--) {
+ mRecentTasks.get(i).clearRootProcess();
+ }
+ mRecentTasks.clear();
+ }
+ }
+
+ public void dump(PrintWriter pw, String prefix) {
+ synchronized (mAtm.mGlobalLock) {
+ if (mActivities.size() > 0) {
+ pw.print(prefix); pw.println("Activities:");
+ for (int i = 0; i < mActivities.size(); i++) {
+ pw.print(prefix); pw.print(" - "); pw.println(mActivities.get(i));
+ }
+ }
+
+ if (mRecentTasks.size() > 0) {
+ pw.println(prefix + "Recent Tasks:");
+ for (int i = 0; i < mRecentTasks.size(); i++) {
+ pw.println(prefix + " - " + mRecentTasks.get(i));
+ }
+ }
+
+ if (mVrThreadTid != 0) {
+ pw.print(prefix); pw.print("mVrThreadTid="); pw.println(mVrThreadTid);
+ }
+ }
+ }
+
+}
diff --git a/services/core/java/com/android/server/am/WindowProcessListener.java b/services/core/java/com/android/server/am/WindowProcessListener.java
new file mode 100644
index 0000000..92e4461
--- /dev/null
+++ b/services/core/java/com/android/server/am/WindowProcessListener.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 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.am;
+
+/**
+ * Interface used by the owner/creator of a process that owns windows to listen to changes from the
+ * WM side.
+ * @see WindowProcessController
+ */
+public interface WindowProcessListener {
+
+ /** Clear the profiler record if we are currently profiling this process. */
+ void clearProfilerIfNeeded();
+
+ /** Update the service connection for this process based on activities it might have. */
+ void updateServiceConnectionActivities();
+
+ /** Set or clear flag that we would like to clean-up UI resources for this process. */
+ void setPendingUiClean(boolean pendingUiClean);
+
+ /**
+ * Set flag that we would like to clean-up UI resources for this process and force new process
+ * state.
+ */
+ void setPendingUiCleanAndForceProcessStateUpTo(int newState);
+
+ /** Update the process information. */
+ void updateProcessInfo(boolean updateServiceConnectionActivities, boolean updateLru,
+ boolean activityChange, boolean updateOomAdj);
+
+ /** Set process package been removed from device. */
+ void setRemoved(boolean removed);
+}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 571ee42..6971f71 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -20,8 +20,6 @@
import static android.media.AudioManager.RINGER_MODE_NORMAL;
import static android.media.AudioManager.RINGER_MODE_SILENT;
import static android.media.AudioManager.RINGER_MODE_VIBRATE;
-import static android.media.AudioManager.STREAM_ALARM;
-import static android.media.AudioManager.STREAM_MUSIC;
import static android.media.AudioManager.STREAM_SYSTEM;
import static android.os.Process.FIRST_APPLICATION_UID;
import static android.provider.Settings.Secure.VOLUME_HUSH_MUTE;
@@ -33,7 +31,6 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
-import android.app.ActivityTaskManagerInternal;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.IUidObserver;
@@ -142,6 +139,7 @@
import com.android.server.audio.AudioServiceEvents.VolumeEvent;
import com.android.server.audio.AudioServiceEvents.WiredDevConnectEvent;
import com.android.server.pm.UserManagerService;
+import com.android.server.wm.ActivityTaskManagerInternal;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/common/AuthenticationClient.java
similarity index 70%
rename from services/core/java/com/android/server/fingerprint/AuthenticationClient.java
rename to services/core/java/com/android/server/biometrics/common/AuthenticationClient.java
index afd1a94..6e5858a 100644
--- a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/common/AuthenticationClient.java
@@ -1,5 +1,5 @@
-/**
- * Copyright (C) 2016 The Android Open Source Project
+/*
+ * Copyright (C) 2018 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.
@@ -11,25 +11,23 @@
* 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.
+ * limitations under the License
*/
-package com.android.server.fingerprint;
+package com.android.server.biometrics.common;
import android.content.Context;
-import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.IBiometricPromptReceiver;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintManager;
-import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.IStatusBarService;
/**
@@ -51,6 +49,7 @@
private Bundle mBundle;
private IStatusBarService mStatusBarService;
private boolean mInLockout;
+ // TODO: BiometricManager, after other biometric modalities are introduced.
private final FingerprintManager mFingerprintManager;
protected boolean mDialogDismissed;
@@ -62,12 +61,12 @@
try {
mDialogReceiverFromClient.onDialogDismissed(reason);
if (reason == BiometricPrompt.DISMISSED_REASON_USER_CANCEL) {
- onError(FingerprintManager.FINGERPRINT_ERROR_USER_CANCELED,
+ onError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED,
0 /* vendorCode */);
}
mDialogDismissed = true;
} catch (RemoteException e) {
- Slog.e(TAG, "Unable to notify dialog dismissed", e);
+ Slog.e(getLogTag(), "Unable to notify dialog dismissed", e);
}
stop(true /* initiatedByClient */);
}
@@ -85,11 +84,13 @@
*/
public abstract void onStop();
- public AuthenticationClient(Context context, long halDeviceId, IBinder token,
- IFingerprintServiceReceiver receiver, int targetUserId, int groupId, long opId,
+ public AuthenticationClient(Context context, Metrics metrics,
+ BiometricService.DaemonWrapper daemon, long halDeviceId, IBinder token,
+ BiometricService.ServiceListener listener, int targetUserId, int groupId, long opId,
boolean restricted, String owner, Bundle bundle,
IBiometricPromptReceiver dialogReceiver, IStatusBarService statusBarService) {
- super(context, halDeviceId, token, receiver, targetUserId, groupId, restricted, owner);
+ super(context, metrics, daemon, halDeviceId, token, listener, targetUserId, groupId,
+ restricted, owner);
mOpId = opId;
mBundle = bundle;
mDialogReceiverFromClient = dialogReceiver;
@@ -112,17 +113,17 @@
// If the dialog is showing, the client doesn't need to receive onAcquired messages.
if (mBundle != null) {
try {
- if (acquiredInfo != FingerprintManager.FINGERPRINT_ACQUIRED_GOOD) {
+ if (acquiredInfo != BiometricConstants.BIOMETRIC_ACQUIRED_GOOD) {
mStatusBarService.onFingerprintHelp(
mFingerprintManager.getAcquiredString(acquiredInfo, vendorCode));
}
return false; // acquisition continues
} catch (RemoteException e) {
- Slog.e(TAG, "Remote exception when sending acquired message", e);
+ Slog.e(getLogTag(), "Remote exception when sending acquired message", e);
return true; // client failed
} finally {
// Good scans will keep the device awake
- if (acquiredInfo == FingerprintManager.FINGERPRINT_ACQUIRED_GOOD) {
+ if (acquiredInfo == BiometricConstants.BIOMETRIC_ACQUIRED_GOOD) {
notifyUserActivity();
}
}
@@ -132,7 +133,7 @@
}
@Override
- public boolean onError(int error, int vendorCode) {
+ public boolean onError(long deviceId, int error, int vendorCode) {
if (mDialogDismissed) {
// If user cancels authentication, the application has already received the
// FingerprintManager.FINGERPRINT_ERROR_USER_CANCELED message from onDialogDismissed()
@@ -145,10 +146,10 @@
mStatusBarService.onFingerprintError(
mFingerprintManager.getErrorString(error, vendorCode));
} catch (RemoteException e) {
- Slog.e(TAG, "Remote exception when sending error", e);
+ Slog.e(getLogTag(), "Remote exception when sending error", e);
}
}
- return super.onError(error, vendorCode);
+ return super.onError(deviceId, error, vendorCode);
}
@Override
@@ -166,36 +167,35 @@
com.android.internal.R.string.fingerprint_not_recognized));
}
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to notify Authenticated:", e);
+ Slog.e(getLogTag(), "Failed to notify Authenticated:", e);
}
}
- IFingerprintServiceReceiver receiver = getReceiver();
- if (receiver != null) {
+ final BiometricService.ServiceListener listener = getListener();
+ if (listener != null) {
try {
- MetricsLogger.action(getContext(), MetricsEvent.ACTION_FINGERPRINT_AUTH,
- authenticated);
+ mMetricsLogger.action(mMetrics.actionBiometricAuth(), authenticated);
if (!authenticated) {
- receiver.onAuthenticationFailed(getHalDeviceId());
+ listener.onAuthenticationFailed(getHalDeviceId());
} else {
if (DEBUG) {
- Slog.v(TAG, "onAuthenticated(owner=" + getOwnerString()
+ Slog.v(getLogTag(), "onAuthenticated(owner=" + getOwnerString()
+ ", id=" + fingerId + ", gp=" + groupId + ")");
}
Fingerprint fp = !getIsRestricted()
? new Fingerprint("" /* TODO */, groupId, fingerId, getHalDeviceId())
: null;
- receiver.onAuthenticationSucceeded(getHalDeviceId(), fp, getTargetUserId());
+ listener.onAuthenticationSucceeded(getHalDeviceId(), fp, getTargetUserId());
}
} catch (RemoteException e) {
- Slog.w(TAG, "Failed to notify Authenticated:", e);
+ Slog.w(getLogTag(), "Failed to notify Authenticated:", e);
result = true; // client failed
}
} else {
result = true; // client not listening
}
if (!authenticated) {
- if (receiver != null) {
+ if (listener != null) {
vibrateError();
}
// allow system-defined limit of number of attempts before giving up
@@ -203,17 +203,17 @@
if (lockoutMode != LOCKOUT_NONE) {
try {
mInLockout = true;
- Slog.w(TAG, "Forcing lockout (fp driver code should do this!), mode(" +
+ Slog.w(getLogTag(), "Forcing lockout (fp driver code should do this!), mode(" +
lockoutMode + ")");
stop(false);
int errorCode = lockoutMode == LOCKOUT_TIMED ?
- FingerprintManager.FINGERPRINT_ERROR_LOCKOUT :
- FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT;
+ BiometricConstants.BIOMETRIC_ERROR_LOCKOUT :
+ BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
// TODO: if the dialog is showing, this error should be delayed. On a similar
// note, AuthenticationClient should override onError and delay all other errors
// as well, if the dialog is showing
- receiver.onError(getHalDeviceId(), errorCode, 0 /* vendorCode */);
+ listener.onError(getHalDeviceId(), errorCode, 0 /* vendorCode */);
// Send the lockout message to the system dialog
if (mBundle != null) {
@@ -221,12 +221,12 @@
mFingerprintManager.getErrorString(errorCode, 0 /* vendorCode */));
}
} catch (RemoteException e) {
- Slog.w(TAG, "Failed to notify lockout:", e);
+ Slog.w(getLogTag(), "Failed to notify lockout:", e);
}
}
result |= lockoutMode != LOCKOUT_NONE; // in a lockout mode
} else {
- if (receiver != null) {
+ if (listener != null) {
vibrateSuccess();
}
result |= true; // we have a valid fingerprint, done
@@ -241,32 +241,28 @@
*/
@Override
public int start() {
- IBiometricsFingerprint daemon = getFingerprintDaemon();
- if (daemon == null) {
- Slog.w(TAG, "start authentication: no fingerprint HAL!");
- return ERROR_ESRCH;
- }
onStart();
try {
- final int result = daemon.authenticate(mOpId, getGroupId());
+ final int result = getDaemonWrapper().authenticate(mOpId, getGroupId());
if (result != 0) {
- Slog.w(TAG, "startAuthentication failed, result=" + result);
- MetricsLogger.histogram(getContext(), "fingeprintd_auth_start_error", result);
- onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
+ Slog.w(getLogTag(), "startAuthentication failed, result=" + result);
+ mMetricsLogger.histogram(mMetrics.tagAuthStartError(), result);
+ onError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */);
return result;
}
- if (DEBUG) Slog.w(TAG, "client " + getOwnerString() + " is authenticating...");
+ if (DEBUG) Slog.w(getLogTag(), "client " + getOwnerString() + " is authenticating...");
// If authenticating with system dialog, show the dialog
if (mBundle != null) {
try {
mStatusBarService.showFingerprintDialog(mBundle, mDialogReceiver);
} catch (RemoteException e) {
- Slog.e(TAG, "Unable to show fingerprint dialog", e);
+ Slog.e(getLogTag(), "Unable to show fingerprint dialog", e);
}
}
} catch (RemoteException e) {
- Slog.e(TAG, "startAuthentication failed", e);
+ Slog.e(getLogTag(), "startAuthentication failed", e);
return ERROR_ESRCH;
}
return 0; // success
@@ -275,25 +271,21 @@
@Override
public int stop(boolean initiatedByClient) {
if (mAlreadyCancelled) {
- Slog.w(TAG, "stopAuthentication: already cancelled!");
+ Slog.w(getLogTag(), "stopAuthentication: already cancelled!");
return 0;
}
onStop();
- IBiometricsFingerprint daemon = getFingerprintDaemon();
- if (daemon == null) {
- Slog.w(TAG, "stopAuthentication: no fingerprint HAL!");
- return ERROR_ESRCH;
- }
+
try {
- final int result = daemon.cancel();
+ final int result = getDaemonWrapper().cancel();
if (result != 0) {
- Slog.w(TAG, "stopAuthentication failed, result=" + result);
+ Slog.w(getLogTag(), "stopAuthentication failed, result=" + result);
return result;
}
- if (DEBUG) Slog.w(TAG, "client " + getOwnerString() + " is no longer authenticating");
+ if (DEBUG) Slog.w(getLogTag(), "client " + getOwnerString() + " is no longer authenticating");
} catch (RemoteException e) {
- Slog.e(TAG, "stopAuthentication failed", e);
+ Slog.e(getLogTag(), "stopAuthentication failed", e);
return ERROR_ESRCH;
} finally {
// If the user already cancelled authentication (via some interaction with the
@@ -304,29 +296,32 @@
try {
mStatusBarService.hideFingerprintDialog();
} catch (RemoteException e) {
- Slog.e(TAG, "Unable to hide fingerprint dialog", e);
+ Slog.e(getLogTag(), "Unable to hide fingerprint dialog", e);
}
}
}
+
mAlreadyCancelled = true;
return 0; // success
}
@Override
- public boolean onEnrollResult(int fingerId, int groupId, int remaining) {
- if (DEBUG) Slog.w(TAG, "onEnrollResult() called for authenticate!");
+ public boolean onEnrollResult(BiometricAuthenticator.Identifier identifier,
+ int remaining) {
+ if (DEBUG) Slog.w(getLogTag(), "onEnrollResult() called for authenticate!");
return true; // Invalid for Authenticate
}
@Override
- public boolean onRemoved(int fingerId, int groupId, int remaining) {
- if (DEBUG) Slog.w(TAG, "onRemoved() called for authenticate!");
+ public boolean onRemoved(BiometricAuthenticator.Identifier identifier, int remaining) {
+ if (DEBUG) Slog.w(getLogTag(), "onRemoved() called for authenticate!");
return true; // Invalid for Authenticate
}
@Override
- public boolean onEnumerationResult(int fingerId, int groupId, int remaining) {
- if (DEBUG) Slog.w(TAG, "onEnumerationResult() called for authenticate!");
+ public boolean onEnumerationResult(BiometricAuthenticator.Identifier identifier,
+ int remaining) {
+ if (DEBUG) Slog.w(getLogTag(), "onEnumerationResult() called for authenticate!");
return true; // Invalid for Authenticate
}
}
diff --git a/services/core/java/com/android/server/biometrics/common/BiometricService.java b/services/core/java/com/android/server/biometrics/common/BiometricService.java
new file mode 100644
index 0000000..41b1575
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/common/BiometricService.java
@@ -0,0 +1,1099 @@
+/*
+ * Copyright (C) 2018 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.common;
+
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
+
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.app.AlarmManager;
+import android.app.AppOpsManager;
+import android.app.IActivityTaskManager;
+import android.app.PendingIntent;
+import android.app.SynchronousUserSwitchObserver;
+import android.app.TaskStackListener;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.IBiometricPromptReceiver;
+import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
+import android.hardware.fingerprint.Fingerprint;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.DeadObjectException;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IHwBinder;
+import android.os.IRemoteCallback;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.security.KeyStore;
+import android.util.Slog;
+import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.server.SystemService;
+import com.android.server.biometrics.face.FaceService;
+import com.android.server.biometrics.fingerprint.FingerprintService;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Abstract base class containing all of the business logic for biometric services, e.g.
+ * Fingerprint, Face, Iris.
+ *
+ * @hide
+ */
+public abstract class BiometricService extends SystemService implements IHwBinder.DeathRecipient {
+
+ protected static final boolean DEBUG = true;
+
+ private static final String KEY_LOCKOUT_RESET_USER = "lockout_reset_user";
+ private static final int MSG_USER_SWITCHING = 10;
+ private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30 * 1000;
+ private static final long CANCEL_TIMEOUT_LIMIT = 3000; // max wait for onCancel() from HAL,in ms
+
+ private final Context mContext;
+ private final String mKeyguardPackage;
+ private final AppOpsManager mAppOps;
+ private final SparseBooleanArray mTimedLockoutCleared;
+ private final SparseIntArray mFailedAttempts;
+ private final IActivityTaskManager mActivityTaskManager;
+ private final AlarmManager mAlarmManager;
+ private final PowerManager mPowerManager;
+ private final UserManager mUserManager;
+ private final MetricsLogger mMetricsLogger;
+ private final BiometricTaskStackListener mTaskStackListener = new BiometricTaskStackListener();
+ private final ResetClientStateRunnable mResetClientState = new ResetClientStateRunnable();
+ private final LockoutReceiver mLockoutReceiver = new LockoutReceiver();
+ private final ArrayList<LockoutResetMonitor> mLockoutMonitors = new ArrayList<>();
+
+ protected final Map<Integer, Long> mAuthenticatorIds =
+ Collections.synchronizedMap(new HashMap<>());
+ protected final ResetFailedAttemptsForUserRunnable mResetFailedAttemptsForCurrentUserRunnable =
+ new ResetFailedAttemptsForUserRunnable();
+ protected final H mHandler = new H();
+
+ private ClientMonitor mCurrentClient;
+ private ClientMonitor mPendingClient;
+ private PerformanceStats mPerformanceStats;
+ protected int mCurrentUserId = UserHandle.USER_NULL;
+ // Normal authentications are tracked by mPerformanceMap.
+ protected HashMap<Integer, PerformanceStats> mPerformanceMap = new HashMap<>();
+ // Transactions that make use of CryptoObjects are tracked by mCryptoPerformaceMap.
+ protected HashMap<Integer, PerformanceStats> mCryptoPerformanceMap = new HashMap<>();
+
+ protected class PerformanceStats {
+ public int accept; // number of accepted biometrics
+ public int reject; // number of rejected biometrics
+ public int acquire; // total number of acquisitions. Should be >= accept+reject due to poor
+ // image acquisition in some cases (too fast, too slow, dirty sensor, etc.)
+ public int lockout; // total number of lockouts
+ public int permanentLockout; // total number of permanent lockouts
+ }
+
+ /**
+ * @return the log tag.
+ */
+ protected abstract String getTag();
+
+ /**
+ * @return the biometric utilities for a specific implementation.
+ */
+ protected abstract BiometricUtils getBiometricUtils();
+
+ /**
+ * @return the number of failed attempts after which the user will be temporarily locked out
+ * from using the biometric. A strong auth (pin/pattern/pass) clears this counter.
+ */
+ protected abstract int getFailedAttemptsLockoutTimed();
+
+ /**
+ * @return the number of failed attempts after which the user will be permanently locked out
+ * from using the biometric. A strong auth (pin/pattern/pass) clears this counter.
+ */
+ protected abstract int getFailedAttemptsLockoutPermanent();
+
+ /**
+ * @return the metrics constants for a biometric implementation.
+ */
+ protected abstract Metrics getMetrics();
+
+ /**
+ * @param userId
+ * @return true if the enrollment limit has been reached.
+ */
+ protected abstract boolean hasReachedEnrollmentLimit(int userId);
+
+ /**
+ * Notifies the HAL that the user has changed.
+ * @param userId
+ * @param clientPackage
+ */
+ protected abstract void updateActiveGroup(int userId, String clientPackage);
+
+ /**
+ * @return The protected intent to reset lockout for a specific biometric.
+ */
+ protected abstract String getLockoutResetIntent();
+
+ /**
+ * @return The permission the sender is required to have in order for the lockout reset intent
+ * to be received by the BiometricService implementation.
+ */
+ protected abstract String getLockoutBroadcastPermission();
+
+ /**
+ * @return The HAL ID.
+ */
+ protected abstract long getHalDeviceId();
+
+ /**
+ * This method is called when the user switches. Implementations should probably notify the
+ * HAL.
+ * @param userId
+ */
+ protected abstract void handleUserSwitching(int userId);
+
+ /**
+ * @param userId
+ * @return Returns true if the user has any enrolled biometrics.
+ */
+ protected abstract boolean hasEnrolledBiometrics(int userId);
+
+ /**
+ * @return Returns the MANAGE_* permission string, which is required for enrollment, removal
+ * etc.
+ */
+ protected abstract String getManageBiometricPermission();
+
+ /**
+ * Checks if the caller has permission to use the biometric service - throws a SecurityException
+ * if not.
+ */
+ protected abstract void checkUseBiometricPermission();
+
+ /**
+ * @return Returns one of the {@link AppOpsManager} constants which pertains to the specific
+ * biometric service.
+ */
+ protected abstract int getAppOp();
+
+
+ /**
+ * Notifies clients of any change in the biometric state (active / idle). This is mainly for
+ * Fingerprint navigation gestures.
+ * @param isActive
+ */
+ protected void notifyClientActiveCallbacks(boolean isActive) {}
+
+ protected class AuthenticationClientImpl extends AuthenticationClient {
+
+ public AuthenticationClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
+ IBinder token, ServiceListener listener, int targetUserId, int groupId, long opId,
+ boolean restricted, String owner, Bundle bundle,
+ IBiometricPromptReceiver dialogReceiver,
+ IStatusBarService statusBarService) {
+ super(context, getMetrics(), daemon, halDeviceId, token, listener,
+ targetUserId, groupId, opId, restricted, owner, bundle, dialogReceiver,
+ statusBarService);
+ }
+
+ @Override
+ public void onStart() {
+ try {
+ mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Could not register task stack listener", e);
+ }
+ }
+
+ @Override
+ public void onStop() {
+ try {
+ mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Could not unregister task stack listener", e);
+ }
+ }
+
+ @Override
+ public void resetFailedAttempts() {
+ resetFailedAttemptsForUser(true /* clearAttemptCounter */,
+ ActivityManager.getCurrentUser());
+ }
+
+ @Override
+ public void notifyUserActivity() {
+ userActivity();
+ }
+
+ @Override
+ public int handleFailedAttempt() {
+ final int currentUser = ActivityManager.getCurrentUser();
+ mFailedAttempts.put(currentUser, mFailedAttempts.get(currentUser, 0) + 1);
+ mTimedLockoutCleared.put(ActivityManager.getCurrentUser(), false);
+ final int lockoutMode = getLockoutMode();
+ if (lockoutMode == AuthenticationClient.LOCKOUT_PERMANENT) {
+ mPerformanceStats.permanentLockout++;
+ } else if (lockoutMode == AuthenticationClient.LOCKOUT_TIMED) {
+ mPerformanceStats.lockout++;
+ }
+
+ // Failing multiple times will continue to push out the lockout time
+ if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
+ scheduleLockoutResetForUser(currentUser);
+ return lockoutMode;
+ }
+ return AuthenticationClient.LOCKOUT_NONE;
+ }
+ }
+
+ protected class EnrollClientImpl extends EnrollClient {
+
+ public EnrollClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
+ IBinder token, ServiceListener listener, int userId, int groupId,
+ byte[] cryptoToken, boolean restricted, String owner) {
+ super(context, getMetrics(), daemon, halDeviceId, token, listener,
+ userId, groupId, cryptoToken, restricted, owner, getBiometricUtils());
+ }
+
+ @Override
+ public void notifyUserActivity() {
+ userActivity();
+ }
+ }
+
+ protected class RemovalClientImpl extends RemovalClient {
+ private boolean mShouldNotify;
+
+ public RemovalClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
+ IBinder token, ServiceListener listener, int fingerId, int groupId, int userId,
+ boolean restricted, String owner) {
+ super(context, getMetrics(), daemon, halDeviceId, token, listener, fingerId, groupId,
+ userId, restricted, owner, getBiometricUtils());
+ }
+
+ public void setShouldNotifyUserActivity(boolean shouldNotify) {
+ mShouldNotify = shouldNotify;
+ }
+
+ @Override
+ public void notifyUserActivity() {
+ if (mShouldNotify) {
+ userActivity();
+ }
+ }
+ }
+
+ protected class EnumerateClientImpl extends EnumerateClient {
+
+ public EnumerateClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
+ IBinder token, ServiceListener listener, int groupId, int userId,
+ boolean restricted, String owner) {
+ super(context, getMetrics(), daemon, halDeviceId, token, listener, groupId, userId,
+ restricted, owner);
+ }
+
+ @Override
+ public void notifyUserActivity() {
+ userActivity();
+ }
+ }
+
+ /**
+ * Wraps the callback interface from Service -> Manager
+ */
+ protected interface ServiceListener {
+ void onEnrollResult(BiometricAuthenticator.Identifier identifier,
+ int remaining) throws RemoteException;
+
+ void onAcquired(long deviceId, int acquiredInfo, int vendorCode)
+ throws RemoteException;
+
+ void onAuthenticationSucceeded(long deviceId,
+ BiometricAuthenticator.Identifier biometric, int userId)
+ throws RemoteException;
+
+ void onAuthenticationFailed(long deviceId)
+ throws RemoteException;
+
+ void onError(long deviceId, int error, int vendorCode)
+ throws RemoteException;
+
+ void onRemoved(BiometricAuthenticator.Identifier identifier,
+ int remaining) throws RemoteException;
+
+ void onEnumerated(BiometricAuthenticator.Identifier identifier,
+ int remaining) throws RemoteException;
+ }
+
+ /**
+ * Wraps a portion of the interface from Service -> Daemon that is used by the ClientMonitor
+ * subclasses.
+ */
+ protected interface DaemonWrapper {
+ int ERROR_ESRCH = 3; // Likely fingerprint HAL is dead. see errno.h.
+ int authenticate(long operationId, int groupId) throws RemoteException;
+ int cancel() throws RemoteException;
+ int remove(int groupId, int biometricId) throws RemoteException;
+ int enumerate() throws RemoteException;
+ int enroll(byte[] cryptoToken, int groupId, int timeout) throws RemoteException;
+ }
+
+ /**
+ * Handler which all subclasses should post events to.
+ */
+ protected final class H extends Handler {
+ @Override
+ public void handleMessage(android.os.Message msg) {
+ switch (msg.what) {
+ case MSG_USER_SWITCHING:
+ handleUserSwitching(msg.arg1);
+ break;
+
+ default:
+ Slog.w(getTag(), "Unknown message:" + msg.what);
+ }
+ }
+ }
+
+ private final class BiometricTaskStackListener extends TaskStackListener {
+ @Override
+ public void onTaskStackChanged() {
+ try {
+ if (!(mCurrentClient instanceof AuthenticationClient)) {
+ return;
+ }
+ final String currentClient = mCurrentClient.getOwnerString();
+ if (isKeyguard(currentClient)) {
+ return; // Keyguard is always allowed
+ }
+ List<ActivityManager.RunningTaskInfo> runningTasks =
+ mActivityTaskManager.getTasks(1);
+ if (!runningTasks.isEmpty()) {
+ final String topPackage = runningTasks.get(0).topActivity.getPackageName();
+ if (!topPackage.contentEquals(currentClient)) {
+ Slog.e(getTag(), "Stopping background authentication, top: " + topPackage
+ + " currentClient: " + currentClient);
+ mCurrentClient.stop(false /* initiatedByClient */);
+ }
+ }
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Unable to get running tasks", e);
+ }
+ }
+ }
+
+ private final class ResetClientStateRunnable implements Runnable {
+ @Override
+ public void run() {
+ /**
+ * Warning: if we get here, the driver never confirmed our call to cancel the current
+ * operation (authenticate, enroll, remove, enumerate, etc), which is
+ * really bad. The result will be a 3-second delay in starting each new client.
+ * If you see this on a device, make certain the driver notifies with
+ * {@link BiometricConstants#BIOMETRIC_ERROR_CANCELED} in response to cancel()
+ * once it has successfully switched to the IDLE state in the HAL.
+ * Additionally,{@link BiometricConstants#BIOMETRIC_ERROR_CANCELED} should only be sent
+ * in response to an actual cancel() call.
+ */
+ Slog.w(getTag(), "Client "
+ + (mCurrentClient != null ? mCurrentClient.getOwnerString() : "null")
+ + " failed to respond to cancel, starting client "
+ + (mPendingClient != null ? mPendingClient.getOwnerString() : "null"));
+
+ mCurrentClient = null;
+ startClient(mPendingClient, false);
+ }
+ }
+
+ private final class LockoutReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Slog.v(getTag(), "Resetting lockout: " + intent.getAction());
+ if (getLockoutResetIntent().equals(intent.getAction())) {
+ final int user = intent.getIntExtra(KEY_LOCKOUT_RESET_USER, 0);
+ resetFailedAttemptsForUser(false /* clearAttemptCounter */, user);
+ }
+ }
+ }
+
+ private final class ResetFailedAttemptsForUserRunnable implements Runnable {
+ @Override
+ public void run() {
+ resetFailedAttemptsForUser(true /* clearAttemptCounter */,
+ ActivityManager.getCurrentUser());
+ }
+ }
+
+ private final class LockoutResetMonitor implements IBinder.DeathRecipient {
+ private static final long WAKELOCK_TIMEOUT_MS = 2000;
+ private final IBiometricServiceLockoutResetCallback mCallback;
+ private final PowerManager.WakeLock mWakeLock;
+
+ public LockoutResetMonitor(IBiometricServiceLockoutResetCallback callback) {
+ mCallback = callback;
+ mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+ "lockout reset callback");
+ try {
+ mCallback.asBinder().linkToDeath(LockoutResetMonitor.this, 0);
+ } catch (RemoteException e) {
+ Slog.w(getTag(), "caught remote exception in linkToDeath", e);
+ }
+ }
+
+ public void sendLockoutReset() {
+ if (mCallback != null) {
+ try {
+ mWakeLock.acquire(WAKELOCK_TIMEOUT_MS);
+ mCallback.onLockoutReset(getHalDeviceId(), new IRemoteCallback.Stub() {
+ @Override
+ public void sendResult(Bundle data) throws RemoteException {
+ releaseWakelock();
+ }
+ });
+ } catch (DeadObjectException e) {
+ Slog.w(getTag(), "Death object while invoking onLockoutReset: ", e);
+ mHandler.post(mRemoveCallbackRunnable);
+ } catch (RemoteException e) {
+ Slog.w(getTag(), "Failed to invoke onLockoutReset: ", e);
+ releaseWakelock();
+ }
+ }
+ }
+
+ private final Runnable mRemoveCallbackRunnable = new Runnable() {
+ @Override
+ public void run() {
+ releaseWakelock();
+ removeLockoutResetCallback(LockoutResetMonitor.this);
+ }
+ };
+
+ @Override
+ public void binderDied() {
+ Slog.e(getTag(), "Lockout reset callback binder died");
+ mHandler.post(mRemoveCallbackRunnable);
+ }
+
+ private void releaseWakelock() {
+ if (mWakeLock.isHeld()) {
+ mWakeLock.release();
+ }
+ }
+ }
+
+ /**
+ * Initializes the system service.
+ * <p>
+ * Subclasses must define a single argument constructor that accepts the context
+ * and passes it to super.
+ * </p>
+ *
+ * @param context The system server context.
+ */
+ public BiometricService(Context context) {
+ super(context);
+ mContext = context;
+ mKeyguardPackage = ComponentName.unflattenFromString(context.getResources().getString(
+ com.android.internal.R.string.config_keyguardComponent)).getPackageName();
+ mAppOps = context.getSystemService(AppOpsManager.class);
+ mTimedLockoutCleared = new SparseBooleanArray();
+ mFailedAttempts = new SparseIntArray();
+ mActivityTaskManager = ((ActivityTaskManager) context.getSystemService(
+ Context.ACTIVITY_TASK_SERVICE)).getService();
+ mPowerManager = mContext.getSystemService(PowerManager.class);
+ mAlarmManager = mContext.getSystemService(AlarmManager.class);
+ mUserManager = UserManager.get(mContext);
+ mMetricsLogger = new MetricsLogger();
+ mContext.registerReceiver(mLockoutReceiver, new IntentFilter(getLockoutResetIntent()),
+ getLockoutBroadcastPermission(), null /* handler */);
+ }
+
+ @Override
+ public void onStart() {
+ listenForUserSwitches();
+ }
+
+ @Override
+ public void serviceDied(long cookie) {
+ Slog.e(getTag(), "HAL died");
+ mMetricsLogger.count(getMetrics().tagHalDied(), 1);
+ handleError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
+ 0 /*vendorCode */);
+ }
+
+ protected ClientMonitor getCurrentClient() {
+ return mCurrentClient;
+ }
+
+ protected ClientMonitor getPendingClient() {
+ return mPendingClient;
+ }
+
+ /**
+ * Callback handlers from the daemon. The caller must put this on a handler.
+ */
+
+ protected void handleAcquired(long deviceId, int acquiredInfo, int vendorCode) {
+ ClientMonitor client = mCurrentClient;
+ if (client != null && client.onAcquired(acquiredInfo, vendorCode)) {
+ removeClient(client);
+ }
+ if (mPerformanceStats != null && getLockoutMode() == AuthenticationClient.LOCKOUT_NONE
+ && client instanceof AuthenticationClient) {
+ // ignore enrollment acquisitions or acquisitions when we're locked out
+ mPerformanceStats.acquire++;
+ }
+ }
+
+ protected void handleAuthenticated(long deviceId, int biometricId, int groupId,
+ ArrayList<Byte> token) {
+ ClientMonitor client = mCurrentClient;
+ if (biometricId != 0) {
+ final byte[] byteToken = new byte[token.size()];
+ for (int i = 0; i < token.size(); i++) {
+ byteToken[i] = token.get(i);
+ }
+ KeyStore.getInstance().addAuthToken(byteToken);
+ }
+ if (client != null && client.onAuthenticated(biometricId, groupId)) {
+ removeClient(client);
+ }
+ if (biometricId != 0) {
+ mPerformanceStats.accept++;
+ } else {
+ mPerformanceStats.reject++;
+ }
+ }
+
+ protected void handleEnrollResult(BiometricAuthenticator.Identifier identifier,
+ int remaining) {
+ ClientMonitor client = mCurrentClient;
+ if (client != null && client.onEnrollResult(identifier, remaining)) {
+ removeClient(client);
+ // When enrollment finishes, update this group's authenticator id, as the HAL has
+ // already generated a new authenticator id when the new biometric is enrolled.
+ if (identifier instanceof Fingerprint) {
+ updateActiveGroup(((Fingerprint)identifier).getGroupId(), null);
+ } else {
+ updateActiveGroup(mCurrentUserId, null);
+ }
+
+ }
+ }
+
+ protected void handleError(long deviceId, int error, int vendorCode) {
+ final ClientMonitor client = mCurrentClient;
+
+ if (DEBUG) Slog.v(getTag(), "handleError(client="
+ + (client != null ? client.getOwnerString() : "null") + ", error = " + error + ")");
+
+ if (client != null && client.onError(deviceId, error, vendorCode)) {
+ removeClient(client);
+ }
+
+ if (error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) {
+ mHandler.removeCallbacks(mResetClientState);
+ if (mPendingClient != null) {
+ if (DEBUG) Slog.v(getTag(), "start pending client " + mPendingClient.getOwnerString());
+ startClient(mPendingClient, false);
+ mPendingClient = null;
+ }
+ }
+ }
+
+ protected void handleRemoved(BiometricAuthenticator.Identifier identifier,
+ final int remaining) {
+ if (DEBUG) Slog.w(getTag(), "Removed: fid=" + identifier.getBiometricId()
+ + ", dev=" + identifier.getDeviceId()
+ + ", rem=" + remaining);
+
+ ClientMonitor client = mCurrentClient;
+ if (client != null && client.onRemoved(identifier, remaining)) {
+ removeClient(client);
+ // When the last biometric of a group is removed, update the authenticator id
+ int userId = mCurrentUserId;
+ if (identifier instanceof Fingerprint) {
+ userId = ((Fingerprint) identifier).getGroupId();
+ }
+ if (!hasEnrolledBiometrics(userId)) {
+ updateActiveGroup(userId, null);
+ }
+ }
+ }
+
+ /**
+ * Calls from the Manager. These are still on the calling binder's thread.
+ */
+
+ protected void enrollInternal(EnrollClientImpl client, int userId) {
+ if (hasReachedEnrollmentLimit(userId)) {
+ return;
+ }
+
+ // Group ID is arbitrarily set to parent profile user ID. It just represents
+ // the default biometrics for the user.
+ if (!isCurrentUserOrProfile(userId)) {
+ return;
+ }
+
+ mHandler.post(() -> {
+ startClient(client, true /* initiatedByClient */);
+ });
+ }
+
+ protected void cancelEnrollmentInternal(IBinder token) {
+ mHandler.post(() -> {
+ ClientMonitor client = mCurrentClient;
+ if (client instanceof EnrollClient && client.getToken() == token) {
+ client.stop(client.getToken() == token);
+ }
+ });
+ }
+
+ protected void authenticateInternal(AuthenticationClientImpl client, long opId,
+ String opPackageName) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+ final int callingUserId = UserHandle.getCallingUserId();
+
+ if (!canUseBiometric(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
+ callingUserId)) {
+ if (DEBUG) Slog.v(getTag(), "authenticate(): reject " + opPackageName);
+ return;
+ }
+
+ mHandler.post(() -> {
+ mMetricsLogger.histogram(getMetrics().tagAuthToken(), opId != 0L ? 1 : 0);
+
+ // Get performance stats object for this user.
+ HashMap<Integer, PerformanceStats> pmap
+ = (opId == 0) ? mPerformanceMap : mCryptoPerformanceMap;
+ PerformanceStats stats = pmap.get(mCurrentUserId);
+ if (stats == null) {
+ stats = new PerformanceStats();
+ pmap.put(mCurrentUserId, stats);
+ }
+ mPerformanceStats = stats;
+
+ startAuthentication(client, opPackageName);
+ });
+ }
+
+ protected void cancelAuthenticationInternal(final IBinder token, final String opPackageName) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+ final int callingUserId = UserHandle.getCallingUserId();
+
+ if (!canUseBiometric(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
+ callingUserId)) {
+ if (DEBUG) Slog.v(getTag(), "cancelAuthentication(): reject " + opPackageName);
+ return;
+ }
+
+ mHandler.post(() -> {
+ ClientMonitor client = mCurrentClient;
+ if (client instanceof AuthenticationClient) {
+ if (client.getToken() == token) {
+ if (DEBUG) Slog.v(getTag(), "stop client " + client.getOwnerString());
+ client.stop(client.getToken() == token);
+ } else {
+ if (DEBUG) Slog.v(getTag(), "can't stop client "
+ + client.getOwnerString() + " since tokens don't match");
+ }
+ } else if (client != null) {
+ if (DEBUG) Slog.v(getTag(), "can't cancel non-authenticating client "
+ + client.getOwnerString());
+ }
+ });
+ }
+
+ protected void setActiveUserInternal(int userId) {
+ mHandler.post(() -> {
+ updateActiveGroup(userId, null /* clientPackage */);
+ });
+ }
+
+ protected void removeInternal(RemovalClientImpl client) {
+ mHandler.post(() -> {
+ startClient(client, true /* initiatedByClient */);
+ });
+ }
+
+ protected void enumerateInternal(EnumerateClientImpl client) {
+ mHandler.post(() -> {
+ startClient(client, true /* initiatedByClient */);
+ });
+ }
+
+ // Should be done on a handler thread - not on the Binder's thread.
+ private void startAuthentication(AuthenticationClientImpl client, String opPackageName) {
+ updateActiveGroup(client.getGroupId(), opPackageName);
+
+ if (DEBUG) Slog.v(getTag(), "startAuthentication(" + opPackageName + ")");
+
+ int lockoutMode = getLockoutMode();
+ if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
+ Slog.v(getTag(), "In lockout mode(" + lockoutMode +
+ ") ; disallowing authentication");
+ int errorCode = lockoutMode == AuthenticationClient.LOCKOUT_TIMED ?
+ BiometricConstants.BIOMETRIC_ERROR_LOCKOUT :
+ BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
+ if (!client.onError(getHalDeviceId(), errorCode, 0 /* vendorCode */)) {
+ Slog.w(getTag(), "Cannot send permanent lockout message to client");
+ }
+ return;
+ }
+ startClient(client, true /* initiatedByClient */);
+ }
+
+ protected void addLockoutResetCallback(IBiometricServiceLockoutResetCallback callback) {
+ mHandler.post(() -> {
+ final LockoutResetMonitor monitor = new LockoutResetMonitor(callback);
+ if (!mLockoutMonitors.contains(monitor)) {
+ mLockoutMonitors.add(monitor);
+ }
+ });
+ }
+
+ /**
+ * Helper methods.
+ */
+
+ /**
+ * @param opPackageName name of package for caller
+ * @param requireForeground only allow this call while app is in the foreground
+ * @return true if caller can use the biometric API
+ */
+ protected boolean canUseBiometric(String opPackageName, boolean requireForeground, int uid,
+ int pid, int userId) {
+ checkUseBiometricPermission();
+
+ if (isKeyguard(opPackageName)) {
+ return true; // Keyguard is always allowed
+ }
+ if (!isCurrentUserOrProfile(userId)) {
+ Slog.w(getTag(), "Rejecting " + opPackageName + "; not a current user or profile");
+ return false;
+ }
+ if (mAppOps.noteOp(getAppOp(), uid, opPackageName) != AppOpsManager.MODE_ALLOWED) {
+ Slog.w(getTag(), "Rejecting " + opPackageName + "; permission denied");
+ return false;
+ }
+ if (requireForeground && !(isForegroundActivity(uid, pid) || isCurrentClient(
+ opPackageName))) {
+ Slog.w(getTag(), "Rejecting " + opPackageName + "; not in foreground");
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @param opPackageName package of the caller
+ * @return true if this is the same client currently using the biometric
+ */
+ private boolean isCurrentClient(String opPackageName) {
+ return mCurrentClient != null && mCurrentClient.getOwnerString().equals(opPackageName);
+ }
+
+ /**
+ * @return true if this is keyguard package
+ */
+ private boolean isKeyguard(String clientPackage) {
+ return mKeyguardPackage.equals(clientPackage);
+ }
+
+ private int getLockoutMode() {
+ final int currentUser = ActivityManager.getCurrentUser();
+ final int failedAttempts = mFailedAttempts.get(currentUser, 0);
+ if (failedAttempts >= getFailedAttemptsLockoutPermanent()) {
+ return AuthenticationClient.LOCKOUT_PERMANENT;
+ } else if (failedAttempts > 0 &&
+ mTimedLockoutCleared.get(currentUser, false) == false
+ && (failedAttempts % getFailedAttemptsLockoutTimed() == 0)) {
+ return AuthenticationClient.LOCKOUT_TIMED;
+ }
+ return AuthenticationClient.LOCKOUT_NONE;
+ }
+
+ private boolean isForegroundActivity(int uid, int pid) {
+ try {
+ List<ActivityManager.RunningAppProcessInfo> procs =
+ ActivityManager.getService().getRunningAppProcesses();
+ int N = procs.size();
+ for (int i = 0; i < N; i++) {
+ ActivityManager.RunningAppProcessInfo proc = procs.get(i);
+ if (proc.pid == pid && proc.uid == uid
+ && proc.importance <= IMPORTANCE_FOREGROUND_SERVICE) {
+ return true;
+ }
+ }
+ } catch (RemoteException e) {
+ Slog.w(getTag(), "am.getRunningAppProcesses() failed");
+ }
+ return false;
+ }
+
+ /**
+ * Calls the HAL to switch states to the new task. If there's already a current task,
+ * it calls cancel() and sets mPendingClient to begin when the current task finishes
+ * ({@link BiometricConstants#BIOMETRIC_ERROR_CANCELED}).
+ *
+ * @param newClient the new client that wants to connect
+ * @param initiatedByClient true for authenticate, remove and enroll
+ */
+ private void startClient(ClientMonitor newClient, boolean initiatedByClient) {
+ ClientMonitor currentClient = mCurrentClient;
+ if (currentClient != null) {
+ if (DEBUG) Slog.v(getTag(), "request stop current client " +
+ currentClient.getOwnerString());
+
+ // This check only matters for FingerprintService, since enumerate may call back
+ // multiple times.
+ if (currentClient instanceof FingerprintService.EnumerateClientImpl ||
+ currentClient instanceof FingerprintService.RemovalClientImpl) {
+ // This condition means we're currently running internal diagnostics to
+ // remove extra fingerprints in the hardware and/or the software
+ // TODO: design an escape hatch in case client never finishes
+ if (newClient != null) {
+ Slog.w(getTag(), "Internal cleanup in progress but trying to start client "
+ + newClient.getClass().getSuperclass().getSimpleName()
+ + "(" + newClient.getOwnerString() + ")"
+ + ", initiatedByClient = " + initiatedByClient);
+ }
+ } else {
+ currentClient.stop(initiatedByClient);
+ }
+ mPendingClient = newClient;
+ mHandler.removeCallbacks(mResetClientState);
+ mHandler.postDelayed(mResetClientState, CANCEL_TIMEOUT_LIMIT);
+ } else if (newClient != null) {
+ mCurrentClient = newClient;
+ if (DEBUG) Slog.v(getTag(), "starting client "
+ + newClient.getClass().getSuperclass().getSimpleName()
+ + "(" + newClient.getOwnerString() + ")"
+ + ", initiatedByClient = " + initiatedByClient);
+ notifyClientActiveCallbacks(true);
+
+ newClient.start();
+ }
+ }
+
+ protected void removeClient(ClientMonitor client) {
+ if (client != null) {
+ client.destroy();
+ if (client != mCurrentClient && mCurrentClient != null) {
+ Slog.w(getTag(), "Unexpected client: " + client.getOwnerString() + "expected: "
+ + mCurrentClient.getOwnerString());
+ }
+ }
+ if (mCurrentClient != null) {
+ if (DEBUG) Slog.v(getTag(), "Done with client: " + client.getOwnerString());
+ mCurrentClient = null;
+ }
+ if (mPendingClient == null) {
+ notifyClientActiveCallbacks(false);
+ }
+ }
+
+ /**
+ * Populates existing authenticator ids. To be used only during the start of the service.
+ */
+ protected void loadAuthenticatorIds() {
+ // This operation can be expensive, so keep track of the elapsed time. Might need to move to
+ // background if it takes too long.
+ long t = System.currentTimeMillis();
+ mAuthenticatorIds.clear();
+ for (UserInfo user : UserManager.get(getContext()).getUsers(true /* excludeDying */)) {
+ int userId = getUserOrWorkProfileId(null, user.id);
+ if (!mAuthenticatorIds.containsKey(userId)) {
+ updateActiveGroup(userId, null);
+ }
+ }
+
+ t = System.currentTimeMillis() - t;
+ if (t > 1000) {
+ Slog.w(getTag(), "loadAuthenticatorIds() taking too long: " + t + "ms");
+ }
+ }
+
+ /**
+ * @param clientPackage the package of the caller
+ * @return the profile id
+ */
+ protected int getUserOrWorkProfileId(String clientPackage, int userId) {
+ if (!isKeyguard(clientPackage) && isWorkProfile(userId)) {
+ return userId;
+ }
+ return getEffectiveUserId(userId);
+ }
+
+ protected boolean isRestricted() {
+ // Only give privileged apps (like Settings) access to biometric info
+ final boolean restricted = !hasPermission(getManageBiometricPermission());
+ return restricted;
+ }
+
+ protected boolean hasPermission(String permission) {
+ return getContext().checkCallingOrSelfPermission(permission)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
+ protected void checkPermission(String permission) {
+ getContext().enforceCallingOrSelfPermission(permission,
+ "Must have " + permission + " permission.");
+ }
+
+ protected boolean isCurrentUserOrProfile(int userId) {
+ UserManager um = UserManager.get(mContext);
+ if (um == null) {
+ Slog.e(getTag(), "Unable to acquire UserManager");
+ return false;
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ // Allow current user or profiles of the current user...
+ for (int profileId : um.getEnabledProfileIds(ActivityManager.getCurrentUser())) {
+ if (profileId == userId) {
+ return true;
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+
+ return false;
+ }
+
+ /***
+ * @param opPackageName the name of the calling package
+ * @return authenticator id for the calling user
+ */
+ protected long getAuthenticatorId(String opPackageName) {
+ final int userId = getUserOrWorkProfileId(opPackageName, UserHandle.getCallingUserId());
+ return mAuthenticatorIds.getOrDefault(userId, 0L);
+ }
+
+ private void scheduleLockoutResetForUser(int userId) {
+ mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime() + FAIL_LOCKOUT_TIMEOUT_MS,
+ getLockoutResetIntentForUser(userId));
+ }
+
+ private PendingIntent getLockoutResetIntentForUser(int userId) {
+ return PendingIntent.getBroadcast(mContext, userId,
+ new Intent(getLockoutResetIntent()).putExtra(KEY_LOCKOUT_RESET_USER, userId),
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+
+ private void userActivity() {
+ long now = SystemClock.uptimeMillis();
+ mPowerManager.userActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
+ }
+
+ /**
+ * @param userId
+ * @return true if this is a work profile
+ */
+ private boolean isWorkProfile(int userId) {
+ UserInfo userInfo = null;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ userInfo = mUserManager.getUserInfo(userId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ return userInfo != null && userInfo.isManagedProfile();
+ }
+
+
+ private int getEffectiveUserId(int userId) {
+ UserManager um = UserManager.get(mContext);
+ if (um != null) {
+ final long callingIdentity = Binder.clearCallingIdentity();
+ userId = um.getCredentialOwnerProfile(userId);
+ Binder.restoreCallingIdentity(callingIdentity);
+ } else {
+ Slog.e(getTag(), "Unable to acquire UserManager");
+ }
+ return userId;
+ }
+
+ // Attempt counter should only be cleared when Keyguard goes away or when
+ // a biometric is successfully authenticated.
+ private void resetFailedAttemptsForUser(boolean clearAttemptCounter, int userId) {
+ if (DEBUG && getLockoutMode() != AuthenticationClient.LOCKOUT_NONE) {
+ Slog.v(getTag(), "Reset biometric lockout, clearAttemptCounter=" + clearAttemptCounter);
+ }
+ if (clearAttemptCounter) {
+ mFailedAttempts.put(userId, 0);
+ }
+ mTimedLockoutCleared.put(userId, true);
+ // If we're asked to reset failed attempts externally (i.e. from Keyguard),
+ // the alarm might still be pending; remove it.
+ cancelLockoutResetForUser(userId);
+ notifyLockoutResetMonitors();
+ }
+
+ private void cancelLockoutResetForUser(int userId) {
+ mAlarmManager.cancel(getLockoutResetIntentForUser(userId));
+ }
+
+ private void listenForUserSwitches() {
+ try {
+ ActivityManager.getService().registerUserSwitchObserver(
+ new SynchronousUserSwitchObserver() {
+ @Override
+ public void onUserSwitching(int newUserId) throws RemoteException {
+ mHandler.obtainMessage(MSG_USER_SWITCHING, newUserId, 0 /* unused */)
+ .sendToTarget();
+ }
+ }, getTag());
+ } catch (RemoteException e) {
+ Slog.w(getTag(), "Failed to listen for user switching event" ,e);
+ }
+ }
+
+ private void notifyLockoutResetMonitors() {
+ for (int i = 0; i < mLockoutMonitors.size(); i++) {
+ mLockoutMonitors.get(i).sendLockoutReset();
+ }
+ }
+
+ private void removeLockoutResetCallback(
+ LockoutResetMonitor monitor) {
+ mLockoutMonitors.remove(monitor);
+ }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/biometrics/common/BiometricUserState.java b/services/core/java/com/android/server/biometrics/common/BiometricUserState.java
new file mode 100644
index 0000000..53eaac0
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/common/BiometricUserState.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2018 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.common;
+
+import android.content.Context;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.os.AsyncTask;
+import android.os.Environment;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.internal.annotations.GuardedBy;
+
+import libcore.io.IoUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Abstract base class for managing biometrics per user across device reboots.
+ * @hide
+ */
+public abstract class BiometricUserState<T extends BiometricAuthenticator.Identifier> {
+ private static final String TAG = "UserState";
+
+ @GuardedBy("this")
+ protected final ArrayList<T> mBiometrics = new ArrayList<>();
+ protected final Context mContext;
+ protected final File mFile;
+
+ private final Runnable mWriteStateRunnable = new Runnable() {
+ @Override
+ public void run() {
+ doWriteState();
+ }
+ };
+
+ /**
+ * @return The tag for the biometrics. There may be multiple instances of a biometric within.
+ */
+ protected abstract String getBiometricsTag();
+
+ /**
+ * @return The file where the biometric metadata should be stored.
+ */
+ protected abstract String getBiometricFile();
+
+ /**
+ * @return The resource for the name template, this is used to generate the default name.
+ */
+ protected abstract int getNameTemplateResource();
+
+ /**
+ * @return A copy of the list.
+ */
+ protected abstract ArrayList<T> getCopy(ArrayList<T> array);
+
+ /**
+ * @return Writes the cached data to persistent storage.
+ */
+ protected abstract void doWriteState();
+
+ /**
+ * @return
+ */
+ protected abstract void parseBiometricsLocked(XmlPullParser parser)
+ throws IOException, XmlPullParserException;
+
+
+ public BiometricUserState(Context context, int userId) {
+ mFile = getFileForUser(userId);
+ mContext = context;
+ synchronized (this) {
+ readStateSyncLocked();
+ }
+ }
+
+ public void addBiometric(T identifier) {
+ synchronized (this) {
+ mBiometrics.add(identifier);
+ scheduleWriteStateLocked();
+ }
+ }
+
+ public void removeBiometric(int biometricId) {
+ synchronized (this) {
+ for (int i = 0; i < mBiometrics.size(); i++) {
+ if (mBiometrics.get(i).getBiometricId() == biometricId) {
+ mBiometrics.remove(i);
+ scheduleWriteStateLocked();
+ break;
+ }
+ }
+ }
+ }
+
+ public void renameBiometric(int biometricId, CharSequence name) {
+ synchronized (this) {
+ for (int i = 0; i < mBiometrics.size(); i++) {
+ if (mBiometrics.get(i).getBiometricId() == biometricId) {
+ BiometricAuthenticator.Identifier identifier = mBiometrics.get(i);
+ identifier.setName(name);
+ scheduleWriteStateLocked();
+ break;
+ }
+ }
+ }
+ }
+
+ public List<T> getBiometrics() {
+ synchronized (this) {
+ return getCopy(mBiometrics);
+ }
+ }
+
+ /**
+ * Finds a unique name for the given fingerprint
+ * @return unique name
+ */
+ public String getUniqueName() {
+ int guess = 1;
+ while (true) {
+ // Not the most efficient algorithm in the world, but there shouldn't be more than 10
+ String name = mContext.getString(getNameTemplateResource(), guess);
+ if (isUnique(name)) {
+ return name;
+ }
+ guess++;
+ }
+ }
+
+ private boolean isUnique(String name) {
+ for (T identifier : mBiometrics) {
+ if (identifier.getName().equals(name)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private File getFileForUser(int userId) {
+ return new File(Environment.getUserSystemDirectory(userId), getBiometricFile());
+ }
+
+ private void scheduleWriteStateLocked() {
+ AsyncTask.execute(mWriteStateRunnable);
+ }
+
+ @GuardedBy("this")
+ private void readStateSyncLocked() {
+ FileInputStream in;
+ if (!mFile.exists()) {
+ return;
+ }
+ try {
+ in = new FileInputStream(mFile);
+ } catch (FileNotFoundException fnfe) {
+ Slog.i(TAG, "No fingerprint state");
+ return;
+ }
+ try {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(in, null);
+ parseStateLocked(parser);
+
+ } catch (XmlPullParserException | IOException e) {
+ throw new IllegalStateException("Failed parsing settings file: "
+ + mFile , e);
+ } finally {
+ IoUtils.closeQuietly(in);
+ }
+ }
+
+ @GuardedBy("this")
+ private void parseStateLocked(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ final int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals(getBiometricsTag())) {
+ parseBiometricsLocked(parser);
+ }
+ }
+ }
+
+}
diff --git a/services/core/java/com/android/server/biometrics/common/BiometricUtils.java b/services/core/java/com/android/server/biometrics/common/BiometricUtils.java
new file mode 100644
index 0000000..8f076f1
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/common/BiometricUtils.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 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.common;
+
+import android.content.Context;
+import android.hardware.biometrics.BiometricAuthenticator;
+
+import java.util.List;
+
+/**
+ * Interface for utilities managing biometrics and their relevant settings.
+ * @hide
+ */
+public interface BiometricUtils<T extends BiometricAuthenticator.Identifier> {
+ List<T> getBiometricsForUser(Context context, int userId);
+ void addBiometricForUser(Context context, int userId, T identifier);
+ void removeBiometricForUser(Context context, int userId, int biometricId);
+ void renameBiometricForUser(Context context, int userId, int biometricId, CharSequence name);
+ CharSequence getUniqueName(Context context, int userId);
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/fingerprint/ClientMonitor.java b/services/core/java/com/android/server/biometrics/common/ClientMonitor.java
similarity index 60%
rename from services/core/java/com/android/server/fingerprint/ClientMonitor.java
rename to services/core/java/com/android/server/biometrics/common/ClientMonitor.java
index b935ba2..699fc32 100644
--- a/services/core/java/com/android/server/fingerprint/ClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/common/ClientMonitor.java
@@ -1,5 +1,5 @@
-/**
- * Copyright (C) 2016 The Android Open Source Project
+/*
+ * Copyright (C) 2018 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.
@@ -11,16 +11,14 @@
* 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.
+ * limitations under the License
*/
-package com.android.server.fingerprint;
+package com.android.server.biometrics.common;
-import android.Manifest;
import android.content.Context;
-import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
-import android.hardware.fingerprint.FingerprintManager;
-import android.hardware.fingerprint.IFingerprintServiceReceiver;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricConstants;
import android.media.AudioAttributes;
import android.os.IBinder;
import android.os.RemoteException;
@@ -28,23 +26,24 @@
import android.os.Vibrator;
import android.util.Slog;
+import com.android.internal.logging.MetricsLogger;
+
import java.util.NoSuchElementException;
/**
- * Abstract base class for keeping track and dispatching events from fingerprint HAL to the
+ * Abstract base class for keeping track and dispatching events from the biometric's HAL to the
* the current client. Subclasses are responsible for coordinating the interaction with
- * fingerprint HAL for the specific action (e.g. authenticate, enroll, enumerate, etc.).
+ * the biometric's HAL for the specific action (e.g. authenticate, enroll, enumerate, etc.).
*/
public abstract class ClientMonitor implements IBinder.DeathRecipient {
- protected static final String TAG = FingerprintService.TAG; // TODO: get specific name
- protected static final int ERROR_ESRCH = 3; // Likely fingerprint HAL is dead. See errno.h.
- protected static final boolean DEBUG = FingerprintService.DEBUG;
- private static final long[] DEFAULT_SUCCESS_VIBRATION_PATTERN = new long[] {0, 30};
+ protected static final int ERROR_ESRCH = 3; // Likely HAL is dead. See errno.h.
+ protected static final boolean DEBUG = BiometricService.DEBUG;
private static final AudioAttributes FINGERPRINT_SONFICATION_ATTRIBUTES =
new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
.build();
+
private final Context mContext;
private final long mHalDeviceId;
private final int mTargetUserId;
@@ -54,51 +53,65 @@
private final String mOwner;
private final VibrationEffect mSuccessVibrationEffect;
private final VibrationEffect mErrorVibrationEffect;
+ private final BiometricService.DaemonWrapper mDaemon;
+
private IBinder mToken;
- private IFingerprintServiceReceiver mReceiver;
+ private BiometricService.ServiceListener mListener;
+
+ protected final MetricsLogger mMetricsLogger;
+ protected final Metrics mMetrics;
+
protected boolean mAlreadyCancelled;
/**
- * @param context context of FingerprintService
- * @param halDeviceId the HAL device ID of the associated fingerprint hardware
+ * @param context context of BiometricService
+ * @param daemon interface to call back to a specific biometric's daemon
+ * @param halDeviceId the HAL device ID of the associated biometric hardware
* @param token a unique token for the client
- * @param receiver recipient of related events (e.g. authentication)
+ * @param listener recipient of related events (e.g. authentication)
* @param userId target user id for operation
* @param groupId groupId for the fingerprint set
- * @param restricted whether or not client has the {@link Manifest#MANAGE_FINGERPRINT}
+ * @param restricted whether or not client has the MANAGE_* permission
* permission
* @param owner name of the client that owns this
*/
- public ClientMonitor(Context context, long halDeviceId, IBinder token,
- IFingerprintServiceReceiver receiver, int userId, int groupId,boolean restricted,
- String owner) {
+ public ClientMonitor(Context context, Metrics metrics, BiometricService.DaemonWrapper daemon,
+ long halDeviceId, IBinder token, BiometricService.ServiceListener listener, int userId,
+ int groupId, boolean restricted, String owner) {
mContext = context;
+ mMetrics = metrics;
+ mDaemon = daemon;
mHalDeviceId = halDeviceId;
mToken = token;
- mReceiver = receiver;
+ mListener = listener;
mTargetUserId = userId;
mGroupId = groupId;
mIsRestricted = restricted;
mOwner = owner;
mSuccessVibrationEffect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
mErrorVibrationEffect = VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK);
+ mMetricsLogger = new MetricsLogger();
try {
if (token != null) {
token.linkToDeath(this, 0);
}
} catch (RemoteException e) {
- Slog.w(TAG, "caught remote exception in linkToDeath: ", e);
+ Slog.w(getLogTag(), "caught remote exception in linkToDeath: ", e);
}
}
+ protected String getLogTag() {
+ return mMetrics.logTag();
+ }
+
/**
- * Contacts fingerprint HAL to start the client.
+ * Contacts the biometric's HAL to start the client.
* @return 0 on success, errno from driver on failure
*/
public abstract int start();
/**
- * Contacts fingerprint HAL to stop the client.
+ * Contacts the biometric's HAL to stop the client.
* @param initiatedByClient whether the operation is at the request of a client
*/
public abstract int stop(boolean initiatedByClient);
@@ -108,56 +121,54 @@
*/
public abstract void notifyUserActivity();
- /**
- * Gets the fingerprint daemon from the cached state in the container class.
- */
- public abstract IBiometricsFingerprint getFingerprintDaemon();
-
// Event callbacks from driver. Inappropriate calls is flagged/logged by the
// respective client (e.g. enrolling shouldn't get authenticate events).
// All of these return 'true' if the operation is completed and it's ok to move
- // to the next client (e.g. authentication accepts or rejects a fingerprint).
- public abstract boolean onEnrollResult(int fingerId, int groupId, int rem);
- public abstract boolean onAuthenticated(int fingerId, int groupId);
- public abstract boolean onRemoved(int fingerId, int groupId, int remaining);
- public abstract boolean onEnumerationResult(int fingerId, int groupId, int remaining);
+ // to the next client (e.g. authentication accepts or rejects a biometric).
+ public abstract boolean onEnrollResult(BiometricAuthenticator.Identifier identifier,
+ int remaining);
+ public abstract boolean onAuthenticated(int biometricId, int groupId);
+ public abstract boolean onRemoved(BiometricAuthenticator.Identifier identifier,
+ int remaining);
+ public abstract boolean onEnumerationResult(
+ BiometricAuthenticator.Identifier identifier, int remaining);
/**
- * Called when we get notification from fingerprint HAL that an image has been acquired.
+ * Called when we get notification from the biometric's HAL that an image has been acquired.
* Common to authenticate and enroll.
* @param acquiredInfo info about the current image acquisition
* @return true if client should be removed
*/
public boolean onAcquired(int acquiredInfo, int vendorCode) {
- if (mReceiver == null)
- return true; // client not connected
try {
- mReceiver.onAcquired(getHalDeviceId(), acquiredInfo, vendorCode);
+ if (mListener != null) {
+ mListener.onAcquired(getHalDeviceId(), acquiredInfo, vendorCode);
+ }
return false; // acquisition continues...
} catch (RemoteException e) {
- Slog.w(TAG, "Failed to invoke sendAcquired:", e);
- return true; // client failed
+ Slog.w(getLogTag(), "Failed to invoke sendAcquired", e);
+ return true;
} finally {
// Good scans will keep the device awake
- if (acquiredInfo == FingerprintManager.FINGERPRINT_ACQUIRED_GOOD) {
+ if (acquiredInfo == BiometricConstants.BIOMETRIC_ACQUIRED_GOOD) {
notifyUserActivity();
}
}
}
/**
- * Called when we get notification from fingerprint HAL that an error has occurred with the
+ * Called when we get notification from the biometric's HAL that an error has occurred with the
* current operation. Common to authenticate, enroll, enumerate and remove.
* @param error
* @return true if client should be removed
*/
- public boolean onError(int error, int vendorCode) {
- if (mReceiver != null) {
- try {
- mReceiver.onError(getHalDeviceId(), error, vendorCode);
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to invoke sendError:", e);
+ public boolean onError(long deviceId, int error, int vendorCode) {
+ try {
+ if (mListener != null) {
+ mListener.onError(deviceId, error, vendorCode);
}
+ } catch (RemoteException e) {
+ Slog.w(getLogTag(), "Failed to invoke sendError", e);
}
return true; // errors always remove current client
}
@@ -168,26 +179,28 @@
mToken.unlinkToDeath(this, 0);
} catch (NoSuchElementException e) {
// TODO: remove when duplicate call bug is found
- Slog.e(TAG, "destroy(): " + this + ":", new Exception("here"));
+ Slog.e(getLogTag(), "destroy(): " + this + ":", new Exception("here"));
}
mToken = null;
}
- mReceiver = null;
+ mListener = null;
}
@Override
public void binderDied() {
mToken = null;
- mReceiver = null;
- onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
+ mListener = null;
+ onError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */);
}
@Override
protected void finalize() throws Throwable {
try {
if (mToken != null) {
- if (DEBUG) Slog.w(TAG, "removing leaked reference: " + mToken);
- onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
+ if (DEBUG) Slog.w(getLogTag(), "removing leaked reference: " + mToken);
+ onError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */);
}
} finally {
super.finalize();
@@ -206,8 +219,12 @@
return mOwner;
}
- public final IFingerprintServiceReceiver getReceiver() {
- return mReceiver;
+ public final BiometricService.ServiceListener getListener() {
+ return mListener;
+ }
+
+ public final BiometricService.DaemonWrapper getDaemonWrapper() {
+ return mDaemon;
}
public final boolean getIsRestricted() {
diff --git a/services/core/java/com/android/server/biometrics/common/EnrollClient.java b/services/core/java/com/android/server/biometrics/common/EnrollClient.java
new file mode 100644
index 0000000..5744fdb
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/common/EnrollClient.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2018 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.common;
+
+import android.content.Context;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricConstants;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import java.util.Arrays;
+
+/**
+ * A class to keep track of the enrollment state for a given client.
+ */
+public abstract class EnrollClient extends ClientMonitor {
+ private static final long MS_PER_SEC = 1000;
+ private static final int ENROLLMENT_TIMEOUT_MS = 60 * 1000; // 1 minute
+ private final byte[] mCryptoToken;
+ private final BiometricUtils mBiometricUtils;
+
+ public EnrollClient(Context context, Metrics metrics, BiometricService.DaemonWrapper daemon,
+ long halDeviceId, IBinder token, BiometricService.ServiceListener listener, int userId,
+ int groupId, byte[] cryptoToken, boolean restricted, String owner,
+ BiometricUtils utils) {
+ super(context, metrics, daemon, halDeviceId, token, listener, userId, groupId, restricted,
+ owner);
+ mBiometricUtils = utils;
+ mCryptoToken = Arrays.copyOf(cryptoToken, cryptoToken.length);
+ }
+
+ @Override
+ public boolean onEnrollResult(BiometricAuthenticator.Identifier identifier,
+ int remaining) {
+ if (remaining == 0) {
+ mBiometricUtils.addBiometricForUser(getContext(), getTargetUserId(), identifier);
+ }
+ return sendEnrollResult(identifier, remaining);
+ }
+
+ /*
+ * @return true if we're done.
+ */
+ private boolean sendEnrollResult(BiometricAuthenticator.Identifier identifier,
+ int remaining) {
+ vibrateSuccess();
+ mMetricsLogger.action(mMetrics.actionBiometricEnroll());
+ try {
+ getListener().onEnrollResult(identifier, remaining);
+ return remaining == 0;
+ } catch (RemoteException e) {
+ Slog.w(getLogTag(), "Failed to notify EnrollResult:", e);
+ return true;
+ }
+ }
+
+ @Override
+ public int start() {
+ final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
+ try {
+ final int result = getDaemonWrapper().enroll(mCryptoToken, getGroupId(), timeout);
+ if (result != 0) {
+ Slog.w(getLogTag(), "startEnroll failed, result=" + result);
+ mMetricsLogger.histogram(mMetrics.tagEnrollStartError(), result);
+ onError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */);
+ return result;
+ }
+ } catch (RemoteException e) {
+ Slog.e(getLogTag(), "startEnroll failed", e);
+ }
+ return 0; // success
+ }
+
+ @Override
+ public int stop(boolean initiatedByClient) {
+ if (mAlreadyCancelled) {
+ Slog.w(getLogTag(), "stopEnroll: already cancelled!");
+ return 0;
+ }
+
+ try {
+ final int result = getDaemonWrapper().cancel();
+ if (result != 0) {
+ Slog.w(getLogTag(), "startEnrollCancel failed, result = " + result);
+ return result;
+ }
+ } catch (RemoteException e) {
+ Slog.e(getLogTag(), "stopEnrollment failed", e);
+ }
+ if (initiatedByClient) {
+ onError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_CANCELED,
+ 0 /* vendorCode */);
+ }
+ mAlreadyCancelled = true;
+ return 0;
+ }
+
+ @Override
+ public boolean onRemoved(BiometricAuthenticator.Identifier identifier, int remaining) {
+ if (DEBUG) Slog.w(getLogTag(), "onRemoved() called for enroll!");
+ return true; // Invalid for EnrollClient
+ }
+
+ @Override
+ public boolean onEnumerationResult(BiometricAuthenticator.Identifier identifier,
+ int remaining) {
+ if (DEBUG) Slog.w(getLogTag(), "onEnumerationResult() called for enroll!");
+ return true; // Invalid for EnrollClient
+ }
+
+ @Override
+ public boolean onAuthenticated(int biometricId, int groupId) {
+ if (DEBUG) Slog.w(getLogTag(), "onAuthenticated() called for enroll!");
+ return true; // Invalid for EnrollClient
+ }
+
+}
diff --git a/services/core/java/com/android/server/biometrics/common/EnumerateClient.java b/services/core/java/com/android/server/biometrics/common/EnumerateClient.java
new file mode 100644
index 0000000..e51c1c6
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/common/EnumerateClient.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2018 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.common;
+
+import android.content.Context;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricConstants;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+/**
+ * A class to keep track of the enumeration state for a given client.
+ */
+public abstract class EnumerateClient extends ClientMonitor {
+ public EnumerateClient(Context context, Metrics metrics, BiometricService.DaemonWrapper daemon,
+ long halDeviceId, IBinder token, BiometricService.ServiceListener listener, int groupId,
+ int userId, boolean restricted, String owner) {
+ super(context, metrics, daemon, halDeviceId, token, listener, userId, groupId, restricted,
+ owner);
+ }
+
+ @Override
+ public int start() {
+ // The biometric template ids will be removed when we get confirmation from the HAL
+ try {
+ final int result = getDaemonWrapper().enumerate();
+ if (result != 0) {
+ Slog.w(getLogTag(), "start enumerate for user " + getTargetUserId()
+ + " failed, result=" + result);
+ mMetricsLogger.histogram(mMetrics.tagEnumerateStartError(), result);
+ onError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */);
+ return result;
+ }
+ } catch (RemoteException e) {
+ Slog.e(getLogTag(), "startEnumeration failed", e);
+ }
+ return 0;
+ }
+
+ @Override
+ public int stop(boolean initiatedByClient) {
+ if (mAlreadyCancelled) {
+ Slog.w(getLogTag(), "stopEnumerate: already cancelled!");
+ return 0;
+ }
+
+ try {
+ final int result = getDaemonWrapper().cancel();
+ if (result != 0) {
+ Slog.w(getLogTag(), "stop enumeration failed, result=" + result);
+ return result;
+ }
+ } catch (RemoteException e) {
+ Slog.e(getLogTag(), "stopEnumeration failed", e);
+ return ERROR_ESRCH;
+ }
+
+ // We don't actually stop enumerate, but inform the client that the cancel operation
+ // succeeded so we can start the next operation.
+ if (initiatedByClient) {
+ onError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_CANCELED,
+ 0 /* vendorCode */);
+ }
+ mAlreadyCancelled = true;
+ return 0; // success
+ }
+
+ @Override
+ public boolean onEnumerationResult(BiometricAuthenticator.Identifier identifier,
+ int remaining) {
+ try {
+ getListener().onEnumerated(identifier, remaining);
+ } catch (RemoteException e) {
+ Slog.w(getLogTag(), "Failed to notify enumerated:", e);
+ }
+ return remaining == 0;
+ }
+
+ @Override
+ public boolean onAuthenticated(int biometricId, int groupId) {
+ if (DEBUG) Slog.w(getLogTag(), "onAuthenticated() called for enumerate!");
+ return true; // Invalid for Enumerate.
+ }
+
+ @Override
+ public boolean onEnrollResult(BiometricAuthenticator.Identifier identifier, int rem) {
+ if (DEBUG) Slog.w(getLogTag(), "onEnrollResult() called for enumerate!");
+ return true; // Invalid for Enumerate.
+ }
+
+ @Override
+ public boolean onRemoved(BiometricAuthenticator.Identifier identifier, int remaining) {
+ if (DEBUG) Slog.w(getLogTag(), "onRemoved() called for enumerate!");
+ return true; // Invalid for Enumerate.
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/common/Metrics.java b/services/core/java/com/android/server/biometrics/common/Metrics.java
new file mode 100644
index 0000000..eb1a1f8
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/common/Metrics.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 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.common;
+
+public interface Metrics {
+ /** The log tag */
+ String logTag();
+
+ /** Strings for MetricsLogger.count() and MetricsLogger.histogram() */
+ String tagHalDied();
+ String tagAuthToken();
+ String tagAuthStartError();
+ String tagEnrollStartError();
+ String tagEnumerateStartError();
+ String tagRemoveStartError();
+
+ /** Integers for MetricsLogger.action() */
+ int actionBiometricAuth();
+ int actionBiometricEnroll();
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/biometrics/common/RemovalClient.java b/services/core/java/com/android/server/biometrics/common/RemovalClient.java
new file mode 100644
index 0000000..23d5539
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/common/RemovalClient.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2018 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.common;
+
+import android.content.Context;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricConstants;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+/**
+ * A class to keep track of the remove state for a given client.
+ */
+public abstract class RemovalClient extends ClientMonitor {
+ private final int mBiometricId;
+ private final BiometricUtils mBiometricUtils;
+
+ public RemovalClient(Context context, Metrics metrics, BiometricService.DaemonWrapper daemon,
+ long halDeviceId, IBinder token, BiometricService.ServiceListener listener,
+ int biometricId, int groupId, int userId, boolean restricted, String owner,
+ BiometricUtils utils) {
+ super(context, metrics, daemon, halDeviceId, token, listener, userId, groupId, restricted,
+ owner);
+ mBiometricId = biometricId;
+ mBiometricUtils = utils;
+ }
+
+ @Override
+ public int start() {
+ // The biometric template ids will be removed when we get confirmation from the HAL
+ try {
+ final int result = getDaemonWrapper().remove(getGroupId(), mBiometricId);
+ if (result != 0) {
+ Slog.w(getLogTag(), "startRemove with id = " + mBiometricId + " failed, result=" +
+ result);
+ mMetricsLogger.histogram(mMetrics.tagRemoveStartError(), result);
+ onError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */);
+ return result;
+ }
+ } catch (RemoteException e) {
+ Slog.e(getLogTag(), "startRemove failed", e);
+ }
+ return 0;
+ }
+
+ @Override
+ public int stop(boolean initiatedByClient) {
+ if (mAlreadyCancelled) {
+ Slog.w(getLogTag(), "stopRemove: already cancelled!");
+ return 0;
+ }
+
+ try {
+ final int result = getDaemonWrapper().cancel();
+ if (result != 0) {
+ Slog.w(getLogTag(), "stopRemoval failed, result=" + result);
+ return result;
+ }
+ if (DEBUG) Slog.w(getLogTag(), "client " + getOwnerString() + " is no longer removing");
+ } catch (RemoteException e) {
+ Slog.e(getLogTag(), "stopRemoval failed", e);
+ return ERROR_ESRCH;
+ }
+ mAlreadyCancelled = true;
+ return 0; // success
+ }
+
+ /*
+ * @return true if we're done.
+ */
+ private boolean sendRemoved(BiometricAuthenticator.Identifier identifier,
+ int remaining) {
+ try {
+ getListener().onRemoved(identifier, remaining);
+ } catch (RemoteException e) {
+ Slog.w(getLogTag(), "Failed to notify Removed:", e);
+ }
+ return remaining == 0;
+ }
+
+ @Override
+ public boolean onRemoved(BiometricAuthenticator.Identifier identifier, int remaining) {
+ if (identifier.getBiometricId() != 0) {
+ mBiometricUtils.removeBiometricForUser(getContext(), getTargetUserId(),
+ identifier.getBiometricId());
+ }
+ return sendRemoved(identifier, remaining);
+ }
+
+ @Override
+ public boolean onEnrollResult(BiometricAuthenticator.Identifier identifier, int rem) {
+ if (DEBUG) Slog.w(getLogTag(), "onEnrollResult() called for remove!");
+ return true; // Invalid for Remove
+ }
+
+ @Override
+ public boolean onAuthenticated(int biometricId, int groupId) {
+ if (DEBUG) Slog.w(getLogTag(), "onAuthenticated() called for remove!");
+ return true; // Invalid for Remove.
+ }
+
+ @Override
+ public boolean onEnumerationResult(BiometricAuthenticator.Identifier identifier,
+ int remaining) {
+ if (DEBUG) Slog.w(getLogTag(), "onEnumerationResult() called for remove!");
+ return true; // Invalid for Remove.
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/face/FaceMetrics.java b/services/core/java/com/android/server/biometrics/face/FaceMetrics.java
new file mode 100644
index 0000000..4c907b1
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/face/FaceMetrics.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 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.face;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.server.biometrics.common.Metrics;
+
+public class FaceMetrics implements Metrics {
+ @Override
+ public String logTag() {
+ return FaceService.TAG;
+ }
+
+ @Override
+ public String tagHalDied() {
+ return "faced_died";
+ }
+
+ @Override
+ public String tagAuthToken() {
+ return "face_token";
+ }
+
+ @Override
+ public String tagAuthStartError() {
+ return "faced_auth_start_error";
+ }
+
+ @Override
+ public String tagEnrollStartError() {
+ return "faced_enroll_start_error";
+ }
+
+ @Override
+ public String tagEnumerateStartError() {
+ return "faced_enum_start_error";
+ }
+
+ @Override
+ public String tagRemoveStartError() {
+ return "faced_remove_start_error";
+ }
+
+ @Override
+ public int actionBiometricAuth() {
+ return MetricsProto.MetricsEvent.ACTION_FACE_AUTH;
+ }
+
+ @Override
+ public int actionBiometricEnroll() {
+ return MetricsProto.MetricsEvent.ACTION_FACE_ENROLL;
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
new file mode 100644
index 0000000..d2a29e4
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -0,0 +1,785 @@
+/*
+ * Copyright (C) 2018 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.face;
+
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
+import static android.Manifest.permission.MANAGE_FACE;
+import static android.Manifest.permission.RESET_FACE_LOCKOUT;
+import static android.Manifest.permission.USE_BIOMETRIC;
+
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.IBiometricPromptReceiver;
+import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
+import android.hardware.biometrics.face.V1_0.IBiometricsFace;
+import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback;
+import android.hardware.face.Face;
+import android.hardware.face.IFaceService;
+import android.hardware.face.IFaceServiceReceiver;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SELinux;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.util.DumpUtils;
+import com.android.server.SystemServerInitThreadPool;
+import com.android.server.biometrics.common.BiometricService;
+import com.android.server.biometrics.common.BiometricUtils;
+import com.android.server.biometrics.common.Metrics;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A service to manage multiple clients that want to access the face HAL API.
+ * The service is responsible for maintaining a list of clients and dispatching all
+ * face -related events.
+ *
+ * @hide
+ */
+public class FaceService extends BiometricService {
+
+ protected static final String TAG = "FaceService";
+ private static final boolean DEBUG = true;
+ private static final String FACE_DATA_DIR = "facedata";
+ private static final String ACTION_LOCKOUT_RESET =
+ "com.android.server.biometrics.face.ACTION_LOCKOUT_RESET";
+ private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED = 3;
+ private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT = 12;
+
+ /**
+ * Receives the incoming binder calls from FaceManager.
+ */
+ private final class FaceServiceWrapper extends IFaceService.Stub {
+
+ /**
+ * The following methods contain common code which is shared in biometrics/common.
+ */
+ @Override // Binder call
+ public long preEnroll(IBinder token) {
+ checkPermission(MANAGE_FACE);
+ return startPreEnroll(token);
+ }
+
+ @Override // Binder call
+ public int postEnroll(IBinder token) {
+ checkPermission(MANAGE_FACE);
+ return startPostEnroll(token);
+ }
+
+ @Override // Binder call
+ public void enroll(final IBinder token, final byte[] cryptoToken, final int userId,
+ final IFaceServiceReceiver receiver, final int flags,
+ final String opPackageName) {
+ checkPermission(MANAGE_FACE);
+
+ final boolean restricted = isRestricted();
+ final EnrollClientImpl client = new EnrollClientImpl(getContext(), mDaemonWrapper,
+ mHalDeviceId, token, new ServiceListenerImpl(receiver), mCurrentUserId,
+ 0 /* groupId */, cryptoToken, restricted, opPackageName);
+
+ enrollInternal(client, userId);
+ }
+
+ @Override // Binder call
+ public void cancelEnrollment(final IBinder token) {
+ checkPermission(MANAGE_FACE);
+ cancelEnrollmentInternal(token);
+ }
+
+ @Override // Binder call
+ public void authenticate(final IBinder token, final long opId,
+ final IFaceServiceReceiver receiver, final int flags,
+ final String opPackageName, final Bundle bundle,
+ final IBiometricPromptReceiver dialogReceiver) {
+ final boolean restricted = isRestricted();
+ final AuthenticationClientImpl client = new AuthenticationClientImpl(getContext(),
+ mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver),
+ mCurrentUserId, 0 /* groupId */, opId, restricted, opPackageName, bundle,
+ dialogReceiver, mStatusBarService);
+
+ authenticateInternal(client, opId, opPackageName);
+ }
+
+ @Override // Binder call
+ public void cancelAuthentication(final IBinder token, final String opPackageName) {
+ cancelAuthenticationInternal(token, opPackageName);
+ }
+
+ @Override // Binder call
+ public void setActiveUser(final int userId) {
+ checkPermission(MANAGE_FACE);
+ setActiveUserInternal(userId);
+ }
+
+ @Override // Binder call
+ public void remove(final IBinder token, final int faceId, final int userId,
+ final IFaceServiceReceiver receiver) {
+ checkPermission(MANAGE_FACE);
+
+ if (token == null) {
+ Slog.w(TAG, "remove(): token is null");
+ return;
+ }
+
+ final boolean restricted = isRestricted();
+ final RemovalClientImpl client = new RemovalClientImpl(getContext(), mDaemonWrapper,
+ mHalDeviceId, token, new ServiceListenerImpl(receiver), faceId, 0 /* groupId */,
+ userId, restricted, token.toString());
+ client.setShouldNotifyUserActivity(true);
+ removeInternal(client);
+ }
+
+ @Override
+ public void enumerate(final IBinder token, final int userId,
+ final IFaceServiceReceiver receiver) {
+ checkPermission(MANAGE_FACE);
+
+ final boolean restricted = isRestricted();
+ final EnumerateClientImpl client = new EnumerateClientImpl(getContext(), mDaemonWrapper,
+ mHalDeviceId, token, new ServiceListenerImpl(receiver), userId, userId,
+ restricted, getContext().getOpPackageName());
+ enumerateInternal(client);
+ }
+
+ @Override
+ public void addLockoutResetCallback(final IBiometricServiceLockoutResetCallback callback)
+ throws RemoteException {
+ FaceService.super.addLockoutResetCallback(callback);
+ }
+
+ @Override // Binder call
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
+ return;
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ if (args.length > 0 && "--proto".equals(args[0])) {
+ dumpProto(fd);
+ } else {
+ dumpInternal(pw);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ /**
+ * The following methods don't use any common code from BiometricService
+ */
+
+ // TODO: refactor out common code here
+ @Override // Binder call
+ public boolean isHardwareDetected(long deviceId, String opPackageName) {
+ if (!canUseBiometric(opPackageName, false /* foregroundOnly */,
+ Binder.getCallingUid(), Binder.getCallingPid(),
+ UserHandle.getCallingUserId())) {
+ return false;
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ IBiometricsFace daemon = getFaceDaemon();
+ return daemon != null && mHalDeviceId != 0;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override // Binder call
+ public void rename(final int faceId, final String name) {
+ checkPermission(MANAGE_FACE);
+ if (!isCurrentUserOrProfile(UserHandle.getCallingUserId())) {
+ return;
+ }
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ getBiometricUtils().renameBiometricForUser(getContext(), mCurrentUserId,
+ faceId, name);
+ }
+ });
+ }
+
+ @Override // Binder call
+ public List<Face> getEnrolledFaces(int userId, String opPackageName) {
+ if (!canUseBiometric(opPackageName, false /* foregroundOnly */,
+ Binder.getCallingUid(), Binder.getCallingPid(),
+ UserHandle.getCallingUserId())) {
+ return null;
+ }
+
+ return FaceService.this.getEnrolledFaces(userId);
+ }
+
+ @Override // Binder call
+ public boolean hasEnrolledFaces(int userId, String opPackageName) {
+ if (!canUseBiometric(opPackageName, false /* foregroundOnly */,
+ Binder.getCallingUid(), Binder.getCallingPid(),
+ UserHandle.getCallingUserId())) {
+ return false;
+ }
+
+ return FaceService.this.hasEnrolledBiometrics(userId);
+ }
+
+ @Override // Binder call
+ public long getAuthenticatorId(String opPackageName) {
+ // In this method, we're not checking whether the caller is permitted to use face
+ // API because current authenticator ID is leaked (in a more contrived way) via Android
+ // Keystore (android.security.keystore package): the user of that API can create a key
+ // which requires face authentication for its use, and then query the key's
+ // characteristics (hidden API) which returns, among other things, face
+ // authenticator ID which was active at key creation time.
+ //
+ // Reason: The part of Android Keystore which runs inside an app's process invokes this
+ // method in certain cases. Those cases are not always where the developer demonstrates
+ // explicit intent to use face functionality. Thus, to avoiding throwing an
+ // unexpected SecurityException this method does not check whether its caller is
+ // permitted to use face API.
+ //
+ // The permission check should be restored once Android Keystore no longer invokes this
+ // method from inside app processes.
+
+ return FaceService.this.getAuthenticatorId(opPackageName);
+ }
+
+ @Override // Binder call
+ public void resetTimeout(byte[] token) {
+ checkPermission(RESET_FACE_LOCKOUT);
+ // TODO: confirm security token when we move timeout management into the HAL layer.
+ mHandler.post(mResetFailedAttemptsForCurrentUserRunnable);
+ }
+ }
+
+ /**
+ * Receives callbacks from the ClientMonitor implementations. The results are forwarded to
+ * the FaceManager.
+ */
+ private class ServiceListenerImpl implements ServiceListener {
+
+ private IFaceServiceReceiver mFaceServiceReceiver;
+
+ public ServiceListenerImpl(IFaceServiceReceiver receiver) {
+ mFaceServiceReceiver = receiver;
+ }
+
+ @Override
+ public void onEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining)
+ throws RemoteException {
+ if (mFaceServiceReceiver != null) {
+ mFaceServiceReceiver.onEnrollResult(identifier.getDeviceId(),
+ identifier.getBiometricId(),
+ remaining);
+ }
+ }
+
+ @Override
+ public void onAcquired(long deviceId, int acquiredInfo, int vendorCode)
+ throws RemoteException {
+ if (mFaceServiceReceiver != null) {
+ mFaceServiceReceiver.onAcquired(deviceId, acquiredInfo, vendorCode);
+ }
+ }
+
+ @Override
+ public void onAuthenticationSucceeded(long deviceId,
+ BiometricAuthenticator.Identifier biometric, int userId)
+ throws RemoteException {
+ if (mFaceServiceReceiver != null) {
+ if (biometric instanceof Face) {
+ mFaceServiceReceiver.onAuthenticationSucceeded(deviceId, (Face)biometric);
+ } else {
+ Slog.e(TAG, "onAuthenticationSucceeded received non-face biometric");
+ }
+ }
+ }
+
+ @Override
+ public void onAuthenticationFailed(long deviceId) throws RemoteException {
+ if (mFaceServiceReceiver != null) {
+ mFaceServiceReceiver.onAuthenticationFailed(deviceId);
+ }
+ }
+
+ @Override
+ public void onError(long deviceId, int error, int vendorCode) throws RemoteException {
+ if (mFaceServiceReceiver != null) {
+ mFaceServiceReceiver.onError(deviceId, error, vendorCode);
+ }
+ }
+
+ @Override
+ public void onRemoved(BiometricAuthenticator.Identifier identifier,
+ int remaining) throws RemoteException {
+ if (mFaceServiceReceiver != null) {
+ mFaceServiceReceiver.onRemoved(identifier.getDeviceId(),
+ identifier.getBiometricId(), remaining);
+ }
+ }
+
+ @Override
+ public void onEnumerated(BiometricAuthenticator.Identifier identifier, int remaining)
+ throws RemoteException {
+ if (mFaceServiceReceiver != null) {
+
+ }
+ }
+ }
+
+ private final FaceMetrics mFaceMetrics = new FaceMetrics();
+
+ @GuardedBy("this")
+ private IBiometricsFace mDaemon;
+
+ private long mHalDeviceId;
+ private IStatusBarService mStatusBarService;
+
+ /**
+ * Receives callbacks from the HAL.
+ */
+ private IBiometricsFaceClientCallback mDaemonCallback =
+ new IBiometricsFaceClientCallback.Stub() {
+ @Override
+ public void onEnrollResult(final long deviceId, int faceId, int userId,
+ int remaining) {
+ mHandler.post(() -> {
+ final Face face = new Face(getBiometricUtils()
+ .getUniqueName(getContext(), userId), faceId, deviceId);
+ FaceService.super.handleEnrollResult(face, remaining);
+ });
+ }
+
+ @Override
+ public void onAcquired(final long deviceId, final int userId,
+ final int acquiredInfo,
+ final int vendorCode) {
+ mHandler.post(() -> {
+ FaceService.super.handleAcquired(deviceId, acquiredInfo, vendorCode);
+ });
+ }
+
+ @Override
+ public void onAuthenticated(final long deviceId, final int faceId, final int userId,
+ ArrayList<Byte> token) {
+ mHandler.post(() -> {
+ FaceService.super.handleAuthenticated(deviceId, faceId, userId, token);
+ });
+ }
+
+ @Override
+ public void onError(final long deviceId, final int userId, final int error,
+ final int vendorCode) {
+ mHandler.post(() -> {
+ FaceService.super.handleError(deviceId, error, vendorCode);
+
+ // TODO: this chunk of code should be common to all biometric services
+ if (error == BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE) {
+ // If we get HW_UNAVAILABLE, try to connect again later...
+ Slog.w(TAG, "Got ERROR_HW_UNAVAILABLE; try reconnecting next client.");
+ synchronized (this) {
+ mDaemon = null;
+ mHalDeviceId = 0;
+ mCurrentUserId = UserHandle.USER_NULL;
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onRemoved(final long deviceId, final int faceId, final int userId,
+ final int remaining) {
+ mHandler.post(() -> {
+ final Face face = new Face("", faceId, deviceId);
+ FaceService.super.handleRemoved(face, remaining);
+ });
+ }
+
+ @Override
+ public void onEnumerate(long deviceId, ArrayList<Integer> faceIds, int userId)
+ throws RemoteException {
+ // TODO
+ }
+ };
+
+ /**
+ * Wraps the HAL-specific code and is passed to the ClientMonitor implementations so that they
+ * can be shared between the multiple biometric services.
+ */
+ private final DaemonWrapper mDaemonWrapper = new DaemonWrapper() {
+ @Override
+ public int authenticate(long operationId, int groupId) throws RemoteException {
+ IBiometricsFace daemon = getFaceDaemon();
+ if (daemon == null) {
+ Slog.w(TAG, "authenticate(): no face HAL!");
+ return ERROR_ESRCH;
+ }
+ return daemon.authenticate(operationId);
+ }
+
+ @Override
+ public int cancel() throws RemoteException {
+ IBiometricsFace daemon = getFaceDaemon();
+ if (daemon == null) {
+ Slog.w(TAG, "cancel(): no face HAL!");
+ return ERROR_ESRCH;
+ }
+ return daemon.cancel();
+ }
+
+ @Override
+ public int remove(int groupId, int biometricId) throws RemoteException {
+ IBiometricsFace daemon = getFaceDaemon();
+ if (daemon == null) {
+ Slog.w(TAG, "remove(): no face HAL!");
+ return ERROR_ESRCH;
+ }
+ return daemon.remove(biometricId);
+ }
+
+ @Override
+ public int enumerate() throws RemoteException {
+ IBiometricsFace daemon = getFaceDaemon();
+ if (daemon == null) {
+ Slog.w(TAG, "enumerate(): no face HAL!");
+ return ERROR_ESRCH;
+ }
+ return daemon.enumerate();
+ }
+
+ @Override
+ public int enroll(byte[] cryptoToken, int groupId, int timeout) throws RemoteException {
+ IBiometricsFace daemon = getFaceDaemon();
+ if (daemon == null) {
+ Slog.w(TAG, "enroll(): no face HAL!");
+ return ERROR_ESRCH;
+ }
+ final ArrayList<Byte> token = new ArrayList<>();
+ for (int i = 0; i < cryptoToken.length; i++) {
+ token.add(cryptoToken[i]);
+ }
+ return daemon.enroll(token, timeout);
+ }
+ };
+
+
+ public FaceService(Context context) {
+ super(context);
+ // TODO: can this be retrieved from AuthenticationClient, or BiometricService?
+ mStatusBarService = IStatusBarService.Stub.asInterface(
+ ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(Context.FACE_SERVICE, new FaceServiceWrapper());
+ SystemServerInitThreadPool.get().submit(this::getFaceDaemon, TAG + ".onStart");
+ }
+
+ @Override
+ public String getTag() {
+ return TAG;
+ }
+
+ @Override
+ protected BiometricUtils getBiometricUtils() {
+ return FaceUtils.getInstance();
+ }
+
+ @Override
+ protected int getFailedAttemptsLockoutTimed() {
+ return MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED;
+ }
+
+ @Override
+ protected int getFailedAttemptsLockoutPermanent() {
+ return MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT;
+ }
+
+ @Override
+ protected Metrics getMetrics() {
+ return mFaceMetrics;
+ }
+
+ @Override
+ protected boolean hasReachedEnrollmentLimit(int userId) {
+ final int limit = getContext().getResources().getInteger(
+ com.android.internal.R.integer.config_face_MaxTemplatesPerUser);
+ final int enrolled = FaceService.this.getEnrolledFaces(userId).size();
+ if (enrolled >= limit) {
+ Slog.w(TAG, "Too many faces registered");
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ protected void updateActiveGroup(int userId, String clientPackage) {
+ IBiometricsFace daemon = getFaceDaemon();
+
+ if (daemon != null) {
+ try {
+ userId = getUserOrWorkProfileId(clientPackage, userId);
+ if (userId != mCurrentUserId) {
+ final File baseDir = Environment.getDataVendorDeDirectory(userId);
+ final File faceDir = new File(baseDir, FACE_DATA_DIR);
+ if (!faceDir.exists()) {
+ if (!faceDir.mkdir()) {
+ Slog.v(TAG, "Cannot make directory: " + faceDir.getAbsolutePath());
+ return;
+ }
+ // Calling mkdir() from this process will create a directory with our
+ // permissions (inherited from the containing dir). This command fixes
+ // the label.
+ if (!SELinux.restorecon(faceDir)) {
+ Slog.w(TAG, "Restorecons failed. Directory will have wrong label.");
+ return;
+ }
+ }
+
+ daemon.setActiveUser(userId, faceDir.getAbsolutePath());
+ mCurrentUserId = userId;
+ }
+ mAuthenticatorIds.put(userId,
+ hasEnrolledBiometrics(userId) ? daemon.getAuthenticatorId().value : 0L);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to setActiveUser():", e);
+ }
+ }
+ }
+
+ @Override
+ protected String getLockoutResetIntent() {
+ return ACTION_LOCKOUT_RESET;
+ }
+
+ @Override
+ protected String getLockoutBroadcastPermission() {
+ return RESET_FACE_LOCKOUT;
+ }
+
+ @Override
+ protected long getHalDeviceId() {
+ return mHalDeviceId;
+ }
+
+ @Override
+ protected void handleUserSwitching(int userId) {
+ updateActiveGroup(userId, null);
+ }
+
+ @Override
+ protected boolean hasEnrolledBiometrics(int userId) {
+ if (userId != UserHandle.getCallingUserId()) {
+ checkPermission(INTERACT_ACROSS_USERS);
+ }
+ return getBiometricUtils().getBiometricsForUser(getContext(), userId).size() > 0;
+ }
+
+ @Override
+ protected String getManageBiometricPermission() {
+ return MANAGE_FACE;
+ }
+
+ @Override
+ protected void checkUseBiometricPermission() {
+ checkPermission(USE_BIOMETRIC);
+ }
+
+ @Override
+ protected int getAppOp() {
+ return AppOpsManager.OP_USE_FACE;
+ }
+
+ @Override
+ protected void notifyClientActiveCallbacks(boolean isActive) {
+ // noop for Face.
+ }
+
+ /** Gets the face daemon */
+ private synchronized IBiometricsFace getFaceDaemon() {
+ if (mDaemon == null) {
+ Slog.v(TAG, "mDaemon was null, reconnect to face");
+ try {
+ mDaemon = IBiometricsFace.getService();
+ } catch (java.util.NoSuchElementException e) {
+ // Service doesn't exist or cannot be opened. Logged below.
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to get biometric interface", e);
+ }
+ if (mDaemon == null) {
+ Slog.w(TAG, "face HIDL not available");
+ return null;
+ }
+
+ mDaemon.asBinder().linkToDeath(this, 0);
+
+ try {
+ mHalDeviceId = mDaemon.setCallback(mDaemonCallback).value;
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to open face HAL", e);
+ mDaemon = null; // try again later!
+ }
+
+ if (DEBUG) Slog.v(TAG, "Face HAL id: " + mHalDeviceId);
+ if (mHalDeviceId != 0) {
+ loadAuthenticatorIds();
+ updateActiveGroup(ActivityManager.getCurrentUser(), null);
+ } else {
+ Slog.w(TAG, "Failed to open Face HAL!");
+ MetricsLogger.count(getContext(), "faced_openhal_error", 1);
+ mDaemon = null;
+ }
+ }
+ return mDaemon;
+ }
+
+ private long startPreEnroll(IBinder token) {
+ IBiometricsFace daemon = getFaceDaemon();
+ if (daemon == null) {
+ Slog.w(TAG, "startPreEnroll: no face HAL!");
+ return 0;
+ }
+ try {
+ return daemon.preEnroll().value;
+ } catch (RemoteException e) {
+ Slog.e(TAG, "startPreEnroll failed", e);
+ }
+ return 0;
+ }
+
+ private int startPostEnroll(IBinder token) {
+ IBiometricsFace daemon = getFaceDaemon();
+ if (daemon == null) {
+ Slog.w(TAG, "startPostEnroll: no face HAL!");
+ return 0;
+ }
+ try {
+ return daemon.postEnroll();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "startPostEnroll failed", e);
+ }
+ return 0;
+ }
+
+ private List<Face> getEnrolledFaces(int userId) {
+ return getBiometricUtils().getBiometricsForUser(getContext(), userId);
+ }
+
+ private void dumpInternal(PrintWriter pw) {
+ JSONObject dump = new JSONObject();
+ try {
+ dump.put("service", "Face Manager");
+
+ JSONArray sets = new JSONArray();
+ for (UserInfo user : UserManager.get(getContext()).getUsers()) {
+ final int userId = user.getUserHandle().getIdentifier();
+ final int N = getBiometricUtils().getBiometricsForUser(getContext(), userId).size();
+ PerformanceStats stats = mPerformanceMap.get(userId);
+ PerformanceStats cryptoStats = mCryptoPerformanceMap.get(userId);
+ JSONObject set = new JSONObject();
+ set.put("id", userId);
+ set.put("count", N);
+ set.put("accept", (stats != null) ? stats.accept : 0);
+ set.put("reject", (stats != null) ? stats.reject : 0);
+ set.put("acquire", (stats != null) ? stats.acquire : 0);
+ set.put("lockout", (stats != null) ? stats.lockout : 0);
+ set.put("permanentLockout", (stats != null) ? stats.permanentLockout : 0);
+ // cryptoStats measures statistics about secure face transactions
+ // (e.g. to unlock password storage, make secure purchases, etc.)
+ set.put("acceptCrypto", (cryptoStats != null) ? cryptoStats.accept : 0);
+ set.put("rejectCrypto", (cryptoStats != null) ? cryptoStats.reject : 0);
+ set.put("acquireCrypto", (cryptoStats != null) ? cryptoStats.acquire : 0);
+ set.put("lockoutCrypto", (cryptoStats != null) ? cryptoStats.lockout : 0);
+ set.put("permanentLockoutCrypto",
+ (cryptoStats != null) ? cryptoStats.permanentLockout : 0);
+ sets.put(set);
+ }
+
+ dump.put("prints", sets);
+ } catch (JSONException e) {
+ Slog.e(TAG, "dump formatting failure", e);
+ }
+ pw.println(dump);
+ }
+
+ private void dumpProto(FileDescriptor fd) {
+ final ProtoOutputStream proto = new ProtoOutputStream(fd);
+ for (UserInfo user : UserManager.get(getContext()).getUsers()) {
+ final int userId = user.getUserHandle().getIdentifier();
+
+ final long userToken = proto.start(FaceServiceDumpProto.USERS);
+
+ proto.write(FaceUserStatsProto.USER_ID, userId);
+ proto.write(FaceUserStatsProto.NUM_FACES,
+ getBiometricUtils().getBiometricsForUser(getContext(), userId).size());
+
+ // Normal face authentications (e.g. lockscreen)
+ final PerformanceStats normal = mPerformanceMap.get(userId);
+ if (normal != null) {
+ final long countsToken = proto.start(FaceUserStatsProto.NORMAL);
+ proto.write(FaceActionStatsProto.ACCEPT, normal.accept);
+ proto.write(FaceActionStatsProto.REJECT, normal.reject);
+ proto.write(FaceActionStatsProto.ACQUIRE, normal.acquire);
+ proto.write(FaceActionStatsProto.LOCKOUT, normal.lockout);
+ proto.write(FaceActionStatsProto.LOCKOUT_PERMANENT, normal.lockout);
+ proto.end(countsToken);
+ }
+
+ // Statistics about secure face transactions (e.g. to unlock password
+ // storage, make secure purchases, etc.)
+ final PerformanceStats crypto = mCryptoPerformanceMap.get(userId);
+ if (crypto != null) {
+ final long countsToken = proto.start(FaceUserStatsProto.CRYPTO);
+ proto.write(FaceActionStatsProto.ACCEPT, crypto.accept);
+ proto.write(FaceActionStatsProto.REJECT, crypto.reject);
+ proto.write(FaceActionStatsProto.ACQUIRE, crypto.acquire);
+ proto.write(FaceActionStatsProto.LOCKOUT, crypto.lockout);
+ proto.write(FaceActionStatsProto.LOCKOUT_PERMANENT, crypto.lockout);
+ proto.end(countsToken);
+ }
+
+ proto.end(userToken);
+ }
+ proto.flush();
+ mPerformanceMap.clear();
+ mCryptoPerformanceMap.clear();
+ }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/biometrics/face/FaceUserState.java b/services/core/java/com/android/server/biometrics/face/FaceUserState.java
new file mode 100644
index 0000000..7d67c62
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/face/FaceUserState.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2018 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.face;
+
+import android.content.Context;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.face.Face;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.server.biometrics.common.BiometricUserState;
+
+import libcore.io.IoUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+
+
+/**
+ * Class managing the set of faces per user across device reboots.
+ * @hide
+ */
+public class FaceUserState extends BiometricUserState {
+
+ private static final String TAG = "FaceState";
+ private static final String FACE_FILE = "settings_face.xml";
+
+ private static final String TAG_FACES = "faces";
+ private static final String TAG_FACE = "face";
+ private static final String ATTR_NAME = "name";
+ private static final String ATTR_FACE_ID = "faceId";
+ private static final String ATTR_DEVICE_ID = "deviceId";
+
+ public FaceUserState(Context ctx, int userId) {
+ super(ctx, userId);
+ }
+
+ @Override
+ protected String getBiometricsTag() {
+ return TAG_FACES;
+ }
+
+ @Override
+ protected String getBiometricFile() {
+ return FACE_FILE;
+ }
+
+ @Override
+ protected int getNameTemplateResource() {
+ return com.android.internal.R.string.face_name_template;
+ }
+
+ @Override
+ public void addBiometric(BiometricAuthenticator.Identifier identifier) {
+ if (identifier instanceof Face) {
+ super.addBiometric(identifier);
+ } else {
+ Slog.w(TAG, "Attempted to add non-face identifier");
+ }
+ }
+
+ @Override
+ protected ArrayList getCopy(ArrayList array) {
+ ArrayList<Face> result = new ArrayList<>(array.size());
+ for (int i = 0; i < array.size(); i++) {
+ Face f = (Face) array.get(i);
+ result.add(new Face(f.getName(), f.getFaceId(), f.getDeviceId()));
+ }
+ return result;
+ }
+
+ @Override
+ protected void doWriteState() {
+ AtomicFile destination = new AtomicFile(mFile);
+
+ ArrayList<Face> faces;
+
+ synchronized (this) {
+ faces = getCopy(mBiometrics);
+ }
+
+ FileOutputStream out = null;
+ try {
+ out = destination.startWrite();
+
+ XmlSerializer serializer = Xml.newSerializer();
+ serializer.setOutput(out, "utf-8");
+ serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+ serializer.startDocument(null, true);
+ serializer.startTag(null, TAG_FACES);
+
+ final int count = faces.size();
+ for (int i = 0; i < count; i++) {
+ Face f = faces.get(i);
+ serializer.startTag(null, TAG_FACE);
+ serializer.attribute(null, ATTR_FACE_ID, Integer.toString(f.getFaceId()));
+ serializer.attribute(null, ATTR_NAME, f.getName().toString());
+ serializer.attribute(null, ATTR_DEVICE_ID, Long.toString(f.getDeviceId()));
+ serializer.endTag(null, TAG_FACE);
+ }
+
+ serializer.endTag(null, TAG_FACES);
+ serializer.endDocument();
+ destination.finishWrite(out);
+
+ // Any error while writing is fatal.
+ } catch (Throwable t) {
+ Slog.wtf(TAG, "Failed to write settings, restoring backup", t);
+ destination.failWrite(out);
+ throw new IllegalStateException("Failed to write faces", t);
+ } finally {
+ IoUtils.closeQuietly(out);
+ }
+ }
+
+ @Override
+ protected void parseBiometricsLocked(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ final int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals(TAG_FACE)) {
+ String name = parser.getAttributeValue(null, ATTR_NAME);
+ String faceId = parser.getAttributeValue(null, ATTR_FACE_ID);
+ String deviceId = parser.getAttributeValue(null, ATTR_DEVICE_ID);
+ mBiometrics.add(new Face(name, Integer.parseInt(faceId), Integer.parseInt(deviceId)));
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/face/FaceUtils.java b/services/core/java/com/android/server/biometrics/face/FaceUtils.java
new file mode 100644
index 0000000..a7e85e0
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/face/FaceUtils.java
@@ -0,0 +1,94 @@
+/**
+ * Copyright (C) 2018 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.face;
+
+import android.content.Context;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.face.Face;
+import android.text.TextUtils;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.biometrics.common.BiometricUtils;
+
+import java.util.List;
+
+/**
+ * Utility class for dealing with faces and face settings.
+ */
+public class FaceUtils implements BiometricUtils {
+
+ private static final Object sInstanceLock = new Object();
+ private static FaceUtils sInstance;
+
+ @GuardedBy("this")
+ private final SparseArray<FaceUserState> mUsers = new SparseArray<>();
+
+ public static FaceUtils getInstance() {
+ synchronized (sInstanceLock) {
+ if (sInstance == null) {
+ sInstance = new FaceUtils();
+ }
+ }
+ return sInstance;
+ }
+
+ private FaceUtils() {
+ }
+
+ @Override
+ public List<Face> getBiometricsForUser(Context ctx, int userId) {
+ return getStateForUser(ctx, userId).getBiometrics();
+ }
+
+ @Override
+ public void addBiometricForUser(Context ctx, int userId,
+ BiometricAuthenticator.Identifier identifier) {
+ getStateForUser(ctx, userId).addBiometric(identifier);
+ }
+
+ @Override
+ public void removeBiometricForUser(Context ctx, int userId, int faceId) {
+ getStateForUser(ctx, userId).removeBiometric(faceId);
+ }
+
+ @Override
+ public void renameBiometricForUser(Context ctx, int userId, int faceId, CharSequence name) {
+ if (TextUtils.isEmpty(name)) {
+ // Don't do the rename if it's empty
+ return;
+ }
+ getStateForUser(ctx, userId).renameBiometric(faceId, name);
+ }
+
+ @Override
+ public CharSequence getUniqueName(Context context, int userId) {
+ return getStateForUser(context, userId).getUniqueName();
+ }
+
+ private FaceUserState getStateForUser(Context ctx, int userId) {
+ synchronized (this) {
+ FaceUserState state = mUsers.get(userId);
+ if (state == null) {
+ state = new FaceUserState(ctx, userId);
+ mUsers.put(userId, state);
+ }
+ return state;
+ }
+ }
+}
+
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintMetrics.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintMetrics.java
new file mode 100644
index 0000000..ba8b3b3
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintMetrics.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 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.fingerprint;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.server.biometrics.common.Metrics;
+
+public class FingerprintMetrics implements Metrics {
+
+ @Override
+ public String logTag() {
+ return FingerprintService.TAG;
+ }
+
+ @Override
+ public String tagHalDied() {
+ return "fingerprintd_died";
+ }
+
+ @Override
+ public String tagAuthToken() {
+ return "fingerprint_token";
+ }
+
+ @Override
+ public String tagAuthStartError() {
+ return "fingerprintd_auth_start_error";
+ }
+
+ @Override
+ public String tagEnrollStartError() {
+ return "fingerprintd_enroll_start_error";
+ }
+
+ @Override
+ public String tagEnumerateStartError() {
+ return "fingerprintd_enum_start_error";
+ }
+
+ @Override
+ public String tagRemoveStartError() {
+ return "fingerprintd_remove_start_error";
+ }
+
+ @Override
+ public int actionBiometricAuth() {
+ return MetricsProto.MetricsEvent.ACTION_FINGERPRINT_AUTH;
+ }
+
+ @Override
+ public int actionBiometricEnroll() {
+ return MetricsProto.MetricsEvent.ACTION_FINGERPRINT_ENROLL;
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
new file mode 100644
index 0000000..7004e1b
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -0,0 +1,1026 @@
+/*
+ * Copyright (C) 2014 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.fingerprint;
+
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
+import static android.Manifest.permission.MANAGE_FINGERPRINT;
+import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT;
+import static android.Manifest.permission.USE_BIOMETRIC;
+import static android.Manifest.permission.USE_FINGERPRINT;
+
+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.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.IBiometricPromptReceiver;
+import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
+import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
+import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprintClientCallback;
+import android.hardware.fingerprint.Fingerprint;
+import android.hardware.fingerprint.IFingerprintClientActiveCallback;
+import android.hardware.fingerprint.IFingerprintService;
+import android.hardware.fingerprint.IFingerprintServiceReceiver;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.SELinux;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.util.DumpUtils;
+import com.android.server.SystemServerInitThreadPool;
+import com.android.server.biometrics.common.BiometricService;
+import com.android.server.biometrics.common.BiometricUtils;
+import com.android.server.biometrics.common.ClientMonitor;
+import com.android.server.biometrics.common.EnumerateClient;
+import com.android.server.biometrics.common.Metrics;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * A service to manage multiple clients that want to access the fingerprint HAL API.
+ * The service is responsible for maintaining a list of clients and dispatching all
+ * fingerprint-related events.
+ *
+ * @hide
+ */
+public class FingerprintService extends BiometricService {
+
+ protected static final String TAG = "FingerprintService";
+ private static final boolean DEBUG = true;
+ private static final boolean CLEANUP_UNUSED_FP = true;
+ private static final String FP_DATA_DIR = "fpdata";
+ private static final String ACTION_LOCKOUT_RESET =
+ "com.android.server.biometrics.fingerprint.ACTION_LOCKOUT_RESET";
+ private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED = 5;
+ private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT = 20;
+
+ // TODO: This should be refactored into BiometricService
+ private final class UserFingerprint {
+ Fingerprint f;
+ int userId;
+ public UserFingerprint(Fingerprint f, int userId) {
+ this.f = f;
+ this.userId = userId;
+ }
+ }
+
+ /**
+ * Receives the incoming binder calls from FingerprintManager.
+ */
+ private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
+
+ /**
+ * The following methods contain common code which is shared in biometrics/common.
+ */
+
+ @Override // Binder call
+ public long preEnroll(IBinder token) {
+ checkPermission(MANAGE_FINGERPRINT);
+ return startPreEnroll(token);
+ }
+
+ @Override // Binder call
+ public int postEnroll(IBinder token) {
+ checkPermission(MANAGE_FINGERPRINT);
+ return startPostEnroll(token);
+ }
+
+ @Override // Binder call
+ public void enroll(final IBinder token, final byte[] cryptoToken, final int userId,
+ final IFingerprintServiceReceiver receiver, final int flags,
+ final String opPackageName) {
+ checkPermission(MANAGE_FINGERPRINT);
+
+ final boolean restricted = isRestricted();
+ final int groupId = userId; // default group for fingerprint enrollment
+ final EnrollClientImpl client = new EnrollClientImpl(getContext(), mDaemonWrapper,
+ mHalDeviceId, token, new ServiceListenerImpl(receiver), mCurrentUserId, groupId,
+ cryptoToken, restricted, opPackageName);
+
+ enrollInternal(client, userId);
+ }
+
+ @Override // Binder call
+ public void cancelEnrollment(final IBinder token) {
+ checkPermission(MANAGE_FINGERPRINT);
+ cancelEnrollmentInternal(token);
+ }
+
+ @Override // Binder call
+ public void authenticate(final IBinder token, final long opId, final int groupId,
+ final IFingerprintServiceReceiver receiver, final int flags,
+ final String opPackageName, final Bundle bundle,
+ final IBiometricPromptReceiver dialogReceiver) {
+ final boolean restricted = isRestricted();
+ final AuthenticationClientImpl client = new AuthenticationClientImpl(getContext(),
+ mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver),
+ mCurrentUserId, groupId, opId, restricted, opPackageName, bundle,
+ dialogReceiver, mStatusBarService);
+
+ authenticateInternal(client, opId, opPackageName);
+ }
+
+ @Override // Binder call
+ public void cancelAuthentication(final IBinder token, final String opPackageName) {
+ cancelAuthenticationInternal(token, opPackageName);
+ }
+
+ @Override // Binder call
+ public void setActiveUser(final int userId) {
+ checkPermission(MANAGE_FINGERPRINT);
+ setActiveUserInternal(userId);
+ }
+
+ @Override // Binder call
+ public void remove(final IBinder token, final int fingerId, final int groupId,
+ final int userId, final IFingerprintServiceReceiver receiver) {
+ checkPermission(MANAGE_FINGERPRINT);
+
+ if (token == null) {
+ Slog.w(TAG, "remove(): token is null");
+ return;
+ }
+
+ final boolean restricted = isRestricted();
+ final RemovalClientImpl client = new RemovalClientImpl(getContext(), mDaemonWrapper,
+ mHalDeviceId, token, new ServiceListenerImpl(receiver), fingerId, groupId,
+ userId, restricted, token.toString());
+ client.setShouldNotifyUserActivity(true);
+ removeInternal(client);
+ }
+
+ @Override // Binder call
+ public void enumerate(final IBinder token, final int userId,
+ final IFingerprintServiceReceiver receiver) {
+ checkPermission(MANAGE_FINGERPRINT);
+
+ final boolean restricted = isRestricted();
+ final EnumerateClientImpl client = new EnumerateClientImpl(getContext(), mDaemonWrapper,
+ mHalDeviceId, token, new ServiceListenerImpl(receiver), userId, userId,
+ restricted, getContext().getOpPackageName());
+ enumerateInternal(client);
+ }
+
+ @Override
+ public void addLockoutResetCallback(final IBiometricServiceLockoutResetCallback callback)
+ throws RemoteException {
+ FingerprintService.super.addLockoutResetCallback(callback);
+ }
+
+ @Override // Binder call
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
+ return;
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ if (args.length > 0 && "--proto".equals(args[0])) {
+ dumpProto(fd);
+ } else {
+ dumpInternal(pw);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ /**
+ * The following methods don't use any common code from BiometricService
+ */
+
+ // TODO: refactor out common code here
+ @Override // Binder call
+ public boolean isHardwareDetected(long deviceId, String opPackageName) {
+ if (!canUseBiometric(opPackageName, false /* foregroundOnly */,
+ Binder.getCallingUid(), Binder.getCallingPid(),
+ UserHandle.getCallingUserId())) {
+ return false;
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ IBiometricsFingerprint daemon = getFingerprintDaemon();
+ return daemon != null && mHalDeviceId != 0;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override // Binder call
+ public void rename(final int fingerId, final int groupId, final String name) {
+ checkPermission(MANAGE_FINGERPRINT);
+ if (!isCurrentUserOrProfile(groupId)) {
+ return;
+ }
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ getBiometricUtils().renameBiometricForUser(getContext(), groupId,
+ fingerId, name);
+ }
+ });
+ }
+
+ @Override // Binder call
+ public List<Fingerprint> getEnrolledFingerprints(int userId, String opPackageName) {
+ if (!canUseBiometric(opPackageName, false /* foregroundOnly */,
+ Binder.getCallingUid(), Binder.getCallingPid(),
+ UserHandle.getCallingUserId())) {
+ return Collections.emptyList();
+ }
+
+ return FingerprintService.this.getEnrolledFingerprints(userId);
+ }
+
+ @Override // Binder call
+ public boolean hasEnrolledFingerprints(int userId, String opPackageName) {
+ if (!canUseBiometric(opPackageName, false /* foregroundOnly */,
+ Binder.getCallingUid(), Binder.getCallingPid(),
+ UserHandle.getCallingUserId())) {
+ return false;
+ }
+
+ return FingerprintService.this.hasEnrolledBiometrics(userId);
+ }
+
+ @Override // Binder call
+ public long getAuthenticatorId(String opPackageName) {
+ // In this method, we're not checking whether the caller is permitted to use fingerprint
+ // API because current authenticator ID is leaked (in a more contrived way) via Android
+ // Keystore (android.security.keystore package): the user of that API can create a key
+ // which requires fingerprint authentication for its use, and then query the key's
+ // characteristics (hidden API) which returns, among other things, fingerprint
+ // authenticator ID which was active at key creation time.
+ //
+ // Reason: The part of Android Keystore which runs inside an app's process invokes this
+ // method in certain cases. Those cases are not always where the developer demonstrates
+ // explicit intent to use fingerprint functionality. Thus, to avoiding throwing an
+ // unexpected SecurityException this method does not check whether its caller is
+ // permitted to use fingerprint API.
+ //
+ // The permission check should be restored once Android Keystore no longer invokes this
+ // method from inside app processes.
+
+ return FingerprintService.super.getAuthenticatorId(opPackageName);
+ }
+
+ @Override // Binder call
+ public void resetTimeout(byte [] token) {
+ checkPermission(RESET_FINGERPRINT_LOCKOUT);
+ // TODO: confirm security token when we move timeout management into the HAL layer.
+ mHandler.post(mResetFailedAttemptsForCurrentUserRunnable);
+ }
+
+ @Override
+ public boolean isClientActive() {
+ checkPermission(MANAGE_FINGERPRINT);
+ synchronized(FingerprintService.this) {
+ return (getCurrentClient() != null) || (getPendingClient() != null);
+ }
+ }
+
+ @Override
+ public void addClientActiveCallback(IFingerprintClientActiveCallback callback) {
+ checkPermission(MANAGE_FINGERPRINT);
+ mClientActiveCallbacks.add(callback);
+ }
+
+ @Override
+ public void removeClientActiveCallback(IFingerprintClientActiveCallback callback) {
+ checkPermission(MANAGE_FINGERPRINT);
+ mClientActiveCallbacks.remove(callback);
+ }
+ }
+
+ /**
+ * Receives callbacks from the ClientMonitor implementations. The results are forwarded to
+ * the FingerprintManager.
+ */
+ private class ServiceListenerImpl implements ServiceListener {
+
+ private IFingerprintServiceReceiver mFingerprintServiceReceiver;
+
+ public ServiceListenerImpl(IFingerprintServiceReceiver receiver) {
+ mFingerprintServiceReceiver = receiver;
+ }
+
+ @Override
+ public void onEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining)
+ throws RemoteException {
+ if (mFingerprintServiceReceiver != null) {
+ // TODO: Pass up the fp directly instead
+ final Fingerprint fp = (Fingerprint) identifier;
+ mFingerprintServiceReceiver.onEnrollResult(fp.getDeviceId(), fp.getBiometricId(),
+ fp.getGroupId(), remaining);
+ }
+ }
+
+ @Override
+ public void onAcquired(long deviceId, int acquiredInfo, int vendorCode)
+ throws RemoteException {
+ if (mFingerprintServiceReceiver != null) {
+ mFingerprintServiceReceiver.onAcquired(deviceId, acquiredInfo, vendorCode);
+ }
+ }
+
+ @Override
+ public void onAuthenticationSucceeded(long deviceId,
+ BiometricAuthenticator.Identifier biometric, int userId)
+ throws RemoteException {
+ if (mFingerprintServiceReceiver != null) {
+ if (biometric == null || biometric instanceof Fingerprint) {
+ mFingerprintServiceReceiver
+ .onAuthenticationSucceeded(deviceId, (Fingerprint) biometric, userId);
+ } else {
+ Slog.e(TAG, "onAuthenticationSucceeded received non-fingerprint biometric");
+ }
+ }
+ }
+
+ @Override
+ public void onAuthenticationFailed(long deviceId) throws RemoteException {
+ if (mFingerprintServiceReceiver != null) {
+ mFingerprintServiceReceiver.onAuthenticationFailed(deviceId);
+ }
+ }
+
+ @Override
+ public void onError(long deviceId, int error, int vendorCode) throws RemoteException {
+ if (mFingerprintServiceReceiver != null) {
+ mFingerprintServiceReceiver.onError(deviceId, error, vendorCode);
+ }
+ }
+
+ @Override
+ public void onRemoved(BiometricAuthenticator.Identifier identifier, int remaining)
+ throws RemoteException {
+ if (mFingerprintServiceReceiver != null) {
+ // TODO: Pass up the fp directly instead
+ final Fingerprint fp = (Fingerprint) identifier;
+ mFingerprintServiceReceiver.onRemoved(fp.getDeviceId(), fp.getBiometricId(),
+ fp.getGroupId(), remaining);
+ }
+ }
+
+ @Override
+ public void onEnumerated(BiometricAuthenticator.Identifier identifier, int remaining)
+ throws RemoteException {
+ if (mFingerprintServiceReceiver != null) {
+ final Fingerprint fp = (Fingerprint) identifier;
+ mFingerprintServiceReceiver.onEnumerated(fp.getDeviceId(), fp.getBiometricId(),
+ fp.getGroupId(), remaining);
+ }
+ }
+ }
+
+ /**
+ * An internal class to help clean up unknown fingerprints in the hardware and software.
+ */
+ private final class InternalEnumerateClient extends BiometricService.EnumerateClientImpl {
+
+ private List<Fingerprint> mEnrolledList;
+ private List<Fingerprint> mUnknownFingerprints = new ArrayList<>(); // list of fp to delete
+
+ public InternalEnumerateClient(Context context, DaemonWrapper daemon, long halDeviceId,
+ IBinder token, ServiceListener listener, int groupId, int userId,
+ boolean restricted, String owner, List<Fingerprint> enrolledList) {
+ super(context, daemon, halDeviceId, token, listener, groupId, userId, restricted,
+ owner);
+ mEnrolledList = enrolledList;
+ }
+
+ private void handleEnumeratedFingerprint(
+ BiometricAuthenticator.Identifier identifier, int remaining) {
+ boolean matched = false;
+ for (int i = 0; i < mEnrolledList.size(); i++) {
+ if (mEnrolledList.get(i).getBiometricId() == identifier.getBiometricId()) {
+ mEnrolledList.remove(i);
+ matched = true;
+ break;
+ }
+ }
+
+ // fingerId 0 means no fingerprints are in hardware
+ if (!matched && identifier.getBiometricId() != 0) {
+ mUnknownFingerprints.add((Fingerprint) identifier);
+ }
+ }
+
+ private void doFingerprintCleanup() {
+ if (mEnrolledList == null) {
+ return;
+ }
+
+ for (Fingerprint f : mEnrolledList) {
+ Slog.e(TAG, "doFingerprintCleanup(): Removing dangling enrolled fingerprint: "
+ + f.getName() + " " + f.getBiometricId() + " " + f.getGroupId()
+ + " " + f.getDeviceId());
+ FingerprintUtils.getInstance().removeBiometricForUser(getContext(),
+ getTargetUserId(), f.getBiometricId());
+ }
+ mEnrolledList.clear();
+ }
+
+ public List<Fingerprint> getUnknownFingerprints() {
+ return mUnknownFingerprints;
+ }
+
+ @Override
+ public boolean onEnumerationResult(BiometricAuthenticator.Identifier identifier,
+ int remaining) {
+ handleEnumeratedFingerprint(identifier, remaining);
+ if (remaining == 0) {
+ doFingerprintCleanup();
+ }
+ return remaining == 0;
+ }
+ }
+
+ /**
+ * An internal class to help clean up unknown fingerprints in hardware and software.
+ */
+ private final class InternalRemovalClient extends BiometricService.RemovalClientImpl {
+ public InternalRemovalClient(Context context,
+ DaemonWrapper daemon, long halDeviceId, IBinder token,
+ ServiceListener listener, int fingerId, int groupId, int userId, boolean restricted,
+ String owner) {
+ super(context, daemon, halDeviceId, token, listener, fingerId, groupId, userId,
+ restricted,
+ owner);
+ }
+ }
+
+ private final FingerprintMetrics mFingerprintMetrics = new FingerprintMetrics();
+ private final CopyOnWriteArrayList<IFingerprintClientActiveCallback> mClientActiveCallbacks =
+ new CopyOnWriteArrayList<>();
+
+ @GuardedBy("this")
+ private IBiometricsFingerprint mDaemon;
+
+ private long mHalDeviceId;
+ private IStatusBarService mStatusBarService;
+ private IBinder mToken = new Binder(); // used for internal FingerprintService enumeration
+ private ArrayList<UserFingerprint> mUnknownFingerprints = new ArrayList<>(); // hw fingerprints
+
+ /**
+ * Receives callbacks from the HAL.
+ */
+ private IBiometricsFingerprintClientCallback mDaemonCallback =
+ new IBiometricsFingerprintClientCallback.Stub() {
+ @Override
+ public void onEnrollResult(final long deviceId, final int fingerId, final int groupId,
+ final int remaining) {
+ mHandler.post(() -> {
+ final Fingerprint fingerprint =
+ new Fingerprint(getBiometricUtils().getUniqueName(getContext(), groupId),
+ groupId, fingerId, deviceId);
+ FingerprintService.super.handleEnrollResult(fingerprint, remaining);
+ });
+ }
+
+ @Override
+ public void onAcquired(final long deviceId, final int acquiredInfo, final int vendorCode) {
+ mHandler.post(() -> {
+ FingerprintService.super.handleAcquired(deviceId, acquiredInfo, vendorCode);
+ });
+ }
+
+ @Override
+ public void onAuthenticated(final long deviceId, final int fingerId, final int groupId,
+ ArrayList<Byte> token) {
+ mHandler.post(() -> {
+ FingerprintService.super.handleAuthenticated(deviceId, fingerId, groupId, token);
+ });
+ }
+
+ @Override
+ public void onError(final long deviceId, final int error, final int vendorCode) {
+ mHandler.post(() -> {
+ ClientMonitor client = getCurrentClient();
+ if (client instanceof InternalRemovalClient
+ || client instanceof InternalEnumerateClient) {
+ clearEnumerateState();
+ }
+ FingerprintService.super.handleError(deviceId, error, vendorCode);
+
+ // TODO: this chunk of code should be common to all biometric services
+ if (error == BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE) {
+ // If we get HW_UNAVAILABLE, try to connect again later...
+ Slog.w(TAG, "Got ERROR_HW_UNAVAILABLE; try reconnecting next client.");
+ synchronized (this) {
+ mDaemon = null;
+ mHalDeviceId = 0;
+ mCurrentUserId = UserHandle.USER_NULL;
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onRemoved(final long deviceId, final int fingerId, final int groupId,
+ final int remaining) {
+ mHandler.post(() -> {
+ ClientMonitor client = getCurrentClient();
+ final Fingerprint fp = new Fingerprint("", groupId, fingerId, deviceId);
+ FingerprintService.super.handleRemoved(fp, remaining);
+ if (client instanceof InternalRemovalClient && !mUnknownFingerprints.isEmpty()) {
+ cleanupUnknownFingerprints();
+ } else if (client instanceof InternalRemovalClient){
+ clearEnumerateState();
+ }
+ });
+ }
+
+ @Override
+ public void onEnumerate(final long deviceId, final int fingerId, final int groupId,
+ final int remaining) {
+ mHandler.post(() -> {
+ // TODO: factor out common enumerate logic if possible
+ final Fingerprint fp = new Fingerprint("", groupId, fingerId, deviceId);
+ FingerprintService.this.handleEnumerate(fp, remaining);
+ });
+
+ }
+ };
+
+ /**
+ * Wraps the HAL-specific code and is passed to the ClientMonitor implementations so that they
+ * can be shared between the multiple biometric services.
+ */
+ private final DaemonWrapper mDaemonWrapper = new DaemonWrapper() {
+ @Override
+ public int authenticate(long operationId, int groupId) throws RemoteException {
+ IBiometricsFingerprint daemon = getFingerprintDaemon();
+ if (daemon == null) {
+ Slog.w(TAG, "authenticate(): no fingerprint HAL!");
+ return ERROR_ESRCH;
+ }
+ return daemon.authenticate(operationId, groupId);
+ }
+
+ @Override
+ public int cancel() throws RemoteException {
+ IBiometricsFingerprint daemon = getFingerprintDaemon();
+ if (daemon == null) {
+ Slog.w(TAG, "cancel(): no fingerprint HAL!");
+ return ERROR_ESRCH;
+ }
+ return daemon.cancel();
+ }
+
+ @Override
+ public int remove(int groupId, int biometricId) throws RemoteException {
+ IBiometricsFingerprint daemon = getFingerprintDaemon();
+ if (daemon == null) {
+ Slog.w(TAG, "remove(): no fingerprint HAL!");
+ return ERROR_ESRCH;
+ }
+ return daemon.remove(groupId, biometricId);
+ }
+
+ @Override
+ public int enumerate() throws RemoteException {
+ IBiometricsFingerprint daemon = getFingerprintDaemon();
+ if (daemon == null) {
+ Slog.w(TAG, "enumerate(): no fingerprint HAL!");
+ return ERROR_ESRCH;
+ }
+ return daemon.enumerate();
+ }
+
+ @Override
+ public int enroll(byte[] cryptoToken, int groupId, int timeout) throws RemoteException {
+ IBiometricsFingerprint daemon = getFingerprintDaemon();
+ if (daemon == null) {
+ Slog.w(TAG, "enroll(): no fingerprint HAL!");
+ return ERROR_ESRCH;
+ }
+ return daemon.enroll(cryptoToken, groupId, timeout);
+ }
+ };
+
+ public FingerprintService(Context context) {
+ super(context);
+ // TODO: can this be retrieved from AuthenticationClient, or BiometricService?
+ mStatusBarService = IStatusBarService.Stub.asInterface(
+ ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
+ SystemServerInitThreadPool.get().submit(this::getFingerprintDaemon, TAG + ".onStart");
+ }
+
+ @Override
+ protected String getTag() {
+ return TAG;
+ }
+
+ @Override
+ protected BiometricUtils getBiometricUtils() {
+ return FingerprintUtils.getInstance();
+ }
+
+ @Override
+ protected int getFailedAttemptsLockoutTimed() {
+ return MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED;
+ }
+
+ @Override
+ protected int getFailedAttemptsLockoutPermanent() {
+ return MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT;
+ }
+
+ @Override
+ protected Metrics getMetrics() {
+ return mFingerprintMetrics;
+ }
+
+ @Override
+ protected boolean hasReachedEnrollmentLimit(int userId) {
+ final int limit = getContext().getResources().getInteger(
+ com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser);
+ final int enrolled = FingerprintService.this.getEnrolledFingerprints(userId).size();
+ if (enrolled >= limit) {
+ Slog.w(TAG, "Too many fingerprints registered");
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ protected void updateActiveGroup(int userId, String clientPackage) {
+ IBiometricsFingerprint daemon = getFingerprintDaemon();
+
+ if (daemon != null) {
+ try {
+ userId = getUserOrWorkProfileId(clientPackage, userId);
+ if (userId != mCurrentUserId) {
+ int firstSdkInt = Build.VERSION.FIRST_SDK_INT;
+ if (firstSdkInt < Build.VERSION_CODES.BASE) {
+ Slog.e(TAG, "First SDK version " + firstSdkInt + " is invalid; must be " +
+ "at least VERSION_CODES.BASE");
+ }
+ File baseDir;
+ if (firstSdkInt <= Build.VERSION_CODES.O_MR1) {
+ baseDir = Environment.getUserSystemDirectory(userId);
+ } else {
+ baseDir = Environment.getDataVendorDeDirectory(userId);
+ }
+
+ File fpDir = new File(baseDir, FP_DATA_DIR);
+ if (!fpDir.exists()) {
+ if (!fpDir.mkdir()) {
+ Slog.v(TAG, "Cannot make directory: " + fpDir.getAbsolutePath());
+ return;
+ }
+ // Calling mkdir() from this process will create a directory with our
+ // permissions (inherited from the containing dir). This command fixes
+ // the label.
+ if (!SELinux.restorecon(fpDir)) {
+ Slog.w(TAG, "Restorecons failed. Directory will have wrong label.");
+ return;
+ }
+ }
+
+ daemon.setActiveGroup(userId, fpDir.getAbsolutePath());
+ mCurrentUserId = userId;
+ }
+ mAuthenticatorIds.put(userId,
+ hasEnrolledBiometrics(userId) ? daemon.getAuthenticatorId() : 0L);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to setActiveGroup():", e);
+ }
+ }
+ }
+
+ @Override
+ protected String getLockoutResetIntent() {
+ return ACTION_LOCKOUT_RESET;
+ }
+
+ @Override
+ protected String getLockoutBroadcastPermission() {
+ return RESET_FINGERPRINT_LOCKOUT;
+ }
+
+ @Override
+ protected long getHalDeviceId() {
+ return mHalDeviceId;
+ }
+
+ @Override
+ protected void handleUserSwitching(int userId) {
+ if (getCurrentClient() instanceof InternalRemovalClient
+ || getCurrentClient() instanceof InternalEnumerateClient) {
+ Slog.w(TAG, "User switched while performing cleanup");
+ removeClient(getCurrentClient());
+ clearEnumerateState();
+ }
+ updateActiveGroup(userId, null);
+ doFingerprintCleanupForUser(userId);
+ }
+
+
+ @Override
+ protected boolean hasEnrolledBiometrics(int userId) {
+ if (userId != UserHandle.getCallingUserId()) {
+ checkPermission(INTERACT_ACROSS_USERS);
+ }
+ return getBiometricUtils().getBiometricsForUser(getContext(), userId).size() > 0;
+ }
+
+ @Override
+ protected String getManageBiometricPermission() {
+ return MANAGE_FINGERPRINT;
+ }
+
+ @Override
+ protected void checkUseBiometricPermission() {
+ if (getContext().checkCallingPermission(USE_FINGERPRINT)
+ != PackageManager.PERMISSION_GRANTED) {
+ checkPermission(USE_BIOMETRIC);
+ }
+ }
+
+ @Override
+ protected int getAppOp() {
+ return AppOpsManager.OP_USE_FINGERPRINT;
+ }
+
+ @Override
+ protected void notifyClientActiveCallbacks(boolean isActive) {
+ List<IFingerprintClientActiveCallback> callbacks = mClientActiveCallbacks;
+ for (int i = 0; i < callbacks.size(); i++) {
+ try {
+ callbacks.get(i).onClientActiveChanged(isActive);
+ } catch (RemoteException re) {
+ // If the remote is dead, stop notifying it
+ mClientActiveCallbacks.remove(callbacks.get(i));
+ }
+ }
+ }
+
+ /** Gets the fingerprint daemon */
+ private synchronized IBiometricsFingerprint getFingerprintDaemon() {
+ if (mDaemon == null) {
+ Slog.v(TAG, "mDaemon was null, reconnect to fingerprint");
+ try {
+ mDaemon = IBiometricsFingerprint.getService();
+ } catch (java.util.NoSuchElementException e) {
+ // Service doesn't exist or cannot be opened. Logged below.
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to get biometric interface", e);
+ }
+ if (mDaemon == null) {
+ Slog.w(TAG, "fingerprint HIDL not available");
+ return null;
+ }
+
+ mDaemon.asBinder().linkToDeath(this, 0);
+
+ try {
+ mHalDeviceId = mDaemon.setNotify(mDaemonCallback);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to open fingerprint HAL", e);
+ mDaemon = null; // try again later!
+ }
+
+ if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
+ if (mHalDeviceId != 0) {
+ loadAuthenticatorIds();
+ updateActiveGroup(ActivityManager.getCurrentUser(), null);
+ doFingerprintCleanupForUser(ActivityManager.getCurrentUser());
+ } else {
+ Slog.w(TAG, "Failed to open Fingerprint HAL!");
+ MetricsLogger.count(getContext(), "fingerprintd_openhal_error", 1);
+ mDaemon = null;
+ }
+ }
+ return mDaemon;
+ }
+
+ /**
+ * This method should be called upon connection to the daemon, and when user switches.
+ * @param userId
+ */
+ private void doFingerprintCleanupForUser(int userId) {
+ if (CLEANUP_UNUSED_FP) {
+ enumerateUser(userId);
+ }
+ }
+
+ private void clearEnumerateState() {
+ if (DEBUG) Slog.v(TAG, "clearEnumerateState()");
+ mUnknownFingerprints.clear();
+ }
+
+ private void enumerateUser(int userId) {
+ if (DEBUG) Slog.v(TAG, "Enumerating user(" + userId + ")");
+
+ final boolean restricted = !hasPermission(MANAGE_FINGERPRINT);
+ final List<Fingerprint> enrolledList = getEnrolledFingerprints(userId);
+
+ InternalEnumerateClient client = new InternalEnumerateClient(getContext(), mDaemonWrapper,
+ mHalDeviceId, mToken, new ServiceListenerImpl(null), userId, userId, restricted,
+ getContext().getOpPackageName(), enrolledList);
+ enumerateInternal(client);
+ }
+
+ // Remove unknown fingerprints from hardware
+ private void cleanupUnknownFingerprints() {
+ if (!mUnknownFingerprints.isEmpty()) {
+ UserFingerprint uf = mUnknownFingerprints.get(0);
+ mUnknownFingerprints.remove(uf);
+ boolean restricted = !hasPermission(MANAGE_FINGERPRINT);
+ InternalRemovalClient client = new InternalRemovalClient(getContext(), mDaemonWrapper,
+ mHalDeviceId, mToken, new ServiceListenerImpl(null), uf.f.getBiometricId(),
+ uf.f.getGroupId(), uf.userId, restricted, getContext().getOpPackageName());
+ removeInternal(client);
+ } else {
+ clearEnumerateState();
+ }
+ }
+
+ private void handleEnumerate(Fingerprint fingerprint, int remaining) {
+ ClientMonitor client = getCurrentClient();
+
+ if ( !(client instanceof InternalRemovalClient) && !(client instanceof EnumerateClient) ) {
+ return;
+ }
+ client.onEnumerationResult(fingerprint, remaining);
+
+ // All fingerprints in hardware for this user were enumerated
+ if (remaining == 0) {
+ if (client instanceof InternalEnumerateClient) {
+ List<Fingerprint> unknownFingerprints =
+ ((InternalEnumerateClient) client).getUnknownFingerprints();
+
+ if (!unknownFingerprints.isEmpty()) {
+ Slog.w(TAG, "Adding " + unknownFingerprints.size() +
+ " fingerprints for deletion");
+ }
+ for (Fingerprint f : unknownFingerprints) {
+ mUnknownFingerprints.add(new UserFingerprint(f, client.getTargetUserId()));
+ }
+ removeClient(client);
+ cleanupUnknownFingerprints();
+ } else {
+ removeClient(client);
+ }
+ }
+ }
+
+ private long startPreEnroll(IBinder token) {
+ IBiometricsFingerprint daemon = getFingerprintDaemon();
+ if (daemon == null) {
+ Slog.w(TAG, "startPreEnroll: no fingerprint HAL!");
+ return 0;
+ }
+ try {
+ return daemon.preEnroll();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "startPreEnroll failed", e);
+ }
+ return 0;
+ }
+
+ private int startPostEnroll(IBinder token) {
+ IBiometricsFingerprint daemon = getFingerprintDaemon();
+ if (daemon == null) {
+ Slog.w(TAG, "startPostEnroll: no fingerprint HAL!");
+ return 0;
+ }
+ try {
+ return daemon.postEnroll();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "startPostEnroll failed", e);
+ }
+ return 0;
+ }
+
+ private List<Fingerprint> getEnrolledFingerprints(int userId) {
+ return getBiometricUtils().getBiometricsForUser(getContext(), userId);
+ }
+
+ private void dumpInternal(PrintWriter pw) {
+ JSONObject dump = new JSONObject();
+ try {
+ dump.put("service", "Fingerprint Manager");
+
+ JSONArray sets = new JSONArray();
+ for (UserInfo user : UserManager.get(getContext()).getUsers()) {
+ final int userId = user.getUserHandle().getIdentifier();
+ final int N = getBiometricUtils().getBiometricsForUser(getContext(), userId).size();
+ PerformanceStats stats = mPerformanceMap.get(userId);
+ PerformanceStats cryptoStats = mCryptoPerformanceMap.get(userId);
+ JSONObject set = new JSONObject();
+ set.put("id", userId);
+ set.put("count", N);
+ set.put("accept", (stats != null) ? stats.accept : 0);
+ set.put("reject", (stats != null) ? stats.reject : 0);
+ set.put("acquire", (stats != null) ? stats.acquire : 0);
+ set.put("lockout", (stats != null) ? stats.lockout : 0);
+ set.put("permanentLockout", (stats != null) ? stats.permanentLockout : 0);
+ // cryptoStats measures statistics about secure fingerprint transactions
+ // (e.g. to unlock password storage, make secure purchases, etc.)
+ set.put("acceptCrypto", (cryptoStats != null) ? cryptoStats.accept : 0);
+ set.put("rejectCrypto", (cryptoStats != null) ? cryptoStats.reject : 0);
+ set.put("acquireCrypto", (cryptoStats != null) ? cryptoStats.acquire : 0);
+ set.put("lockoutCrypto", (cryptoStats != null) ? cryptoStats.lockout : 0);
+ set.put("permanentLockoutCrypto",
+ (cryptoStats != null) ? cryptoStats.permanentLockout : 0);
+ sets.put(set);
+ }
+
+ dump.put("prints", sets);
+ } catch (JSONException e) {
+ Slog.e(TAG, "dump formatting failure", e);
+ }
+ pw.println(dump);
+ }
+
+ private void dumpProto(FileDescriptor fd) {
+ final ProtoOutputStream proto = new ProtoOutputStream(fd);
+ for (UserInfo user : UserManager.get(getContext()).getUsers()) {
+ final int userId = user.getUserHandle().getIdentifier();
+
+ final long userToken = proto.start(FingerprintServiceDumpProto.USERS);
+
+ proto.write(FingerprintUserStatsProto.USER_ID, userId);
+ proto.write(FingerprintUserStatsProto.NUM_FINGERPRINTS,
+ getBiometricUtils().getBiometricsForUser(getContext(), userId).size());
+
+ // Normal fingerprint authentications (e.g. lockscreen)
+ final PerformanceStats normal = mPerformanceMap.get(userId);
+ if (normal != null) {
+ final long countsToken = proto.start(FingerprintUserStatsProto.NORMAL);
+ proto.write(PerformanceStatsProto.ACCEPT, normal.accept);
+ proto.write(PerformanceStatsProto.REJECT, normal.reject);
+ proto.write(PerformanceStatsProto.ACQUIRE, normal.acquire);
+ proto.write(PerformanceStatsProto.LOCKOUT, normal.lockout);
+ proto.write(PerformanceStatsProto.PERMANENT_LOCKOUT, normal.permanentLockout);
+ proto.end(countsToken);
+ }
+
+ // Statistics about secure fingerprint transactions (e.g. to unlock password
+ // storage, make secure purchases, etc.)
+ final PerformanceStats crypto = mCryptoPerformanceMap.get(userId);
+ if (crypto != null) {
+ final long countsToken = proto.start(FingerprintUserStatsProto.CRYPTO);
+ proto.write(PerformanceStatsProto.ACCEPT, crypto.accept);
+ proto.write(PerformanceStatsProto.REJECT, crypto.reject);
+ proto.write(PerformanceStatsProto.ACQUIRE, crypto.acquire);
+ proto.write(PerformanceStatsProto.LOCKOUT, crypto.lockout);
+ proto.write(PerformanceStatsProto.PERMANENT_LOCKOUT, crypto.permanentLockout);
+ proto.end(countsToken);
+ }
+
+ proto.end(userToken);
+ }
+ proto.flush();
+ mPerformanceMap.clear();
+ mCryptoPerformanceMap.clear();
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintUserState.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintUserState.java
new file mode 100644
index 0000000..9e34ee8
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintUserState.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2015 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.fingerprint;
+
+import android.content.Context;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.fingerprint.Fingerprint;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.biometrics.common.BiometricUserState;
+
+import libcore.io.IoUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * Class managing the set of fingerprint per user across device reboots.
+ * @hide
+ */
+public class FingerprintUserState extends BiometricUserState {
+
+ private static final String TAG = "FingerprintState";
+ private static final String FINGERPRINT_FILE = "settings_fingerprint.xml";
+
+ private static final String TAG_FINGERPRINTS = "fingerprints";
+ private static final String TAG_FINGERPRINT = "fingerprint";
+ private static final String ATTR_NAME = "name";
+ private static final String ATTR_GROUP_ID = "groupId";
+ private static final String ATTR_FINGER_ID = "fingerId";
+ private static final String ATTR_DEVICE_ID = "deviceId";
+
+ public FingerprintUserState(Context context, int userId) {
+ super(context, userId);
+ }
+
+ @Override
+ protected String getBiometricsTag() {
+ return TAG_FINGERPRINTS;
+ }
+
+ @Override
+ protected String getBiometricFile() {
+ return FINGERPRINT_FILE;
+ }
+
+ @Override
+ protected int getNameTemplateResource() {
+ return com.android.internal.R.string.fingerprint_name_template;
+ }
+
+ @Override
+ public void addBiometric(BiometricAuthenticator.Identifier identifier) {
+ if (identifier instanceof Fingerprint) {
+ super.addBiometric(identifier);
+ } else {
+ Slog.w(TAG, "Attempted to add non-fingerprint identifier");
+ }
+ }
+
+ @Override
+ protected ArrayList getCopy(ArrayList array) {
+ ArrayList<Fingerprint> result = new ArrayList<>();
+ for (int i = 0; i < array.size(); i++) {
+ Fingerprint fp = (Fingerprint) array.get(i);
+ result.add(new Fingerprint(fp.getName(), fp.getGroupId(), fp.getBiometricId(),
+ fp.getDeviceId()));
+ }
+ return result;
+ }
+
+ @Override
+ protected void doWriteState() {
+ AtomicFile destination = new AtomicFile(mFile);
+
+ ArrayList<Fingerprint> fingerprints;
+
+ synchronized (this) {
+ fingerprints = getCopy(mBiometrics);
+ }
+
+ FileOutputStream out = null;
+ try {
+ out = destination.startWrite();
+
+ XmlSerializer serializer = Xml.newSerializer();
+ serializer.setOutput(out, "utf-8");
+ serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+ serializer.startDocument(null, true);
+ serializer.startTag(null, TAG_FINGERPRINTS);
+
+ final int count = fingerprints.size();
+ for (int i = 0; i < count; i++) {
+ Fingerprint fp = fingerprints.get(i);
+ serializer.startTag(null, TAG_FINGERPRINT);
+ serializer.attribute(null, ATTR_FINGER_ID, Integer.toString(fp.getBiometricId()));
+ serializer.attribute(null, ATTR_NAME, fp.getName().toString());
+ serializer.attribute(null, ATTR_GROUP_ID, Integer.toString(fp.getGroupId()));
+ serializer.attribute(null, ATTR_DEVICE_ID, Long.toString(fp.getDeviceId()));
+ serializer.endTag(null, TAG_FINGERPRINT);
+ }
+
+ serializer.endTag(null, TAG_FINGERPRINTS);
+ serializer.endDocument();
+ destination.finishWrite(out);
+
+ // Any error while writing is fatal.
+ } catch (Throwable t) {
+ Slog.wtf(TAG, "Failed to write settings, restoring backup", t);
+ destination.failWrite(out);
+ throw new IllegalStateException("Failed to write fingerprints", t);
+ } finally {
+ IoUtils.closeQuietly(out);
+ }
+ }
+
+ @GuardedBy("this")
+ @Override
+ protected void parseBiometricsLocked(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+
+ final int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals(TAG_FINGERPRINT)) {
+ String name = parser.getAttributeValue(null, ATTR_NAME);
+ String groupId = parser.getAttributeValue(null, ATTR_GROUP_ID);
+ String fingerId = parser.getAttributeValue(null, ATTR_FINGER_ID);
+ String deviceId = parser.getAttributeValue(null, ATTR_DEVICE_ID);
+ mBiometrics.add(new Fingerprint(name, Integer.parseInt(groupId),
+ Integer.parseInt(fingerId), Long.parseLong(deviceId)));
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintUtils.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintUtils.java
new file mode 100644
index 0000000..41216e9
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintUtils.java
@@ -0,0 +1,95 @@
+/**
+ * Copyright (C) 2015 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.fingerprint;
+
+import android.content.Context;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.fingerprint.Fingerprint;
+import android.text.TextUtils;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.biometrics.common.BiometricUtils;
+
+import java.util.List;
+
+/**
+ * Utility class for dealing with fingerprints and fingerprint settings.
+ */
+public class FingerprintUtils implements BiometricUtils {
+
+ private static final Object sInstanceLock = new Object();
+ private static FingerprintUtils sInstance;
+
+ @GuardedBy("this")
+ private final SparseArray<FingerprintUserState> mUsers = new SparseArray<>();
+
+ public static FingerprintUtils getInstance() {
+ synchronized (sInstanceLock) {
+ if (sInstance == null) {
+ sInstance = new FingerprintUtils();
+ }
+ }
+ return sInstance;
+ }
+
+ private FingerprintUtils() {
+ }
+
+ @Override
+ public List<Fingerprint> getBiometricsForUser(Context ctx, int userId) {
+ return getStateForUser(ctx, userId).getBiometrics();
+ }
+
+ @Override
+ public void addBiometricForUser(Context context, int userId,
+ BiometricAuthenticator.Identifier identifier) {
+ getStateForUser(context, userId).addBiometric(identifier);
+ }
+
+ @Override
+ public void removeBiometricForUser(Context context, int userId, int fingerId) {
+ getStateForUser(context, userId).removeBiometric(fingerId);
+ }
+
+ @Override
+ public void renameBiometricForUser(Context context, int userId, int fingerId,
+ CharSequence name) {
+ if (TextUtils.isEmpty(name)) {
+ // Don't do the rename if it's empty
+ return;
+ }
+ getStateForUser(context, userId).renameBiometric(fingerId, name);
+ }
+
+ @Override
+ public CharSequence getUniqueName(Context context, int userId) {
+ return getStateForUser(context, userId).getUniqueName();
+ }
+
+ private FingerprintUserState getStateForUser(Context ctx, int userId) {
+ synchronized (this) {
+ FingerprintUserState state = mUsers.get(userId);
+ if (state == null) {
+ state = new FingerprintUserState(ctx, userId);
+ mUsers.put(userId, state);
+ }
+ return state;
+ }
+ }
+}
+
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index df6a6f8..5105941 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -1350,8 +1350,11 @@
// do not currently know how to watch for changes in DUN settings.
maybeUpdateConfiguration();
- final NetworkState ns = mUpstreamNetworkMonitor.selectPreferredUpstreamType(
- mConfig.preferredUpstreamIfaceTypes);
+ final TetheringConfiguration config = mConfig;
+ final NetworkState ns = (config.chooseUpstreamAutomatically)
+ ? mUpstreamNetworkMonitor.getCurrentPreferredUpstream()
+ : mUpstreamNetworkMonitor.selectPreferredUpstreamType(
+ config.preferredUpstreamIfaceTypes);
if (ns == null) {
if (tryCell) {
mUpstreamNetworkMonitor.registerMobileNetworkRequest();
@@ -1380,9 +1383,7 @@
}
notifyDownstreamsOfNewUpstreamIface(ifaces);
if (ns != null && pertainsToCurrentUpstream(ns)) {
- // If we already have NetworkState for this network examine
- // it immediately, because there likely will be no second
- // EVENT_ON_AVAILABLE (it was already received).
+ // If we already have NetworkState for this network update it immediately.
handleNewUpstreamNetworkState(ns);
} else if (mCurrentUpstreamIfaceSet == null) {
// There are no available upstream networks.
@@ -1498,15 +1499,6 @@
}
switch (arg1) {
- case UpstreamNetworkMonitor.EVENT_ON_AVAILABLE:
- // The default network changed, or DUN connected
- // before this callback was processed. Updates
- // for the current NetworkCapabilities and
- // LinkProperties have been requested (default
- // request) or are being sent shortly (DUN). Do
- // nothing until they arrive; if no updates
- // arrive there's nothing to do.
- break;
case UpstreamNetworkMonitor.EVENT_ON_CAPABILITIES:
handleNewUpstreamNetworkState(ns);
break;
@@ -1539,7 +1531,7 @@
}
mSimChange.startListening();
- mUpstreamNetworkMonitor.start();
+ mUpstreamNetworkMonitor.start(mDeps.getDefaultNetworkRequest());
// TODO: De-duplicate with updateUpstreamWanted() below.
if (upstreamWanted()) {
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
index 454c579..dd9fe05 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -27,6 +27,7 @@
import static com.android.internal.R.array.config_tether_usb_regexs;
import static com.android.internal.R.array.config_tether_upstream_types;
import static com.android.internal.R.array.config_tether_wifi_regexs;
+import static com.android.internal.R.bool.config_tether_upstream_automatic;
import static com.android.internal.R.string.config_mobile_hotspot_provision_app_no_ui;
import android.content.Context;
@@ -86,6 +87,7 @@
public final String[] tetherableBluetoothRegexs;
public final int dunCheck;
public final boolean isDunRequired;
+ public final boolean chooseUpstreamAutomatically;
public final Collection<Integer> preferredUpstreamIfaceTypes;
public final String[] dhcpRanges;
public final String[] defaultIPv4DNS;
@@ -106,6 +108,7 @@
dunCheck = checkDunRequired(ctx);
configLog.log("DUN check returned: " + dunCheckString(dunCheck));
+ chooseUpstreamAutomatically = getResourceBoolean(ctx, config_tether_upstream_automatic);
preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(ctx, dunCheck);
isDunRequired = preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN);
@@ -142,6 +145,8 @@
pw.print("isDunRequired: ");
pw.println(isDunRequired);
+ pw.print("chooseUpstreamAutomatically: ");
+ pw.println(chooseUpstreamAutomatically);
dumpStringArray(pw, "preferredUpstreamIfaceTypes",
preferredUpstreamNames(preferredUpstreamIfaceTypes));
@@ -160,6 +165,7 @@
sj.add(String.format("tetherableBluetoothRegexs:%s",
makeString(tetherableBluetoothRegexs)));
sj.add(String.format("isDunRequired:%s", isDunRequired));
+ sj.add(String.format("chooseUpstreamAutomatically:%s", chooseUpstreamAutomatically));
sj.add(String.format("preferredUpstreamIfaceTypes:%s",
makeString(preferredUpstreamNames(preferredUpstreamIfaceTypes))));
sj.add(String.format("provisioningApp:%s", makeString(provisioningApp)));
@@ -286,6 +292,14 @@
}
}
+ private static boolean getResourceBoolean(Context ctx, int resId) {
+ try {
+ return ctx.getResources().getBoolean(resId);
+ } catch (Resources.NotFoundException e404) {
+ return false;
+ }
+ }
+
private static String[] getResourceStringArray(Context ctx, int resId) {
try {
final String[] strArray = ctx.getResources().getStringArray(resId);
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
index 0ac7a36..605ee9c 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.net.INetd;
+import android.net.NetworkRequest;
import android.net.ip.RouterAdvertisementDaemon;
import android.net.util.InterfaceParams;
import android.net.util.NetdService;
@@ -64,4 +65,8 @@
public boolean isTetheringSupported() {
return true;
}
+
+ public NetworkRequest getDefaultNetworkRequest() {
+ return null;
+ }
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
index 3413291..f488be7 100644
--- a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
@@ -20,6 +20,9 @@
import static android.net.ConnectivityManager.TYPE_NONE;
import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import android.content.Context;
import android.os.Handler;
@@ -74,14 +77,13 @@
private static final boolean DBG = false;
private static final boolean VDBG = false;
- public static final int EVENT_ON_AVAILABLE = 1;
- public static final int EVENT_ON_CAPABILITIES = 2;
- public static final int EVENT_ON_LINKPROPERTIES = 3;
- public static final int EVENT_ON_LOST = 4;
+ public static final int EVENT_ON_CAPABILITIES = 1;
+ public static final int EVENT_ON_LINKPROPERTIES = 2;
+ public static final int EVENT_ON_LOST = 3;
public static final int NOTIFY_LOCAL_PREFIXES = 10;
private static final int CALLBACK_LISTEN_ALL = 1;
- private static final int CALLBACK_TRACK_DEFAULT = 2;
+ private static final int CALLBACK_DEFAULT_INTERNET = 2;
private static final int CALLBACK_MOBILE_REQUEST = 3;
private final Context mContext;
@@ -117,7 +119,7 @@
mCM = cm;
}
- public void start() {
+ public void start(NetworkRequest defaultNetworkRequest) {
stop();
final NetworkRequest listenAllRequest = new NetworkRequest.Builder()
@@ -125,8 +127,16 @@
mListenAllCallback = new UpstreamNetworkCallback(CALLBACK_LISTEN_ALL);
cm().registerNetworkCallback(listenAllRequest, mListenAllCallback, mHandler);
- mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_TRACK_DEFAULT);
- cm().registerDefaultNetworkCallback(mDefaultNetworkCallback, mHandler);
+ if (defaultNetworkRequest != null) {
+ // This is not really a "request", just a way of tracking the system default network.
+ // It's guaranteed not to actually bring up any networks because it's the same request
+ // as the ConnectivityService default request, and thus shares fate with it. We can't
+ // use registerDefaultNetworkCallback because it will not track the system default
+ // network if there is a VPN that applies to our UID.
+ final NetworkRequest trackDefaultRequest = new NetworkRequest(defaultNetworkRequest);
+ mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_DEFAULT_INTERNET);
+ cm().requestNetwork(trackDefaultRequest, mDefaultNetworkCallback, mHandler);
+ }
}
public void stop() {
@@ -225,6 +235,20 @@
return typeStatePair.ns;
}
+ // Returns null if no current upstream available.
+ public NetworkState getCurrentPreferredUpstream() {
+ final NetworkState dfltState = (mDefaultInternetNetwork != null)
+ ? mNetworkMap.get(mDefaultInternetNetwork)
+ : null;
+ if (!mDunRequired) return dfltState;
+
+ if (isNetworkUsableAndNotCellular(dfltState)) return dfltState;
+
+ // Find a DUN network. Note that code in Tethering causes a DUN request
+ // to be filed, but this might be moved into this class in future.
+ return findFirstDunNetwork(mNetworkMap.values());
+ }
+
public void setCurrentUpstream(Network upstream) {
mTetheringUpstreamNetwork = upstream;
}
@@ -233,72 +257,16 @@
return (Set<IpPrefix>) mLocalPrefixes.clone();
}
- private void handleAvailable(int callbackType, Network network) {
- if (VDBG) Log.d(TAG, "EVENT_ON_AVAILABLE for " + network);
+ private void handleAvailable(Network network) {
+ if (mNetworkMap.containsKey(network)) return;
- if (!mNetworkMap.containsKey(network)) {
- mNetworkMap.put(network,
- new NetworkState(null, null, null, network, null, null));
- }
-
- // Always request whatever extra information we can, in case this
- // was already up when start() was called, in which case we would
- // not have been notified of any information that had not changed.
- switch (callbackType) {
- case CALLBACK_LISTEN_ALL:
- break;
-
- case CALLBACK_TRACK_DEFAULT:
- if (mDefaultNetworkCallback == null) {
- // The callback was unregistered in the interval between
- // ConnectivityService enqueueing onAvailable() and our
- // handling of it here on the mHandler thread.
- //
- // Clean-up of this network entry is deferred to the
- // handling of onLost() by other callbacks.
- //
- // These request*() calls can be deleted post oag/339444.
- return;
- }
- mDefaultInternetNetwork = network;
- break;
-
- case CALLBACK_MOBILE_REQUEST:
- if (mMobileNetworkCallback == null) {
- // The callback was unregistered in the interval between
- // ConnectivityService enqueueing onAvailable() and our
- // handling of it here on the mHandler thread.
- //
- // Clean-up of this network entry is deferred to the
- // handling of onLost() by other callbacks.
- return;
- }
- break;
- }
-
- // Requesting updates for mListenAllCallback is not currently possible
- // because it's a "listen". Two possible solutions to getting updates
- // about networks without waiting for a change (which might never come)
- // are:
- //
- // [1] extend request{NetworkCapabilities,LinkProperties}() to
- // take a Network argument and have ConnectivityService do
- // what's required (if the network satisfies the request)
- //
- // [2] explicitly file a NetworkRequest for each connectivity type
- // listed as a preferred upstream and wait for these callbacks
- // to be notified (requires tracking many more callbacks).
- //
- // Until this is addressed, networks that exist prior to the "listen"
- // registration and which do not subsequently change will not cause
- // us to learn their NetworkCapabilities nor their LinkProperties.
-
- // TODO: If sufficient information is available to select a more
- // preferable upstream, do so now and notify the target.
- notifyTarget(EVENT_ON_AVAILABLE, network);
+ if (VDBG) Log.d(TAG, "onAvailable for " + network);
+ mNetworkMap.put(network, new NetworkState(null, null, null, network, null, null));
}
- private void handleNetCap(Network network, NetworkCapabilities newNc) {
+ private void handleNetCap(int callbackType, Network network, NetworkCapabilities newNc) {
+ if (callbackType == CALLBACK_DEFAULT_INTERNET) mDefaultInternetNetwork = network;
+
final NetworkState prev = mNetworkMap.get(network);
if (prev == null || newNc.equals(prev.networkCapabilities)) {
// Ignore notifications about networks for which we have not yet
@@ -360,13 +328,17 @@
}
private void handleLost(int callbackType, Network network) {
- if (callbackType == CALLBACK_TRACK_DEFAULT) {
+ if (network.equals(mDefaultInternetNetwork)) {
mDefaultInternetNetwork = null;
- // Receiving onLost() for a default network does not necessarily
- // mean the network is gone. We wait for a separate notification
- // on either the LISTEN_ALL or MOBILE_REQUEST callbacks before
- // clearing all state.
- return;
+ // There are few TODOs within ConnectivityService's rematching code
+ // pertaining to spurious onLost() notifications.
+ //
+ // TODO: simplify this, probably if favor of code that:
+ // - selects a new upstream if mTetheringUpstreamNetwork has
+ // been lost (by any callback)
+ // - deletes the entry from the map only when the LISTEN_ALL
+ // callback gets notified.
+ if (callbackType == CALLBACK_DEFAULT_INTERNET) return;
}
if (!mNetworkMap.containsKey(network)) {
@@ -416,17 +388,19 @@
@Override
public void onAvailable(Network network) {
- handleAvailable(mCallbackType, network);
+ handleAvailable(network);
}
@Override
public void onCapabilitiesChanged(Network network, NetworkCapabilities newNc) {
- handleNetCap(network, newNc);
+ handleNetCap(mCallbackType, network, newNc);
}
@Override
public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
handleLinkProp(network, newLp);
+ // TODO(b/110335330): reduce the number of times this is called by
+ // only recomputing on the LISTEN_ALL callback.
recomputeLocalPrefixes();
}
@@ -443,6 +417,8 @@
@Override
public void onLost(Network network) {
handleLost(mCallbackType, network);
+ // TODO(b/110335330): reduce the number of times this is called by
+ // only recomputing on the LISTEN_ALL callback.
recomputeLocalPrefixes();
}
}
@@ -509,4 +485,31 @@
if (nc == null || !nc.hasSignalStrength()) return "unknown";
return Integer.toString(nc.getSignalStrength());
}
+
+ private static boolean isCellular(NetworkState ns) {
+ return (ns != null) && isCellular(ns.networkCapabilities);
+ }
+
+ private static boolean isCellular(NetworkCapabilities nc) {
+ return (nc != null) && nc.hasTransport(TRANSPORT_CELLULAR) &&
+ nc.hasCapability(NET_CAPABILITY_NOT_VPN);
+ }
+
+ private static boolean hasCapability(NetworkState ns, int netCap) {
+ return (ns != null) && (ns.networkCapabilities != null) &&
+ ns.networkCapabilities.hasCapability(netCap);
+ }
+
+ private static boolean isNetworkUsableAndNotCellular(NetworkState ns) {
+ return (ns != null) && (ns.networkCapabilities != null) && (ns.linkProperties != null) &&
+ !isCellular(ns.networkCapabilities);
+ }
+
+ private static NetworkState findFirstDunNetwork(Iterable<NetworkState> netStates) {
+ for (NetworkState ns : netStates) {
+ if (isCellular(ns) && hasCapability(ns, NET_CAPABILITY_DUN)) return ns;
+ }
+
+ return null;
+ }
}
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index 11f0701..811dc75 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -30,10 +30,6 @@
import android.content.SyncRequest;
import android.content.SyncStatusInfo;
import android.content.pm.PackageManager;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteException;
-import android.database.sqlite.SQLiteQueryBuilder;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
@@ -510,10 +506,6 @@
readAccountInfoLocked();
readStatusLocked();
readStatisticsLocked();
- readAndDeleteLegacyAccountInfoLocked();
- writeAccountInfoLocked();
- writeStatusLocked();
- writeStatisticsLocked();
if (mLogger.enabled()) {
final int size = mAuthorities.size();
@@ -1581,7 +1573,6 @@
readAccountInfoLocked();
readStatusLocked();
readStatisticsLocked();
- readAndDeleteLegacyAccountInfoLocked();
writeAccountInfoLocked();
writeStatusLocked();
writeStatisticsLocked();
@@ -1998,146 +1989,6 @@
}
}
- static int getIntColumn(Cursor c, String name) {
- return c.getInt(c.getColumnIndex(name));
- }
-
- static long getLongColumn(Cursor c, String name) {
- return c.getLong(c.getColumnIndex(name));
- }
-
- /**
- * TODO Remove it. It's super old code that was used to migrate the information from a sqlite
- * database that we used a long time ago, and is no longer relevant.
- */
- private void readAndDeleteLegacyAccountInfoLocked() {
- // Look for old database to initialize from.
- File file = mContext.getDatabasePath("syncmanager.db");
- if (!file.exists()) {
- return;
- }
- String path = file.getPath();
- SQLiteDatabase db = null;
- try {
- db = SQLiteDatabase.openDatabase(path, null,
- SQLiteDatabase.OPEN_READONLY);
- } catch (SQLiteException e) {
- }
-
- if (db != null) {
- final boolean hasType = db.getVersion() >= 11;
-
- // Copy in all of the status information, as well as accounts.
- if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
- Slog.v(TAG_FILE, "Reading legacy sync accounts db");
- }
- SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
- qb.setTables("stats, status");
- HashMap<String,String> map = new HashMap<String,String>();
- map.put("_id", "status._id as _id");
- map.put("account", "stats.account as account");
- if (hasType) {
- map.put("account_type", "stats.account_type as account_type");
- }
- map.put("authority", "stats.authority as authority");
- map.put("totalElapsedTime", "totalElapsedTime");
- map.put("numSyncs", "numSyncs");
- map.put("numSourceLocal", "numSourceLocal");
- map.put("numSourcePoll", "numSourcePoll");
- map.put("numSourceServer", "numSourceServer");
- map.put("numSourceUser", "numSourceUser");
- map.put("lastSuccessSource", "lastSuccessSource");
- map.put("lastSuccessTime", "lastSuccessTime");
- map.put("lastFailureSource", "lastFailureSource");
- map.put("lastFailureTime", "lastFailureTime");
- map.put("lastFailureMesg", "lastFailureMesg");
- map.put("pending", "pending");
- qb.setProjectionMap(map);
- qb.appendWhere("stats._id = status.stats_id");
- Cursor c = qb.query(db, null, null, null, null, null, null);
- while (c.moveToNext()) {
- String accountName = c.getString(c.getColumnIndex("account"));
- String accountType = hasType
- ? c.getString(c.getColumnIndex("account_type")) : null;
- if (accountType == null) {
- accountType = "com.google";
- }
- String authorityName = c.getString(c.getColumnIndex("authority"));
- AuthorityInfo authority =
- this.getOrCreateAuthorityLocked(
- new EndPoint(new Account(accountName, accountType),
- authorityName,
- 0 /* legacy is single-user */)
- , -1,
- false);
- if (authority != null) {
- int i = mSyncStatus.size();
- boolean found = false;
- SyncStatusInfo st = null;
- while (i > 0) {
- i--;
- st = mSyncStatus.valueAt(i);
- if (st.authorityId == authority.ident) {
- found = true;
- break;
- }
- }
- if (!found) {
- st = new SyncStatusInfo(authority.ident);
- mSyncStatus.put(authority.ident, st);
- }
- st.totalStats.totalElapsedTime = getLongColumn(c, "totalElapsedTime");
- st.totalStats.numSyncs = getIntColumn(c, "numSyncs");
- st.totalStats.numSourceLocal = getIntColumn(c, "numSourceLocal");
- st.totalStats.numSourcePoll = getIntColumn(c, "numSourcePoll");
- st.totalStats.numSourceOther = getIntColumn(c, "numSourceServer");
- st.totalStats.numSourceUser = getIntColumn(c, "numSourceUser");
- st.totalStats.numSourcePeriodic = 0;
- st.lastSuccessSource = getIntColumn(c, "lastSuccessSource");
- st.lastSuccessTime = getLongColumn(c, "lastSuccessTime");
- st.lastFailureSource = getIntColumn(c, "lastFailureSource");
- st.lastFailureTime = getLongColumn(c, "lastFailureTime");
- st.lastFailureMesg = c.getString(c.getColumnIndex("lastFailureMesg"));
- st.pending = getIntColumn(c, "pending") != 0;
- }
- }
-
- c.close();
-
- // Retrieve the settings.
- qb = new SQLiteQueryBuilder();
- qb.setTables("settings");
- c = qb.query(db, null, null, null, null, null, null);
- while (c.moveToNext()) {
- String name = c.getString(c.getColumnIndex("name"));
- String value = c.getString(c.getColumnIndex("value"));
- if (name == null) continue;
- if (name.equals("listen_for_tickles")) {
- setMasterSyncAutomatically(value == null || Boolean.parseBoolean(value), 0,
- ContentResolver.SYNC_EXEMPTION_NONE, SyncLogger.CALLING_UID_SELF);
- } else if (name.startsWith("sync_provider_")) {
- String provider = name.substring("sync_provider_".length(),
- name.length());
- int i = mAuthorities.size();
- while (i > 0) {
- i--;
- AuthorityInfo authority = mAuthorities.valueAt(i);
- if (authority.target.provider.equals(provider)) {
- authority.enabled = value == null || Boolean.parseBoolean(value);
- authority.syncable = 1;
- }
- }
- }
- }
-
- c.close();
-
- db.close();
-
- (new File(path)).delete();
- }
- }
-
public static final int STATUS_FILE_END = 0;
public static final int STATUS_FILE_ITEM = 100;
diff --git a/services/core/java/com/android/server/fingerprint/EnrollClient.java b/services/core/java/com/android/server/fingerprint/EnrollClient.java
deleted file mode 100644
index c9efcf2..0000000
--- a/services/core/java/com/android/server/fingerprint/EnrollClient.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/**
- * Copyright (C) 2016 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.fingerprint;
-
-import android.content.Context;
-import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
-import android.hardware.fingerprint.FingerprintManager;
-import android.hardware.fingerprint.IFingerprintServiceReceiver;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Slog;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-import java.util.Arrays;
-
-/**
- * A class to keep track of the enrollment state for a given client.
- */
-public abstract class EnrollClient extends ClientMonitor {
- private static final long MS_PER_SEC = 1000;
- private static final int ENROLLMENT_TIMEOUT_MS = 60 * 1000; // 1 minute
- private byte[] mCryptoToken;
-
- public EnrollClient(Context context, long halDeviceId, IBinder token,
- IFingerprintServiceReceiver receiver, int userId, int groupId, byte [] cryptoToken,
- boolean restricted, String owner) {
- super(context, halDeviceId, token, receiver, userId, groupId, restricted, owner);
- mCryptoToken = Arrays.copyOf(cryptoToken, cryptoToken.length);
- }
-
- @Override
- public boolean onEnrollResult(int fingerId, int groupId, int remaining) {
- if (groupId != getGroupId()) {
- Slog.w(TAG, "groupId != getGroupId(), groupId: " + groupId +
- " getGroupId():" + getGroupId());
- }
- if (remaining == 0) {
- FingerprintUtils.getInstance().addFingerprintForUser(getContext(), fingerId,
- getTargetUserId());
- }
- return sendEnrollResult(fingerId, groupId, remaining);
- }
-
- /*
- * @return true if we're done.
- */
- private boolean sendEnrollResult(int fpId, int groupId, int remaining) {
- IFingerprintServiceReceiver receiver = getReceiver();
- if (receiver == null)
- return true; // client not listening
-
- vibrateSuccess();
- MetricsLogger.action(getContext(), MetricsEvent.ACTION_FINGERPRINT_ENROLL);
- try {
- receiver.onEnrollResult(getHalDeviceId(), fpId, groupId, remaining);
- return remaining == 0;
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to notify EnrollResult:", e);
- return true;
- }
- }
-
- @Override
- public int start() {
- IBiometricsFingerprint daemon = getFingerprintDaemon();
- if (daemon == null) {
- Slog.w(TAG, "enroll: no fingerprint HAL!");
- return ERROR_ESRCH;
- }
- final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
- try {
- final int result = daemon.enroll(mCryptoToken, getGroupId(), timeout);
- if (result != 0) {
- Slog.w(TAG, "startEnroll failed, result=" + result);
- MetricsLogger.histogram(getContext(), "fingerprintd_enroll_start_error", result);
- onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
- return result;
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "startEnroll failed", e);
- }
- return 0; // success
- }
-
- @Override
- public int stop(boolean initiatedByClient) {
- if (mAlreadyCancelled) {
- Slog.w(TAG, "stopEnroll: already cancelled!");
- return 0;
- }
- IBiometricsFingerprint daemon = getFingerprintDaemon();
- if (daemon == null) {
- Slog.w(TAG, "stopEnrollment: no fingerprint HAL!");
- return ERROR_ESRCH;
- }
- try {
- final int result = daemon.cancel();
- if (result != 0) {
- Slog.w(TAG, "startEnrollCancel failed, result = " + result);
- return result;
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "stopEnrollment failed", e);
- }
- if (initiatedByClient) {
- onError(FingerprintManager.FINGERPRINT_ERROR_CANCELED, 0 /* vendorCode */);
- }
- mAlreadyCancelled = true;
- return 0;
- }
-
- @Override
- public boolean onRemoved(int fingerId, int groupId, int remaining) {
- if (DEBUG) Slog.w(TAG, "onRemoved() called for enroll!");
- return true; // Invalid for EnrollClient
- }
-
- @Override
- public boolean onEnumerationResult(int fingerId, int groupId, int remaining) {
- if (DEBUG) Slog.w(TAG, "onEnumerationResult() called for enroll!");
- return true; // Invalid for EnrollClient
- }
-
- @Override
- public boolean onAuthenticated(int fingerId, int groupId) {
- if (DEBUG) Slog.w(TAG, "onAuthenticated() called for enroll!");
- return true; // Invalid for EnrollClient
- }
-
-}
diff --git a/services/core/java/com/android/server/fingerprint/EnumerateClient.java b/services/core/java/com/android/server/fingerprint/EnumerateClient.java
deleted file mode 100644
index b6bbd1b..0000000
--- a/services/core/java/com/android/server/fingerprint/EnumerateClient.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/**
- * Copyright (C) 2016 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.fingerprint;
-
-import android.content.Context;
-import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
-import android.hardware.fingerprint.FingerprintManager;
-import android.hardware.fingerprint.IFingerprintServiceReceiver;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Slog;
-import com.android.internal.logging.MetricsLogger;
-
-/**
- * A class to keep track of the enumeration state for a given client.
- */
-public abstract class EnumerateClient extends ClientMonitor {
- public EnumerateClient(Context context, long halDeviceId, IBinder token,
- IFingerprintServiceReceiver receiver, int groupId, int userId,
- boolean restricted, String owner) {
- super(context, halDeviceId, token, receiver, userId, groupId, restricted, owner);
- }
-
- @Override
- public int start() {
- IBiometricsFingerprint daemon = getFingerprintDaemon();
- // The fingerprint template ids will be removed when we get confirmation from the HAL
- try {
- final int result = daemon.enumerate();
- if (result != 0) {
- Slog.w(TAG, "start enumerate for user " + getTargetUserId()
- + " failed, result=" + result);
- MetricsLogger.histogram(getContext(), "fingerprintd_enum_start_error", result);
- onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
- return result;
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "startEnumeration failed", e);
- }
- return 0;
- }
-
- @Override
- public int stop(boolean initiatedByClient) {
- if (mAlreadyCancelled) {
- Slog.w(TAG, "stopEnumerate: already cancelled!");
- return 0;
- }
- IBiometricsFingerprint daemon = getFingerprintDaemon();
- if (daemon == null) {
- Slog.w(TAG, "stopEnumeration: no fingerprint HAL!");
- return ERROR_ESRCH;
- }
- try {
- final int result = daemon.cancel();
- if (result != 0) {
- Slog.w(TAG, "stop enumeration failed, result=" + result);
- return result;
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "stopEnumeration failed", e);
- return ERROR_ESRCH;
- }
-
- // We don't actually stop enumerate, but inform the client that the cancel operation
- // succeeded so we can start the next operation.
- if (initiatedByClient) {
- onError(FingerprintManager.FINGERPRINT_ERROR_CANCELED, 0 /* vendorCode */);
- }
- mAlreadyCancelled = true;
- return 0; // success
- }
-
- @Override
- public boolean onEnumerationResult(int fingerId, int groupId, int remaining) {
- IFingerprintServiceReceiver receiver = getReceiver();
- if (receiver == null)
- return true; // client not listening
- try {
- receiver.onEnumerated(getHalDeviceId(), fingerId, groupId, remaining);
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to notify enumerated:", e);
- }
- return remaining == 0;
- }
-
- @Override
- public boolean onAuthenticated(int fingerId, int groupId) {
- if (DEBUG) Slog.w(TAG, "onAuthenticated() called for enumerate!");
- return true; // Invalid for Enumerate.
- }
-
- @Override
- public boolean onEnrollResult(int fingerId, int groupId, int rem) {
- if (DEBUG) Slog.w(TAG, "onEnrollResult() called for enumerate!");
- return true; // Invalid for Enumerate.
- }
-
- @Override
- public boolean onRemoved(int fingerId, int groupId, int remaining) {
- if (DEBUG) Slog.w(TAG, "onRemoved() called for enumerate!");
- return true; // Invalid for Enumerate.
- }
-}
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
deleted file mode 100644
index 8e77820..0000000
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ /dev/null
@@ -1,1595 +0,0 @@
-/*
- * Copyright (C) 2014 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.fingerprint;
-
-import static android.Manifest.permission.INTERACT_ACROSS_USERS;
-import static android.Manifest.permission.MANAGE_FINGERPRINT;
-import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT;
-import static android.Manifest.permission.USE_BIOMETRIC;
-import static android.Manifest.permission.USE_FINGERPRINT;
-import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
-
-import android.app.ActivityManager;
-import android.app.ActivityManager.RunningAppProcessInfo;
-import android.app.ActivityTaskManager;
-import android.app.AlarmManager;
-import android.app.AppOpsManager;
-import android.app.IActivityManager;
-import android.app.IActivityTaskManager;
-import android.app.PendingIntent;
-import android.app.SynchronousUserSwitchObserver;
-import android.app.TaskStackListener;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.pm.UserInfo;
-import android.hardware.biometrics.IBiometricPromptReceiver;
-import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
-import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprintClientCallback;
-import android.hardware.fingerprint.Fingerprint;
-import android.hardware.fingerprint.FingerprintManager;
-import android.hardware.fingerprint.IFingerprintClientActiveCallback;
-import android.hardware.fingerprint.IFingerprintService;
-import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
-import android.hardware.fingerprint.IFingerprintServiceReceiver;
-import android.os.Binder;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.DeadObjectException;
-import android.os.Environment;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.IHwBinder;
-import android.os.IRemoteCallback;
-import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
-import android.os.RemoteException;
-import android.os.SELinux;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.security.KeyStore;
-import android.util.Slog;
-import android.util.SparseBooleanArray;
-import android.util.SparseIntArray;
-import android.util.proto.ProtoOutputStream;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.statusbar.IStatusBarService;
-import com.android.internal.util.DumpUtils;
-import com.android.server.SystemServerInitThreadPool;
-import com.android.server.SystemService;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-/**
- * A service to manage multiple clients that want to access the fingerprint HAL API.
- * The service is responsible for maintaining a list of clients and dispatching all
- * fingerprint-related events.
- *
- * @hide
- */
-public class FingerprintService extends SystemService implements IHwBinder.DeathRecipient {
- static final String TAG = "FingerprintService";
- static final boolean DEBUG = true;
- private static final boolean CLEANUP_UNUSED_FP = true;
- private static final String FP_DATA_DIR = "fpdata";
- private static final int MSG_USER_SWITCHING = 10;
- private static final String ACTION_LOCKOUT_RESET =
- "com.android.server.fingerprint.ACTION_LOCKOUT_RESET";
- private static final String KEY_LOCKOUT_RESET_USER = "lockout_reset_user";
-
- private class PerformanceStats {
- int accept; // number of accepted fingerprints
- int reject; // number of rejected fingerprints
- int acquire; // total number of acquisitions. Should be >= accept+reject due to poor image
- // acquisition in some cases (too fast, too slow, dirty sensor, etc.)
- int lockout; // total number of lockouts
- int permanentLockout; // total number of permanent lockouts
- }
-
- private final ArrayList<FingerprintServiceLockoutResetMonitor> mLockoutMonitors =
- new ArrayList<>();
- private final CopyOnWriteArrayList<IFingerprintClientActiveCallback> mClientActiveCallbacks =
- new CopyOnWriteArrayList<>();
- private final Map<Integer, Long> mAuthenticatorIds =
- Collections.synchronizedMap(new HashMap<>());
- private final AppOpsManager mAppOps;
- private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30*1000;
- private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED = 5;
- private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT = 20;
-
- private static final long CANCEL_TIMEOUT_LIMIT = 3000; // max wait for onCancel() from HAL,in ms
- private final String mKeyguardPackage;
- private int mCurrentUserId = UserHandle.USER_NULL;
- private final FingerprintUtils mFingerprintUtils = FingerprintUtils.getInstance();
- private Context mContext;
- private long mHalDeviceId;
- private SparseBooleanArray mTimedLockoutCleared;
- private SparseIntArray mFailedAttempts;
- @GuardedBy("this")
- private IBiometricsFingerprint mDaemon;
- private IStatusBarService mStatusBarService;
- private final IActivityManager mActivityManager;
- private final IActivityTaskManager mActivityTaskManager;
- private final PowerManager mPowerManager;
- private final AlarmManager mAlarmManager;
- private final UserManager mUserManager;
- private ClientMonitor mCurrentClient;
- private ClientMonitor mPendingClient;
- private PerformanceStats mPerformanceStats;
-
- private IBinder mToken = new Binder(); // used for internal FingerprintService enumeration
- private ArrayList<UserFingerprint> mUnknownFingerprints = new ArrayList<>(); // hw fingerprints
-
- private class UserFingerprint {
- Fingerprint f;
- int userId;
- public UserFingerprint(Fingerprint f, int userId) {
- this.f = f;
- this.userId = userId;
- }
- }
-
- // Normal fingerprint authentications are tracked by mPerformanceMap.
- private HashMap<Integer, PerformanceStats> mPerformanceMap = new HashMap<>();
-
- // Transactions that make use of CryptoObjects are tracked by mCryptoPerformaceMap.
- private HashMap<Integer, PerformanceStats> mCryptoPerformanceMap = new HashMap<>();
-
- private Handler mHandler = new Handler() {
- @Override
- public void handleMessage(android.os.Message msg) {
- switch (msg.what) {
- case MSG_USER_SWITCHING:
- handleUserSwitching(msg.arg1);
- break;
-
- default:
- Slog.w(TAG, "Unknown message:" + msg.what);
- }
- }
- };
-
- private final BroadcastReceiver mLockoutReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (ACTION_LOCKOUT_RESET.equals(intent.getAction())) {
- final int user = intent.getIntExtra(KEY_LOCKOUT_RESET_USER, 0);
- resetFailedAttemptsForUser(false /* clearAttemptCounter */, user);
- }
- }
- };
-
- private final Runnable mResetFailedAttemptsForCurrentUserRunnable = new Runnable() {
- @Override
- public void run() {
- resetFailedAttemptsForUser(true /* clearAttemptCounter */,
- ActivityManager.getCurrentUser());
- }
- };
-
- private final Runnable mResetClientState = new Runnable() {
- @Override
- public void run() {
- // Warning: if we get here, the driver never confirmed our call to cancel the current
- // operation (authenticate, enroll, remove, enumerate, etc), which is
- // really bad. The result will be a 3-second delay in starting each new client.
- // If you see this on a device, make certain the driver notifies with
- // {@link FingerprintManager#FINGERPRINT_ERROR_CANCEL} in response to cancel()
- // once it has successfully switched to the IDLE state in the fingerprint HAL.
- // Additionally,{@link FingerprintManager#FINGERPRINT_ERROR_CANCEL} should only be sent
- // in response to an actual cancel() call.
- Slog.w(TAG, "Client "
- + (mCurrentClient != null ? mCurrentClient.getOwnerString() : "null")
- + " failed to respond to cancel, starting client "
- + (mPendingClient != null ? mPendingClient.getOwnerString() : "null"));
-
- mCurrentClient = null;
- startClient(mPendingClient, false);
- }
- };
-
- private final TaskStackListener mTaskStackListener = new TaskStackListener() {
- @Override
- public void onTaskStackChanged() {
- try {
- if (!(mCurrentClient instanceof AuthenticationClient)) {
- return;
- }
- final String currentClient = mCurrentClient.getOwnerString();
- if (isKeyguard(currentClient)) {
- return; // Keyguard is always allowed
- }
- List<ActivityManager.RunningTaskInfo> runningTasks =
- mActivityTaskManager.getTasks(1);
- if (!runningTasks.isEmpty()) {
- final String topPackage = runningTasks.get(0).topActivity.getPackageName();
- if (!topPackage.contentEquals(currentClient)) {
- Slog.e(TAG, "Stopping background authentication, top: " + topPackage
- + " currentClient: " + currentClient);
- mCurrentClient.stop(false /* initiatedByClient */);
- }
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to get running tasks", e);
- }
- }
- };
-
- public FingerprintService(Context context) {
- super(context);
- mContext = context;
- mKeyguardPackage = ComponentName.unflattenFromString(context.getResources().getString(
- com.android.internal.R.string.config_keyguardComponent)).getPackageName();
- mAppOps = context.getSystemService(AppOpsManager.class);
- mPowerManager = mContext.getSystemService(PowerManager.class);
- mAlarmManager = mContext.getSystemService(AlarmManager.class);
- mContext.registerReceiver(mLockoutReceiver, new IntentFilter(ACTION_LOCKOUT_RESET),
- RESET_FINGERPRINT_LOCKOUT, null /* handler */);
- mUserManager = UserManager.get(mContext);
- mTimedLockoutCleared = new SparseBooleanArray();
- mFailedAttempts = new SparseIntArray();
- mStatusBarService = IStatusBarService.Stub.asInterface(
- ServiceManager.getService(Context.STATUS_BAR_SERVICE));
- mActivityManager = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE))
- .getService();
- mActivityTaskManager = ((ActivityTaskManager) context.getSystemService(
- Context.ACTIVITY_TASK_SERVICE)).getService();
- }
-
- @Override
- public void serviceDied(long cookie) {
- Slog.v(TAG, "fingerprint HAL died");
- MetricsLogger.count(mContext, "fingerprintd_died", 1);
- handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE,
- 0 /*vendorCode */);
- }
-
- public synchronized IBiometricsFingerprint getFingerprintDaemon() {
- if (mDaemon == null) {
- Slog.v(TAG, "mDaemon was null, reconnect to fingerprint");
- try {
- mDaemon = IBiometricsFingerprint.getService();
- } catch (java.util.NoSuchElementException e) {
- // Service doesn't exist or cannot be opened. Logged below.
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to get biometric interface", e);
- }
- if (mDaemon == null) {
- Slog.w(TAG, "fingerprint HIDL not available");
- return null;
- }
-
- mDaemon.asBinder().linkToDeath(this, 0);
-
- try {
- mHalDeviceId = mDaemon.setNotify(mDaemonCallback);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to open fingerprint HAL", e);
- mDaemon = null; // try again later!
- }
-
- if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
- if (mHalDeviceId != 0) {
- loadAuthenticatorIds();
- updateActiveGroup(ActivityManager.getCurrentUser(), null);
- doFingerprintCleanupForUser(ActivityManager.getCurrentUser());
- } else {
- Slog.w(TAG, "Failed to open Fingerprint HAL!");
- MetricsLogger.count(mContext, "fingerprintd_openhal_error", 1);
- mDaemon = null;
- }
- }
- return mDaemon;
- }
-
- /** Populates existing authenticator ids. To be used only during the start of the service. */
- private void loadAuthenticatorIds() {
- // This operation can be expensive, so keep track of the elapsed time. Might need to move to
- // background if it takes too long.
- long t = System.currentTimeMillis();
- mAuthenticatorIds.clear();
- for (UserInfo user : UserManager.get(mContext).getUsers(true /* excludeDying */)) {
- int userId = getUserOrWorkProfileId(null, user.id);
- if (!mAuthenticatorIds.containsKey(userId)) {
- updateActiveGroup(userId, null);
- }
- }
-
- t = System.currentTimeMillis() - t;
- if (t > 1000) {
- Slog.w(TAG, "loadAuthenticatorIds() taking too long: " + t + "ms");
- }
- }
-
- /**
- * This method should be called upon connection to the daemon, and when user switches.
- * @param userId
- */
- private void doFingerprintCleanupForUser(int userId) {
- if (CLEANUP_UNUSED_FP) {
- enumerateUser(userId);
- }
- }
-
- private void clearEnumerateState() {
- if (DEBUG) Slog.v(TAG, "clearEnumerateState()");
- mUnknownFingerprints.clear();
- }
-
- private void enumerateUser(int userId) {
- if (DEBUG) Slog.v(TAG, "Enumerating user(" + userId + ")");
- boolean restricted = !hasPermission(MANAGE_FINGERPRINT);
- startEnumerate(mToken, userId, null, restricted, true /* internal */);
- }
-
- // Remove unknown fingerprints from hardware
- private void cleanupUnknownFingerprints() {
- if (!mUnknownFingerprints.isEmpty()) {
- UserFingerprint uf = mUnknownFingerprints.get(0);
- mUnknownFingerprints.remove(uf);
- boolean restricted = !hasPermission(MANAGE_FINGERPRINT);
- startRemove(mToken, uf.f.getFingerId(), uf.f.getGroupId(), uf.userId, null,
- restricted, true /* internal */);
- } else {
- clearEnumerateState();
- }
- }
-
- protected void handleEnumerate(long deviceId, int fingerId, int groupId, int remaining) {
- ClientMonitor client = mCurrentClient;
-
- if ( !(client instanceof InternalRemovalClient) && !(client instanceof EnumerateClient) ) {
- return;
- }
- client.onEnumerationResult(fingerId, groupId, remaining);
-
- // All fingerprints in hardware for this user were enumerated
- if (remaining == 0) {
- if (client instanceof InternalEnumerateClient) {
- List<Fingerprint> unknownFingerprints =
- ((InternalEnumerateClient) client).getUnknownFingerprints();
-
- if (!unknownFingerprints.isEmpty()) {
- Slog.w(TAG, "Adding " + unknownFingerprints.size() +
- " fingerprints for deletion");
- }
- for (Fingerprint f : unknownFingerprints) {
- mUnknownFingerprints.add(new UserFingerprint(f, client.getTargetUserId()));
- }
- removeClient(client);
- cleanupUnknownFingerprints();
- } else {
- removeClient(client);
- }
- }
- }
-
- protected void handleError(long deviceId, int error, int vendorCode) {
- ClientMonitor client = mCurrentClient;
- if (client instanceof InternalRemovalClient || client instanceof InternalEnumerateClient) {
- clearEnumerateState();
- }
- if (client != null && client.onError(error, vendorCode)) {
- removeClient(client);
- }
-
- if (DEBUG) Slog.v(TAG, "handleError(client="
- + (client != null ? client.getOwnerString() : "null") + ", error = " + error + ")");
- // This is the magic code that starts the next client when the old client finishes.
- if (error == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
- mHandler.removeCallbacks(mResetClientState);
- if (mPendingClient != null) {
- if (DEBUG) Slog.v(TAG, "start pending client " + mPendingClient.getOwnerString());
- startClient(mPendingClient, false);
- mPendingClient = null;
- }
- } else if (error == FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE) {
- // If we get HW_UNAVAILABLE, try to connect again later...
- Slog.w(TAG, "Got ERROR_HW_UNAVAILABLE; try reconnecting next client.");
- synchronized (this) {
- mDaemon = null;
- mHalDeviceId = 0;
- mCurrentUserId = UserHandle.USER_NULL;
- }
- }
- }
-
- protected void handleRemoved(long deviceId, int fingerId, int groupId, int remaining) {
- if (DEBUG) Slog.w(TAG, "Removed: fid=" + fingerId
- + ", gid=" + groupId
- + ", dev=" + deviceId
- + ", rem=" + remaining);
-
- ClientMonitor client = mCurrentClient;
- if (client != null && client.onRemoved(fingerId, groupId, remaining)) {
- removeClient(client);
- // When the last fingerprint of a group is removed, update the authenticator id
- if (!hasEnrolledFingerprints(groupId)) {
- updateActiveGroup(groupId, null);
- }
- }
- if (client instanceof InternalRemovalClient && !mUnknownFingerprints.isEmpty()) {
- cleanupUnknownFingerprints();
- } else if (client instanceof InternalRemovalClient){
- clearEnumerateState();
- }
- }
-
- protected void handleAuthenticated(long deviceId, int fingerId, int groupId,
- ArrayList<Byte> token) {
- ClientMonitor client = mCurrentClient;
- if (fingerId != 0) {
- // Ugh...
- final byte[] byteToken = new byte[token.size()];
- for (int i = 0; i < token.size(); i++) {
- byteToken[i] = token.get(i);
- }
- // Send to Keystore
- KeyStore.getInstance().addAuthToken(byteToken);
- }
- if (client != null && client.onAuthenticated(fingerId, groupId)) {
- removeClient(client);
- }
- if (fingerId != 0) {
- mPerformanceStats.accept++;
- } else {
- mPerformanceStats.reject++;
- }
- }
-
- protected void handleAcquired(long deviceId, int acquiredInfo, int vendorCode) {
- ClientMonitor client = mCurrentClient;
- if (client != null && client.onAcquired(acquiredInfo, vendorCode)) {
- removeClient(client);
- }
- if (mPerformanceStats != null && getLockoutMode() == AuthenticationClient.LOCKOUT_NONE
- && client instanceof AuthenticationClient) {
- // ignore enrollment acquisitions or acquisitions when we're locked out
- mPerformanceStats.acquire++;
- }
- }
-
- protected void handleEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
- ClientMonitor client = mCurrentClient;
- if (client != null && client.onEnrollResult(fingerId, groupId, remaining)) {
- removeClient(client);
- // When enrollment finishes, update this group's authenticator id, as the HAL has
- // already generated a new authenticator id when the new fingerprint is enrolled.
- updateActiveGroup(groupId, null);
- }
- }
-
- private void userActivity() {
- long now = SystemClock.uptimeMillis();
- mPowerManager.userActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
- }
-
- void handleUserSwitching(int userId) {
- if (mCurrentClient instanceof InternalRemovalClient
- || mCurrentClient instanceof InternalEnumerateClient) {
- Slog.w(TAG, "User switched while performing cleanup");
- removeClient(mCurrentClient);
- clearEnumerateState();
- }
- updateActiveGroup(userId, null);
- doFingerprintCleanupForUser(userId);
- }
-
- private void removeClient(ClientMonitor client) {
- if (client != null) {
- client.destroy();
- if (client != mCurrentClient && mCurrentClient != null) {
- Slog.w(TAG, "Unexpected client: " + client.getOwnerString() + "expected: "
- + mCurrentClient != null ? mCurrentClient.getOwnerString() : "null");
- }
- }
- if (mCurrentClient != null) {
- if (DEBUG) Slog.v(TAG, "Done with client: " + client.getOwnerString());
- mCurrentClient = null;
- }
- if (mPendingClient == null) {
- notifyClientActiveCallbacks(false);
- }
- }
-
- private int getLockoutMode() {
- final int currentUser = ActivityManager.getCurrentUser();
- final int failedAttempts = mFailedAttempts.get(currentUser, 0);
- if (failedAttempts >= MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT) {
- return AuthenticationClient.LOCKOUT_PERMANENT;
- } else if (failedAttempts > 0 &&
- mTimedLockoutCleared.get(currentUser, false) == false
- && (failedAttempts % MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED == 0)) {
- return AuthenticationClient.LOCKOUT_TIMED;
- }
- return AuthenticationClient.LOCKOUT_NONE;
- }
-
- private void scheduleLockoutResetForUser(int userId) {
- mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- SystemClock.elapsedRealtime() + FAIL_LOCKOUT_TIMEOUT_MS,
- getLockoutResetIntentForUser(userId));
- }
-
- private void cancelLockoutResetForUser(int userId) {
- mAlarmManager.cancel(getLockoutResetIntentForUser(userId));
- }
-
- private PendingIntent getLockoutResetIntentForUser(int userId) {
- return PendingIntent.getBroadcast(mContext, userId,
- new Intent(ACTION_LOCKOUT_RESET).putExtra(KEY_LOCKOUT_RESET_USER, userId),
- PendingIntent.FLAG_UPDATE_CURRENT);
- }
-
- public long startPreEnroll(IBinder token) {
- IBiometricsFingerprint daemon = getFingerprintDaemon();
- if (daemon == null) {
- Slog.w(TAG, "startPreEnroll: no fingerprint HAL!");
- return 0;
- }
- try {
- return daemon.preEnroll();
- } catch (RemoteException e) {
- Slog.e(TAG, "startPreEnroll failed", e);
- }
- return 0;
- }
-
- public int startPostEnroll(IBinder token) {
- IBiometricsFingerprint daemon = getFingerprintDaemon();
- if (daemon == null) {
- Slog.w(TAG, "startPostEnroll: no fingerprint HAL!");
- return 0;
- }
- try {
- return daemon.postEnroll();
- } catch (RemoteException e) {
- Slog.e(TAG, "startPostEnroll failed", e);
- }
- return 0;
- }
-
- /**
- * Calls fingerprint HAL to switch states to the new task. If there's already a current task,
- * it calls cancel() and sets mPendingClient to begin when the current task finishes
- * ({@link FingerprintManager#FINGERPRINT_ERROR_CANCELED}).
- * @param newClient the new client that wants to connect
- * @param initiatedByClient true for authenticate, remove and enroll
- */
- private void startClient(ClientMonitor newClient, boolean initiatedByClient) {
- ClientMonitor currentClient = mCurrentClient;
- if (currentClient != null) {
- if (DEBUG) Slog.v(TAG, "request stop current client " + currentClient.getOwnerString());
- if (currentClient instanceof InternalEnumerateClient ||
- currentClient instanceof InternalRemovalClient) {
- // This condition means we're currently running internal diagnostics to
- // remove extra fingerprints in the hardware and/or the software
- // TODO: design an escape hatch in case client never finishes
- if (newClient != null) {
- Slog.w(TAG, "Internal cleanup in progress but trying to start client "
- + newClient.getClass().getSuperclass().getSimpleName()
- + "(" + newClient.getOwnerString() + ")"
- + ", initiatedByClient = " + initiatedByClient);
- }
- }
- else {
- currentClient.stop(initiatedByClient);
- }
- mPendingClient = newClient;
- mHandler.removeCallbacks(mResetClientState);
- mHandler.postDelayed(mResetClientState, CANCEL_TIMEOUT_LIMIT);
- } else if (newClient != null) {
- mCurrentClient = newClient;
- if (DEBUG) Slog.v(TAG, "starting client "
- + newClient.getClass().getSuperclass().getSimpleName()
- + "(" + newClient.getOwnerString() + ")"
- + ", initiatedByClient = " + initiatedByClient);
- notifyClientActiveCallbacks(true);
-
- newClient.start();
- }
- }
-
- void startRemove(IBinder token, int fingerId, int groupId, int userId,
- IFingerprintServiceReceiver receiver, boolean restricted, boolean internal) {
- if (token == null) {
- Slog.w(TAG, "startRemove: token is null");
- return;
- }
- if (receiver == null) {
- Slog.w(TAG, "startRemove: receiver is null");
- return;
- }
-
- IBiometricsFingerprint daemon = getFingerprintDaemon();
- if (daemon == null) {
- Slog.w(TAG, "startRemove: no fingerprint HAL!");
- return;
- }
-
- if (internal) {
- Context context = getContext();
- InternalRemovalClient client = new InternalRemovalClient(context, mHalDeviceId,
- token, receiver, fingerId, groupId, userId, restricted,
- context.getOpPackageName()) {
- @Override
- public void notifyUserActivity() {
-
- }
- @Override
- public IBiometricsFingerprint getFingerprintDaemon() {
- return FingerprintService.this.getFingerprintDaemon();
- }
- };
- startClient(client, true);
- }
- else {
- RemovalClient client = new RemovalClient(getContext(), mHalDeviceId, token,
- receiver, fingerId, groupId, userId, restricted, token.toString()) {
- @Override
- public void notifyUserActivity() {
- FingerprintService.this.userActivity();
- }
-
- @Override
- public IBiometricsFingerprint getFingerprintDaemon() {
- return FingerprintService.this.getFingerprintDaemon();
- }
- };
- startClient(client, true);
- }
- }
-
- void startEnumerate(IBinder token, int userId,
- IFingerprintServiceReceiver receiver, boolean restricted, boolean internal) {
- IBiometricsFingerprint daemon = getFingerprintDaemon();
- if (daemon == null) {
- Slog.w(TAG, "startEnumerate: no fingerprint HAL!");
- return;
- }
- if (internal) {
- List<Fingerprint> enrolledList = getEnrolledFingerprints(userId);
- Context context = getContext();
- InternalEnumerateClient client = new InternalEnumerateClient(context, mHalDeviceId,
- token, receiver, userId, userId, restricted, context.getOpPackageName(),
- enrolledList) {
- @Override
- public void notifyUserActivity() {
-
- }
-
- @Override
- public IBiometricsFingerprint getFingerprintDaemon() {
- return FingerprintService.this.getFingerprintDaemon();
- }
- };
- startClient(client, true);
- }
- else {
- EnumerateClient client = new EnumerateClient(getContext(), mHalDeviceId, token,
- receiver, userId, userId, restricted, token.toString()) {
- @Override
- public void notifyUserActivity() {
- FingerprintService.this.userActivity();
- }
-
- @Override
- public IBiometricsFingerprint getFingerprintDaemon() {
- return FingerprintService.this.getFingerprintDaemon();
- }
- };
- startClient(client, true);
- }
- }
-
- public List<Fingerprint> getEnrolledFingerprints(int userId) {
- return mFingerprintUtils.getFingerprintsForUser(mContext, userId);
- }
-
- public boolean hasEnrolledFingerprints(int userId) {
- if (userId != UserHandle.getCallingUserId()) {
- checkPermission(INTERACT_ACROSS_USERS);
- }
- return mFingerprintUtils.getFingerprintsForUser(mContext, userId).size() > 0;
- }
-
- boolean hasPermission(String permission) {
- return getContext().checkCallingOrSelfPermission(permission)
- == PackageManager.PERMISSION_GRANTED;
- }
-
- void checkPermission(String permission) {
- getContext().enforceCallingOrSelfPermission(permission,
- "Must have " + permission + " permission.");
- }
-
- int getEffectiveUserId(int userId) {
- UserManager um = UserManager.get(mContext);
- if (um != null) {
- final long callingIdentity = Binder.clearCallingIdentity();
- userId = um.getCredentialOwnerProfile(userId);
- Binder.restoreCallingIdentity(callingIdentity);
- } else {
- Slog.e(TAG, "Unable to acquire UserManager");
- }
- return userId;
- }
-
- boolean isCurrentUserOrProfile(int userId) {
- UserManager um = UserManager.get(mContext);
- if (um == null) {
- Slog.e(TAG, "Unable to acquire UserManager");
- return false;
- }
-
- final long token = Binder.clearCallingIdentity();
- try {
- // Allow current user or profiles of the current user...
- for (int profileId : um.getEnabledProfileIds(ActivityManager.getCurrentUser())) {
- if (profileId == userId) {
- return true;
- }
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
-
- return false;
- }
-
- private boolean isForegroundActivity(int uid, int pid) {
- try {
- List<RunningAppProcessInfo> procs =
- ActivityManager.getService().getRunningAppProcesses();
- int N = procs.size();
- for (int i = 0; i < N; i++) {
- RunningAppProcessInfo proc = procs.get(i);
- if (proc.pid == pid && proc.uid == uid
- && proc.importance <= IMPORTANCE_FOREGROUND_SERVICE) {
- return true;
- }
- }
- } catch (RemoteException e) {
- Slog.w(TAG, "am.getRunningAppProcesses() failed");
- }
- return false;
- }
-
- /**
- * @param opPackageName name of package for caller
- * @param requireForeground only allow this call while app is in the foreground
- * @return true if caller can use fingerprint API
- */
- private boolean canUseFingerprint(String opPackageName, boolean requireForeground, int uid,
- int pid, int userId) {
- if (getContext().checkCallingPermission(USE_FINGERPRINT)
- != PackageManager.PERMISSION_GRANTED) {
- checkPermission(USE_BIOMETRIC);
- }
-
- if (isKeyguard(opPackageName)) {
- return true; // Keyguard is always allowed
- }
- if (!isCurrentUserOrProfile(userId)) {
- Slog.w(TAG,"Rejecting " + opPackageName + " ; not a current user or profile");
- return false;
- }
- if (mAppOps.noteOp(AppOpsManager.OP_USE_FINGERPRINT, uid, opPackageName)
- != AppOpsManager.MODE_ALLOWED) {
- Slog.w(TAG, "Rejecting " + opPackageName + " ; permission denied");
- return false;
- }
- if (requireForeground && !(isForegroundActivity(uid, pid) || currentClient(opPackageName))){
- Slog.w(TAG, "Rejecting " + opPackageName + " ; not in foreground");
- return false;
- }
- return true;
- }
-
- /**
- * @param opPackageName package of the caller
- * @return true if this is the same client currently using fingerprint
- */
- private boolean currentClient(String opPackageName) {
- return mCurrentClient != null && mCurrentClient.getOwnerString().equals(opPackageName);
- }
-
- /**
- * @param clientPackage
- * @return true if this is keyguard package
- */
- private boolean isKeyguard(String clientPackage) {
- return mKeyguardPackage.equals(clientPackage);
- }
-
- private void addLockoutResetMonitor(FingerprintServiceLockoutResetMonitor monitor) {
- if (!mLockoutMonitors.contains(monitor)) {
- mLockoutMonitors.add(monitor);
- }
- }
-
- private void removeLockoutResetCallback(
- FingerprintServiceLockoutResetMonitor monitor) {
- mLockoutMonitors.remove(monitor);
- }
-
- private void notifyLockoutResetMonitors() {
- for (int i = 0; i < mLockoutMonitors.size(); i++) {
- mLockoutMonitors.get(i).sendLockoutReset();
- }
- }
-
- private void notifyClientActiveCallbacks(boolean isActive) {
- List<IFingerprintClientActiveCallback> callbacks = mClientActiveCallbacks;
- for (int i = 0; i < callbacks.size(); i++) {
- try {
- callbacks.get(i).onClientActiveChanged(isActive);
- } catch (RemoteException re) {
- // If the remote is dead, stop notifying it
- mClientActiveCallbacks.remove(callbacks.get(i));
- }
- }
- }
-
- private void startAuthentication(IBinder token, long opId, int callingUserId, int groupId,
- IFingerprintServiceReceiver receiver, int flags, boolean restricted,
- String opPackageName, Bundle bundle, IBiometricPromptReceiver dialogReceiver) {
- updateActiveGroup(groupId, opPackageName);
-
- if (DEBUG) Slog.v(TAG, "startAuthentication(" + opPackageName + ")");
-
- AuthenticationClient client = new AuthenticationClient(getContext(), mHalDeviceId, token,
- receiver, mCurrentUserId, groupId, opId, restricted, opPackageName, bundle,
- dialogReceiver, mStatusBarService) {
- @Override
- public void onStart() {
- try {
- mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
- } catch (RemoteException e) {
- Slog.e(TAG, "Could not register task stack listener", e);
- }
- }
-
- @Override
- public void onStop() {
- try {
- mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
- } catch (RemoteException e) {
- Slog.e(TAG, "Could not unregister task stack listener", e);
- }
- }
-
- @Override
- public int handleFailedAttempt() {
- final int currentUser = ActivityManager.getCurrentUser();
- mFailedAttempts.put(currentUser, mFailedAttempts.get(currentUser, 0) + 1);
- mTimedLockoutCleared.put(ActivityManager.getCurrentUser(), false);
- final int lockoutMode = getLockoutMode();
- if (lockoutMode == AuthenticationClient.LOCKOUT_PERMANENT) {
- mPerformanceStats.permanentLockout++;
- } else if (lockoutMode == AuthenticationClient.LOCKOUT_TIMED) {
- mPerformanceStats.lockout++;
- }
-
- // Failing multiple times will continue to push out the lockout time
- if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
- scheduleLockoutResetForUser(currentUser);
- return lockoutMode;
- }
- return AuthenticationClient.LOCKOUT_NONE;
- }
-
- @Override
- public void resetFailedAttempts() {
- FingerprintService.this.resetFailedAttemptsForUser(true /* clearAttemptCounter */,
- ActivityManager.getCurrentUser());
- }
-
- @Override
- public void notifyUserActivity() {
- FingerprintService.this.userActivity();
- }
-
- @Override
- public IBiometricsFingerprint getFingerprintDaemon() {
- return FingerprintService.this.getFingerprintDaemon();
- }
- };
-
- int lockoutMode = getLockoutMode();
- if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
- Slog.v(TAG, "In lockout mode(" + lockoutMode +
- ") ; disallowing authentication");
- int errorCode = lockoutMode == AuthenticationClient.LOCKOUT_TIMED ?
- FingerprintManager.FINGERPRINT_ERROR_LOCKOUT :
- FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT;
- if (!client.onError(errorCode, 0 /* vendorCode */)) {
- Slog.w(TAG, "Cannot send permanent lockout message to client");
- }
- return;
- }
- startClient(client, true /* initiatedByClient */);
- }
-
- private void startEnrollment(IBinder token, byte [] cryptoToken, int userId,
- IFingerprintServiceReceiver receiver, int flags, boolean restricted,
- String opPackageName) {
- updateActiveGroup(userId, opPackageName);
-
- final int groupId = userId; // default group for fingerprint enrollment
-
- EnrollClient client = new EnrollClient(getContext(), mHalDeviceId, token, receiver,
- userId, groupId, cryptoToken, restricted, opPackageName) {
-
- @Override
- public IBiometricsFingerprint getFingerprintDaemon() {
- return FingerprintService.this.getFingerprintDaemon();
- }
-
- @Override
- public void notifyUserActivity() {
- FingerprintService.this.userActivity();
- }
- };
- startClient(client, true /* initiatedByClient */);
- }
-
- // attempt counter should only be cleared when Keyguard goes away or when
- // a fingerprint is successfully authenticated
- protected void resetFailedAttemptsForUser(boolean clearAttemptCounter, int userId) {
- if (DEBUG && getLockoutMode() != AuthenticationClient.LOCKOUT_NONE) {
- Slog.v(TAG, "Reset fingerprint lockout, clearAttemptCounter=" + clearAttemptCounter);
- }
- if (clearAttemptCounter) {
- mFailedAttempts.put(userId, 0);
- }
- mTimedLockoutCleared.put(userId, true);
- // If we're asked to reset failed attempts externally (i.e. from Keyguard),
- // the alarm might still be pending; remove it.
- cancelLockoutResetForUser(userId);
- notifyLockoutResetMonitors();
- }
-
- private class FingerprintServiceLockoutResetMonitor implements IBinder.DeathRecipient {
-
- private static final long WAKELOCK_TIMEOUT_MS = 2000;
- private final IFingerprintServiceLockoutResetCallback mCallback;
- private final WakeLock mWakeLock;
-
- public FingerprintServiceLockoutResetMonitor(
- IFingerprintServiceLockoutResetCallback callback) {
- mCallback = callback;
- mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
- "lockout reset callback");
- try {
- mCallback.asBinder().linkToDeath(FingerprintServiceLockoutResetMonitor.this, 0);
- } catch (RemoteException e) {
- Slog.w(TAG, "caught remote exception in linkToDeath", e);
- }
- }
-
- public void sendLockoutReset() {
- if (mCallback != null) {
- try {
- mWakeLock.acquire(WAKELOCK_TIMEOUT_MS);
- mCallback.onLockoutReset(mHalDeviceId, new IRemoteCallback.Stub() {
-
- @Override
- public void sendResult(Bundle data) throws RemoteException {
- releaseWakelock();
- }
- });
- } catch (DeadObjectException e) {
- Slog.w(TAG, "Death object while invoking onLockoutReset: ", e);
- mHandler.post(mRemoveCallbackRunnable);
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to invoke onLockoutReset: ", e);
- releaseWakelock();
- }
- }
- }
-
- private final Runnable mRemoveCallbackRunnable = new Runnable() {
- @Override
- public void run() {
- releaseWakelock();
- removeLockoutResetCallback(FingerprintServiceLockoutResetMonitor.this);
- }
- };
-
- @Override
- public void binderDied() {
- Slog.e(TAG, "Lockout reset callback binder died");
- mHandler.post(mRemoveCallbackRunnable);
- }
-
- private void releaseWakelock() {
- if (mWakeLock.isHeld()) {
- mWakeLock.release();
- }
- }
- }
-
- private IBiometricsFingerprintClientCallback mDaemonCallback =
- new IBiometricsFingerprintClientCallback.Stub() {
-
- @Override
- public void onEnrollResult(final long deviceId, final int fingerId, final int groupId,
- final int remaining) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- handleEnrollResult(deviceId, fingerId, groupId, remaining);
- }
- });
- }
-
- @Override
- public void onAcquired(final long deviceId, final int acquiredInfo, final int vendorCode) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- handleAcquired(deviceId, acquiredInfo, vendorCode);
- }
- });
- }
-
- @Override
- public void onAuthenticated(final long deviceId, final int fingerId, final int groupId,
- ArrayList<Byte> token) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- handleAuthenticated(deviceId, fingerId, groupId, token);
- }
- });
- }
-
- @Override
- public void onError(final long deviceId, final int error, final int vendorCode) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- handleError(deviceId, error, vendorCode);
- }
- });
- }
-
- @Override
- public void onRemoved(final long deviceId, final int fingerId, final int groupId, final int remaining) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- handleRemoved(deviceId, fingerId, groupId, remaining);
- }
- });
- }
-
- @Override
- public void onEnumerate(final long deviceId, final int fingerId, final int groupId,
- final int remaining) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- handleEnumerate(deviceId, fingerId, groupId, remaining);
- }
- });
- }
- };
-
- private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
- @Override // Binder call
- public long preEnroll(IBinder token) {
- checkPermission(MANAGE_FINGERPRINT);
- return startPreEnroll(token);
- }
-
- @Override // Binder call
- public int postEnroll(IBinder token) {
- checkPermission(MANAGE_FINGERPRINT);
- return startPostEnroll(token);
- }
-
- @Override // Binder call
- public void enroll(final IBinder token, final byte[] cryptoToken, final int userId,
- final IFingerprintServiceReceiver receiver, final int flags,
- final String opPackageName) {
- checkPermission(MANAGE_FINGERPRINT);
- final int limit = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser);
-
- final int enrolled = FingerprintService.this.getEnrolledFingerprints(userId).size();
- if (enrolled >= limit) {
- Slog.w(TAG, "Too many fingerprints registered");
- return;
- }
-
- // Group ID is arbitrarily set to parent profile user ID. It just represents
- // the default fingerprints for the user.
- if (!isCurrentUserOrProfile(userId)) {
- return;
- }
-
- final boolean restricted = isRestricted();
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- startEnrollment(token, cryptoToken, userId, receiver, flags,
- restricted, opPackageName);
- }
- });
- }
-
- private boolean isRestricted() {
- // Only give privileged apps (like Settings) access to fingerprint info
- final boolean restricted = !hasPermission(MANAGE_FINGERPRINT);
- return restricted;
- }
-
- @Override // Binder call
- public void cancelEnrollment(final IBinder token) {
- checkPermission(MANAGE_FINGERPRINT);
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- ClientMonitor client = mCurrentClient;
- if (client instanceof EnrollClient && client.getToken() == token) {
- client.stop(client.getToken() == token);
- }
- }
- });
- }
-
- @Override // Binder call
- public void authenticate(final IBinder token, final long opId, final int groupId,
- final IFingerprintServiceReceiver receiver, final int flags,
- final String opPackageName, final Bundle bundle,
- final IBiometricPromptReceiver dialogReceiver) {
- final int callingUid = Binder.getCallingUid();
- final int callingPid = Binder.getCallingPid();
- final int callingUserId = UserHandle.getCallingUserId();
- final boolean restricted = isRestricted();
-
- if (!canUseFingerprint(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
- callingUserId)) {
- if (DEBUG) Slog.v(TAG, "authenticate(): reject " + opPackageName);
- return;
- }
-
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- MetricsLogger.histogram(mContext, "fingerprint_token", opId != 0L ? 1 : 0);
-
- // Get performance stats object for this user.
- HashMap<Integer, PerformanceStats> pmap
- = (opId == 0) ? mPerformanceMap : mCryptoPerformanceMap;
- PerformanceStats stats = pmap.get(mCurrentUserId);
- if (stats == null) {
- stats = new PerformanceStats();
- pmap.put(mCurrentUserId, stats);
- }
- mPerformanceStats = stats;
-
- startAuthentication(token, opId, callingUserId, groupId, receiver,
- flags, restricted, opPackageName, bundle, dialogReceiver);
- }
- });
- }
-
- @Override // Binder call
- public void cancelAuthentication(final IBinder token, final String opPackageName) {
- final int callingUid = Binder.getCallingUid();
- final int callingPid = Binder.getCallingPid();
- final int callingUserId = UserHandle.getCallingUserId();
-
- if (!canUseFingerprint(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
- callingUserId)) {
- if (DEBUG) Slog.v(TAG, "cancelAuthentication(): reject " + opPackageName);
- return;
- }
-
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- ClientMonitor client = mCurrentClient;
- if (client instanceof AuthenticationClient) {
- if (client.getToken() == token) {
- if (DEBUG) Slog.v(TAG, "stop client " + client.getOwnerString());
- client.stop(client.getToken() == token);
- } else {
- if (DEBUG) Slog.v(TAG, "can't stop client "
- + client.getOwnerString() + " since tokens don't match");
- }
- } else if (client != null) {
- if (DEBUG) Slog.v(TAG, "can't cancel non-authenticating client "
- + client.getOwnerString());
- }
- }
- });
- }
-
- @Override // Binder call
- public void setActiveUser(final int userId) {
- checkPermission(MANAGE_FINGERPRINT);
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- updateActiveGroup(userId, null);
- }
- });
- }
-
- @Override // Binder call
- public void remove(final IBinder token, final int fingerId, final int groupId,
- final int userId, final IFingerprintServiceReceiver receiver) {
- checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission
- final boolean restricted = isRestricted();
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- startRemove(token, fingerId, groupId, userId, receiver,
- restricted, false /* internal */);
- }
- });
- }
-
- @Override // Binder call
- public void enumerate(final IBinder token, final int userId,
- final IFingerprintServiceReceiver receiver) {
- checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission
- final boolean restricted = isRestricted();
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- startEnumerate(token, userId, receiver, restricted, false /* internal */);
- }
- });
- }
-
- @Override // Binder call
- public boolean isHardwareDetected(long deviceId, String opPackageName) {
- if (!canUseFingerprint(opPackageName, false /* foregroundOnly */,
- Binder.getCallingUid(), Binder.getCallingPid(),
- UserHandle.getCallingUserId())) {
- return false;
- }
-
- final long token = Binder.clearCallingIdentity();
- try {
- IBiometricsFingerprint daemon = getFingerprintDaemon();
- return daemon != null && mHalDeviceId != 0;
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override // Binder call
- public void rename(final int fingerId, final int groupId, final String name) {
- checkPermission(MANAGE_FINGERPRINT);
- if (!isCurrentUserOrProfile(groupId)) {
- return;
- }
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mFingerprintUtils.renameFingerprintForUser(mContext, fingerId,
- groupId, name);
- }
- });
- }
-
- @Override // Binder call
- public List<Fingerprint> getEnrolledFingerprints(int userId, String opPackageName) {
- if (!canUseFingerprint(opPackageName, false /* foregroundOnly */,
- Binder.getCallingUid(), Binder.getCallingPid(),
- UserHandle.getCallingUserId())) {
- return Collections.emptyList();
- }
-
- return FingerprintService.this.getEnrolledFingerprints(userId);
- }
-
- @Override // Binder call
- public boolean hasEnrolledFingerprints(int userId, String opPackageName) {
- if (!canUseFingerprint(opPackageName, false /* foregroundOnly */,
- Binder.getCallingUid(), Binder.getCallingPid(),
- UserHandle.getCallingUserId())) {
- return false;
- }
-
- return FingerprintService.this.hasEnrolledFingerprints(userId);
- }
-
- @Override // Binder call
- public long getAuthenticatorId(String opPackageName) {
- // In this method, we're not checking whether the caller is permitted to use fingerprint
- // API because current authenticator ID is leaked (in a more contrived way) via Android
- // Keystore (android.security.keystore package): the user of that API can create a key
- // which requires fingerprint authentication for its use, and then query the key's
- // characteristics (hidden API) which returns, among other things, fingerprint
- // authenticator ID which was active at key creation time.
- //
- // Reason: The part of Android Keystore which runs inside an app's process invokes this
- // method in certain cases. Those cases are not always where the developer demonstrates
- // explicit intent to use fingerprint functionality. Thus, to avoiding throwing an
- // unexpected SecurityException this method does not check whether its caller is
- // permitted to use fingerprint API.
- //
- // The permission check should be restored once Android Keystore no longer invokes this
- // method from inside app processes.
-
- return FingerprintService.this.getAuthenticatorId(opPackageName);
- }
-
- @Override // Binder call
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
-
- final long ident = Binder.clearCallingIdentity();
- try {
- if (args.length > 0 && "--proto".equals(args[0])) {
- dumpProto(fd);
- } else {
- dumpInternal(pw);
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- @Override // Binder call
- public void resetTimeout(byte [] token) {
- checkPermission(RESET_FINGERPRINT_LOCKOUT);
- // TODO: confirm security token when we move timeout management into the HAL layer.
- mHandler.post(mResetFailedAttemptsForCurrentUserRunnable);
- }
-
- @Override
- public void addLockoutResetCallback(final IFingerprintServiceLockoutResetCallback callback)
- throws RemoteException {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- addLockoutResetMonitor(
- new FingerprintServiceLockoutResetMonitor(callback));
- }
- });
- }
-
- @Override
- public boolean isClientActive() {
- checkPermission(MANAGE_FINGERPRINT);
- synchronized(FingerprintService.this) {
- return (mCurrentClient != null) || (mPendingClient != null);
- }
- }
-
- @Override
- public void addClientActiveCallback(IFingerprintClientActiveCallback callback) {
- checkPermission(MANAGE_FINGERPRINT);
- mClientActiveCallbacks.add(callback);
- }
-
- @Override
- public void removeClientActiveCallback(IFingerprintClientActiveCallback callback) {
- checkPermission(MANAGE_FINGERPRINT);
- mClientActiveCallbacks.remove(callback);
- }
- }
-
- private void dumpInternal(PrintWriter pw) {
- JSONObject dump = new JSONObject();
- try {
- dump.put("service", "Fingerprint Manager");
-
- JSONArray sets = new JSONArray();
- for (UserInfo user : UserManager.get(getContext()).getUsers()) {
- final int userId = user.getUserHandle().getIdentifier();
- final int N = mFingerprintUtils.getFingerprintsForUser(mContext, userId).size();
- PerformanceStats stats = mPerformanceMap.get(userId);
- PerformanceStats cryptoStats = mCryptoPerformanceMap.get(userId);
- JSONObject set = new JSONObject();
- set.put("id", userId);
- set.put("count", N);
- set.put("accept", (stats != null) ? stats.accept : 0);
- set.put("reject", (stats != null) ? stats.reject : 0);
- set.put("acquire", (stats != null) ? stats.acquire : 0);
- set.put("lockout", (stats != null) ? stats.lockout : 0);
- set.put("permanentLockout", (stats != null) ? stats.permanentLockout : 0);
- // cryptoStats measures statistics about secure fingerprint transactions
- // (e.g. to unlock password storage, make secure purchases, etc.)
- set.put("acceptCrypto", (cryptoStats != null) ? cryptoStats.accept : 0);
- set.put("rejectCrypto", (cryptoStats != null) ? cryptoStats.reject : 0);
- set.put("acquireCrypto", (cryptoStats != null) ? cryptoStats.acquire : 0);
- set.put("lockoutCrypto", (cryptoStats != null) ? cryptoStats.lockout : 0);
- set.put("permanentLockoutCrypto",
- (cryptoStats != null) ? cryptoStats.permanentLockout : 0);
- sets.put(set);
- }
-
- dump.put("prints", sets);
- } catch (JSONException e) {
- Slog.e(TAG, "dump formatting failure", e);
- }
- pw.println(dump);
- }
-
- private void dumpProto(FileDescriptor fd) {
- final ProtoOutputStream proto = new ProtoOutputStream(fd);
- for (UserInfo user : UserManager.get(getContext()).getUsers()) {
- final int userId = user.getUserHandle().getIdentifier();
-
- final long userToken = proto.start(FingerprintServiceDumpProto.USERS);
-
- proto.write(FingerprintUserStatsProto.USER_ID, userId);
- proto.write(FingerprintUserStatsProto.NUM_FINGERPRINTS,
- mFingerprintUtils.getFingerprintsForUser(mContext, userId).size());
-
- // Normal fingerprint authentications (e.g. lockscreen)
- final PerformanceStats normal = mPerformanceMap.get(userId);
- if (normal != null) {
- final long countsToken = proto.start(FingerprintUserStatsProto.NORMAL);
- proto.write(PerformanceStatsProto.ACCEPT, normal.accept);
- proto.write(PerformanceStatsProto.REJECT, normal.reject);
- proto.write(PerformanceStatsProto.ACQUIRE, normal.acquire);
- proto.write(PerformanceStatsProto.LOCKOUT, normal.lockout);
- proto.write(PerformanceStatsProto.PERMANENT_LOCKOUT, normal.permanentLockout);
- proto.end(countsToken);
- }
-
- // Statistics about secure fingerprint transactions (e.g. to unlock password
- // storage, make secure purchases, etc.)
- final PerformanceStats crypto = mCryptoPerformanceMap.get(userId);
- if (crypto != null) {
- final long countsToken = proto.start(FingerprintUserStatsProto.CRYPTO);
- proto.write(PerformanceStatsProto.ACCEPT, crypto.accept);
- proto.write(PerformanceStatsProto.REJECT, crypto.reject);
- proto.write(PerformanceStatsProto.ACQUIRE, crypto.acquire);
- proto.write(PerformanceStatsProto.LOCKOUT, crypto.lockout);
- proto.write(PerformanceStatsProto.PERMANENT_LOCKOUT, crypto.permanentLockout);
- proto.end(countsToken);
- }
-
- proto.end(userToken);
- }
- proto.flush();
- mPerformanceMap.clear();
- mCryptoPerformanceMap.clear();
- }
-
- @Override
- public void onStart() {
- publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
- SystemServerInitThreadPool.get().submit(this::getFingerprintDaemon, TAG + ".onStart");
- listenForUserSwitches();
- }
-
- private void updateActiveGroup(int userId, String clientPackage) {
- IBiometricsFingerprint daemon = getFingerprintDaemon();
-
- if (daemon != null) {
- try {
- userId = getUserOrWorkProfileId(clientPackage, userId);
- if (userId != mCurrentUserId) {
- int firstSdkInt = Build.VERSION.FIRST_SDK_INT;
- if (firstSdkInt < Build.VERSION_CODES.BASE) {
- Slog.e(TAG, "First SDK version " + firstSdkInt + " is invalid; must be " +
- "at least VERSION_CODES.BASE");
- }
- File baseDir;
- if (firstSdkInt <= Build.VERSION_CODES.O_MR1) {
- baseDir = Environment.getUserSystemDirectory(userId);
- } else {
- baseDir = Environment.getDataVendorDeDirectory(userId);
- }
-
- File fpDir = new File(baseDir, FP_DATA_DIR);
- if (!fpDir.exists()) {
- if (!fpDir.mkdir()) {
- Slog.v(TAG, "Cannot make directory: " + fpDir.getAbsolutePath());
- return;
- }
- // Calling mkdir() from this process will create a directory with our
- // permissions (inherited from the containing dir). This command fixes
- // the label.
- if (!SELinux.restorecon(fpDir)) {
- Slog.w(TAG, "Restorecons failed. Directory will have wrong label.");
- return;
- }
- }
-
- daemon.setActiveGroup(userId, fpDir.getAbsolutePath());
- mCurrentUserId = userId;
- }
- mAuthenticatorIds.put(userId,
- hasEnrolledFingerprints(userId) ? daemon.getAuthenticatorId() : 0L);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to setActiveGroup():", e);
- }
- }
- }
-
- /**
- * @param clientPackage the package of the caller
- * @return the profile id
- */
- private int getUserOrWorkProfileId(String clientPackage, int userId) {
- if (!isKeyguard(clientPackage) && isWorkProfile(userId)) {
- return userId;
- }
- return getEffectiveUserId(userId);
- }
-
- /**
- * @param userId
- * @return true if this is a work profile
- */
- private boolean isWorkProfile(int userId) {
- UserInfo userInfo = null;
- final long token = Binder.clearCallingIdentity();
- try {
- userInfo = mUserManager.getUserInfo(userId);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- return userInfo != null && userInfo.isManagedProfile();
- }
-
- private void listenForUserSwitches() {
- try {
- ActivityManager.getService().registerUserSwitchObserver(
- new SynchronousUserSwitchObserver() {
- @Override
- public void onUserSwitching(int newUserId) throws RemoteException {
- mHandler.obtainMessage(MSG_USER_SWITCHING, newUserId, 0 /* unused */)
- .sendToTarget();
- }
- }, TAG);
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to listen for user switching event" ,e);
- }
- }
-
- /***
- * @param opPackageName the name of the calling package
- * @return authenticator id for the calling user
- */
- public long getAuthenticatorId(String opPackageName) {
- final int userId = getUserOrWorkProfileId(opPackageName, UserHandle.getCallingUserId());
- return mAuthenticatorIds.getOrDefault(userId, 0L);
- }
-}
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintUtils.java b/services/core/java/com/android/server/fingerprint/FingerprintUtils.java
deleted file mode 100644
index 5fbd735..0000000
--- a/services/core/java/com/android/server/fingerprint/FingerprintUtils.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/**
- * Copyright (C) 2015 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.fingerprint;
-
-import android.content.Context;
-import android.hardware.fingerprint.Fingerprint;
-import android.text.TextUtils;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.util.List;
-
-/**
- * Utility class for dealing with fingerprints and fingerprint settings.
- */
-public class FingerprintUtils {
-
- private static final Object sInstanceLock = new Object();
- private static FingerprintUtils sInstance;
-
- @GuardedBy("this")
- private final SparseArray<FingerprintsUserState> mUsers = new SparseArray<>();
-
- public static FingerprintUtils getInstance() {
- synchronized (sInstanceLock) {
- if (sInstance == null) {
- sInstance = new FingerprintUtils();
- }
- }
- return sInstance;
- }
-
- private FingerprintUtils() {
- }
-
- public List<Fingerprint> getFingerprintsForUser(Context ctx, int userId) {
- return getStateForUser(ctx, userId).getFingerprints();
- }
-
- public void addFingerprintForUser(Context ctx, int fingerId, int userId) {
- getStateForUser(ctx, userId).addFingerprint(fingerId, userId);
- }
-
- public void removeFingerprintIdForUser(Context ctx, int fingerId, int userId) {
- getStateForUser(ctx, userId).removeFingerprint(fingerId);
- }
-
- public void renameFingerprintForUser(Context ctx, int fingerId, int userId, CharSequence name) {
- if (TextUtils.isEmpty(name)) {
- // Don't do the rename if it's empty
- return;
- }
- getStateForUser(ctx, userId).renameFingerprint(fingerId, name);
- }
-
- private FingerprintsUserState getStateForUser(Context ctx, int userId) {
- synchronized (this) {
- FingerprintsUserState state = mUsers.get(userId);
- if (state == null) {
- state = new FingerprintsUserState(ctx, userId);
- mUsers.put(userId, state);
- }
- return state;
- }
- }
-}
-
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintsUserState.java b/services/core/java/com/android/server/fingerprint/FingerprintsUserState.java
deleted file mode 100644
index b0cde2d..0000000
--- a/services/core/java/com/android/server/fingerprint/FingerprintsUserState.java
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Copyright (C) 2015 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.fingerprint;
-
-import android.content.Context;
-import android.hardware.fingerprint.Fingerprint;
-import android.os.AsyncTask;
-import android.os.Environment;
-import android.util.AtomicFile;
-import android.util.Slog;
-import android.util.Xml;
-
-import com.android.internal.annotations.GuardedBy;
-
-import libcore.io.IoUtils;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Class managing the set of fingerprint per user across device reboots.
- */
-class FingerprintsUserState {
-
- private static final String TAG = "FingerprintState";
- private static final String FINGERPRINT_FILE = "settings_fingerprint.xml";
-
- private static final String TAG_FINGERPRINTS = "fingerprints";
- private static final String TAG_FINGERPRINT = "fingerprint";
- private static final String ATTR_NAME = "name";
- private static final String ATTR_GROUP_ID = "groupId";
- private static final String ATTR_FINGER_ID = "fingerId";
- private static final String ATTR_DEVICE_ID = "deviceId";
-
- private final File mFile;
-
- @GuardedBy("this")
- private final ArrayList<Fingerprint> mFingerprints = new ArrayList<Fingerprint>();
- private final Context mCtx;
-
- public FingerprintsUserState(Context ctx, int userId) {
- mFile = getFileForUser(userId);
- mCtx = ctx;
- synchronized (this) {
- readStateSyncLocked();
- }
- }
-
- public void addFingerprint(int fingerId, int groupId) {
- synchronized (this) {
- mFingerprints.add(new Fingerprint(getUniqueName(), groupId, fingerId, 0));
- scheduleWriteStateLocked();
- }
- }
-
- public void removeFingerprint(int fingerId) {
- synchronized (this) {
- for (int i = 0; i < mFingerprints.size(); i++) {
- if (mFingerprints.get(i).getFingerId() == fingerId) {
- mFingerprints.remove(i);
- scheduleWriteStateLocked();
- break;
- }
- }
- }
- }
-
- public void renameFingerprint(int fingerId, CharSequence name) {
- synchronized (this) {
- for (int i = 0; i < mFingerprints.size(); i++) {
- if (mFingerprints.get(i).getFingerId() == fingerId) {
- Fingerprint old = mFingerprints.get(i);
- mFingerprints.set(i, new Fingerprint(name, old.getGroupId(), old.getFingerId(),
- old.getDeviceId()));
- scheduleWriteStateLocked();
- break;
- }
- }
- }
- }
-
- public List<Fingerprint> getFingerprints() {
- synchronized (this) {
- return getCopy(mFingerprints);
- }
- }
-
- /**
- * Finds a unique name for the given fingerprint
- * @return unique name
- */
- private String getUniqueName() {
- int guess = 1;
- while (true) {
- // Not the most efficient algorithm in the world, but there shouldn't be more than 10
- String name = mCtx.getString(com.android.internal.R.string.fingerprint_name_template,
- guess);
- if (isUnique(name)) {
- return name;
- }
- guess++;
- }
- }
-
- private boolean isUnique(String name) {
- for (Fingerprint fp : mFingerprints) {
- if (fp.getName().equals(name)) {
- return false;
- }
- }
- return true;
- }
-
- private static File getFileForUser(int userId) {
- return new File(Environment.getUserSystemDirectory(userId), FINGERPRINT_FILE);
- }
-
- private final Runnable mWriteStateRunnable = new Runnable() {
- @Override
- public void run() {
- doWriteState();
- }
- };
-
- private void scheduleWriteStateLocked() {
- AsyncTask.execute(mWriteStateRunnable);
- }
-
- private ArrayList<Fingerprint> getCopy(ArrayList<Fingerprint> array) {
- ArrayList<Fingerprint> result = new ArrayList<Fingerprint>(array.size());
- for (int i = 0; i < array.size(); i++) {
- Fingerprint fp = array.get(i);
- result.add(new Fingerprint(fp.getName(), fp.getGroupId(), fp.getFingerId(),
- fp.getDeviceId()));
- }
- return result;
- }
-
- private void doWriteState() {
- AtomicFile destination = new AtomicFile(mFile);
-
- ArrayList<Fingerprint> fingerprints;
-
- synchronized (this) {
- fingerprints = getCopy(mFingerprints);
- }
-
- FileOutputStream out = null;
- try {
- out = destination.startWrite();
-
- XmlSerializer serializer = Xml.newSerializer();
- serializer.setOutput(out, "utf-8");
- serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
- serializer.startDocument(null, true);
- serializer.startTag(null, TAG_FINGERPRINTS);
-
- final int count = fingerprints.size();
- for (int i = 0; i < count; i++) {
- Fingerprint fp = fingerprints.get(i);
- serializer.startTag(null, TAG_FINGERPRINT);
- serializer.attribute(null, ATTR_FINGER_ID, Integer.toString(fp.getFingerId()));
- serializer.attribute(null, ATTR_NAME, fp.getName().toString());
- serializer.attribute(null, ATTR_GROUP_ID, Integer.toString(fp.getGroupId()));
- serializer.attribute(null, ATTR_DEVICE_ID, Long.toString(fp.getDeviceId()));
- serializer.endTag(null, TAG_FINGERPRINT);
- }
-
- serializer.endTag(null, TAG_FINGERPRINTS);
- serializer.endDocument();
- destination.finishWrite(out);
-
- // Any error while writing is fatal.
- } catch (Throwable t) {
- Slog.wtf(TAG, "Failed to write settings, restoring backup", t);
- destination.failWrite(out);
- throw new IllegalStateException("Failed to write fingerprints", t);
- } finally {
- IoUtils.closeQuietly(out);
- }
- }
-
- @GuardedBy("this")
- private void readStateSyncLocked() {
- FileInputStream in;
- if (!mFile.exists()) {
- return;
- }
- try {
- in = new FileInputStream(mFile);
- } catch (FileNotFoundException fnfe) {
- Slog.i(TAG, "No fingerprint state");
- return;
- }
- try {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(in, null);
- parseStateLocked(parser);
-
- } catch (XmlPullParserException | IOException e) {
- throw new IllegalStateException("Failed parsing settings file: "
- + mFile , e);
- } finally {
- IoUtils.closeQuietly(in);
- }
- }
-
- @GuardedBy("this")
- private void parseStateLocked(XmlPullParser parser)
- throws IOException, XmlPullParserException {
- final int outerDepth = parser.getDepth();
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (tagName.equals(TAG_FINGERPRINTS)) {
- parseFingerprintsLocked(parser);
- }
- }
- }
-
- @GuardedBy("this")
- private void parseFingerprintsLocked(XmlPullParser parser)
- throws IOException, XmlPullParserException {
-
- final int outerDepth = parser.getDepth();
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (tagName.equals(TAG_FINGERPRINT)) {
- String name = parser.getAttributeValue(null, ATTR_NAME);
- String groupId = parser.getAttributeValue(null, ATTR_GROUP_ID);
- String fingerId = parser.getAttributeValue(null, ATTR_FINGER_ID);
- String deviceId = parser.getAttributeValue(null, ATTR_DEVICE_ID);
- mFingerprints.add(new Fingerprint(name, Integer.parseInt(groupId),
- Integer.parseInt(fingerId), Integer.parseInt(deviceId)));
- }
- }
- }
-
-}
diff --git a/services/core/java/com/android/server/fingerprint/InternalEnumerateClient.java b/services/core/java/com/android/server/fingerprint/InternalEnumerateClient.java
deleted file mode 100644
index 434db98..0000000
--- a/services/core/java/com/android/server/fingerprint/InternalEnumerateClient.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.fingerprint;
-
-import android.content.Context;
-import android.hardware.fingerprint.Fingerprint;
-import android.hardware.fingerprint.IFingerprintServiceReceiver;
-import android.os.IBinder;
-import android.util.Slog;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * An internal class to help clean up unknown fingerprints in the hardware and software
- */
-public abstract class InternalEnumerateClient extends EnumerateClient {
-
- private List<Fingerprint> mEnrolledList;
- private List<Fingerprint> mUnknownFingerprints = new ArrayList<>(); // list of fp to delete
-
- public InternalEnumerateClient(Context context, long halDeviceId, IBinder token,
- IFingerprintServiceReceiver receiver, int groupId, int userId,
- boolean restricted, String owner, List<Fingerprint> enrolledList) {
-
- super(context, halDeviceId, token, receiver, userId, groupId, restricted, owner);
- mEnrolledList = enrolledList;
- }
-
- private void handleEnumeratedFingerprint(int fingerId, int groupId, int remaining) {
-
- boolean matched = false;
- for (int i=0; i<mEnrolledList.size(); i++) {
- if (mEnrolledList.get(i).getFingerId() == fingerId) {
- mEnrolledList.remove(i);
- matched = true;
- break;
- }
- }
-
- // fingerId 0 means no fingerprints are in hardware
- if (!matched && fingerId != 0) {
- Fingerprint fingerprint = new Fingerprint("", groupId, fingerId, getHalDeviceId());
- mUnknownFingerprints.add(fingerprint);
- }
- }
-
- private void doFingerprintCleanup() {
-
- if (mEnrolledList == null) {
- return;
- }
-
- for (Fingerprint f : mEnrolledList) {
- Slog.e(TAG, "Internal Enumerate: Removing dangling enrolled fingerprint: "
- + f.getName() + " " + f.getFingerId() + " " + f.getGroupId()
- + " " + f.getDeviceId());
-
- FingerprintUtils.getInstance().removeFingerprintIdForUser(getContext(),
- f.getFingerId(), getTargetUserId());
- }
- mEnrolledList.clear();
- }
-
- public List<Fingerprint> getUnknownFingerprints() {
- return mUnknownFingerprints;
- }
-
- @Override
- public boolean onEnumerationResult(int fingerId, int groupId, int remaining) {
-
- handleEnumeratedFingerprint(fingerId, groupId, remaining);
- if (remaining == 0) {
- doFingerprintCleanup();
- }
-
- return remaining == 0;
- }
-
-}
diff --git a/services/core/java/com/android/server/fingerprint/InternalRemovalClient.java b/services/core/java/com/android/server/fingerprint/InternalRemovalClient.java
deleted file mode 100644
index 19f61fe..0000000
--- a/services/core/java/com/android/server/fingerprint/InternalRemovalClient.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.fingerprint;
-
-import android.content.Context;
-import android.os.IBinder;
-import android.hardware.fingerprint.IFingerprintServiceReceiver;
-import com.android.server.fingerprint.RemovalClient;
-
-public abstract class InternalRemovalClient extends RemovalClient {
-
- public InternalRemovalClient(Context context, long halDeviceId, IBinder token,
- IFingerprintServiceReceiver receiver, int fingerId, int groupId, int userId,
- boolean restricted, String owner) {
-
- super(context, halDeviceId, token, receiver, fingerId, groupId, userId, restricted, owner);
-
- }
-}
diff --git a/services/core/java/com/android/server/fingerprint/RemovalClient.java b/services/core/java/com/android/server/fingerprint/RemovalClient.java
deleted file mode 100644
index ffc8488..0000000
--- a/services/core/java/com/android/server/fingerprint/RemovalClient.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/**
- * Copyright (C) 2016 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.fingerprint;
-
-import android.content.Context;
-import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
-import android.hardware.fingerprint.FingerprintManager;
-import android.hardware.fingerprint.IFingerprintServiceReceiver;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.util.Slog;
-import com.android.internal.logging.MetricsLogger;
-
-/**
- * A class to keep track of the remove state for a given client.
- */
-public abstract class RemovalClient extends ClientMonitor {
- private int mFingerId;
-
- public RemovalClient(Context context, long halDeviceId, IBinder token,
- IFingerprintServiceReceiver receiver, int fingerId, int groupId, int userId,
- boolean restricted, String owner) {
- super(context, halDeviceId, token, receiver, userId, groupId, restricted, owner);
- mFingerId = fingerId;
- }
-
- @Override
- public int start() {
- IBiometricsFingerprint daemon = getFingerprintDaemon();
- // The fingerprint template ids will be removed when we get confirmation from the HAL
- try {
- final int result = daemon.remove(getGroupId(), mFingerId);
- if (result != 0) {
- Slog.w(TAG, "startRemove with id = " + mFingerId + " failed, result=" + result);
- MetricsLogger.histogram(getContext(), "fingerprintd_remove_start_error", result);
- onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
- return result;
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "startRemove failed", e);
- }
- return 0;
- }
-
- @Override
- public int stop(boolean initiatedByClient) {
- if (mAlreadyCancelled) {
- Slog.w(TAG, "stopRemove: already cancelled!");
- return 0;
- }
- IBiometricsFingerprint daemon = getFingerprintDaemon();
- if (daemon == null) {
- Slog.w(TAG, "stopRemoval: no fingerprint HAL!");
- return ERROR_ESRCH;
- }
- try {
- final int result = daemon.cancel();
- if (result != 0) {
- Slog.w(TAG, "stopRemoval failed, result=" + result);
- return result;
- }
- if (DEBUG) Slog.w(TAG, "client " + getOwnerString() + " is no longer removing");
- } catch (RemoteException e) {
- Slog.e(TAG, "stopRemoval failed", e);
- return ERROR_ESRCH;
- }
- mAlreadyCancelled = true;
- return 0; // success
- }
-
- /*
- * @return true if we're done.
- */
- private boolean sendRemoved(int fingerId, int groupId, int remaining) {
- IFingerprintServiceReceiver receiver = getReceiver();
- try {
- if (receiver != null) {
- receiver.onRemoved(getHalDeviceId(), fingerId, groupId, remaining);
- }
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to notify Removed:", e);
- }
- return remaining == 0;
- }
-
- @Override
- public boolean onRemoved(int fingerId, int groupId, int remaining) {
- if (fingerId != 0) {
- FingerprintUtils.getInstance().removeFingerprintIdForUser(getContext(), fingerId,
- getTargetUserId());
- }
- return sendRemoved(fingerId, getGroupId(), remaining);
- }
-
- @Override
- public boolean onEnrollResult(int fingerId, int groupId, int rem) {
- if (DEBUG) Slog.w(TAG, "onEnrollResult() called for remove!");
- return true; // Invalid for Remove
- }
-
- @Override
- public boolean onAuthenticated(int fingerId, int groupId) {
- if (DEBUG) Slog.w(TAG, "onAuthenticated() called for remove!");
- return true; // Invalid for Remove.
- }
-
- @Override
- public boolean onEnumerationResult(int fingerId, int groupId, int remaining) {
- if (DEBUG) Slog.w(TAG, "onEnumerationResult() called for remove!");
- return true; // Invalid for Remove.
- }
-
-
-}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 5681367..2949b92 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -516,8 +516,7 @@
static boolean isPowerOffOrToggleCommand(HdmiCecMessage message) {
byte[] params = message.getParams();
return message.getOpcode() == Constants.MESSAGE_USER_CONTROL_PRESSED
- && (params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER
- || params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER_OFF_FUNCTION
+ && (params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER_OFF_FUNCTION
|| params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER_TOGGLE_FUNCTION);
}
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index d515ce6..86ecd12 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -254,7 +254,7 @@
// 1 second, or 1 Hz frequency.
private static final long LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS = 1000;
// Default update duration in milliseconds for REQUEST_LOCATION.
- private static final long LOCATION_UPDATE_DURATION_MILLIS = 0;
+ private static final long LOCATION_UPDATE_DURATION_MILLIS = 10 * 1000;
/** simpler wrapper for ProviderRequest + Worksource */
private static class GpsRequest {
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 36b04fc..c6a8712 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -955,12 +955,18 @@
@GuardedBy("mSeparateChallengeLock")
private void setSeparateProfileChallengeEnabledLocked(@UserIdInt int userId, boolean enabled,
String managedUserPassword) {
+ final boolean old = getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId);
setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, enabled, userId);
- if (enabled) {
- mStorage.removeChildProfileLock(userId);
- removeKeystoreProfileKey(userId);
- } else {
- tieManagedProfileLockIfNecessary(userId, managedUserPassword);
+ try {
+ if (enabled) {
+ mStorage.removeChildProfileLock(userId);
+ removeKeystoreProfileKey(userId);
+ } else {
+ tieManagedProfileLockIfNecessary(userId, managedUserPassword);
+ }
+ } catch (IllegalStateException e) {
+ setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, old, userId);
+ throw e;
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 32f1744..6402b7b 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -3125,14 +3125,19 @@
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
final DumpFilter filter = DumpFilter.parseFromArguments(args);
- if (filter.stats) {
- dumpJson(pw, filter);
- } else if (filter.proto) {
- dumpProto(fd, filter);
- } else if (filter.criticalPriority) {
- dumpNotificationRecords(pw, filter);
- } else {
- dumpImpl(pw, filter);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (filter.stats) {
+ dumpJson(pw, filter);
+ } else if (filter.proto) {
+ dumpProto(fd, filter);
+ } else if (filter.criticalPriority) {
+ dumpNotificationRecords(pw, filter);
+ } else {
+ dumpImpl(pw, filter);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
}
@@ -4532,6 +4537,15 @@
@GuardedBy("mNotificationLock")
@VisibleForTesting
protected boolean isVisuallyInterruptive(NotificationRecord old, NotificationRecord r) {
+ // Ignore summary updates because we don't display most of the information.
+ if (r.sbn.isGroup() && r.sbn.getNotification().isGroupSummary()) {
+ if (DEBUG_INTERRUPTIVENESS) {
+ Log.v(TAG, "INTERRUPTIVENESS: "
+ + r.getKey() + " is not interruptive: summary");
+ }
+ return false;
+ }
+
if (old == null) {
if (DEBUG_INTERRUPTIVENESS) {
Log.v(TAG, "INTERRUPTIVENESS: "
@@ -4569,15 +4583,6 @@
return false;
}
- // Ignore summary updates because we don't display most of the information.
- if (r.sbn.isGroup() && r.sbn.getNotification().isGroupSummary()) {
- if (DEBUG_INTERRUPTIVENESS) {
- Log.v(TAG, "INTERRUPTIVENESS: "
- + r.getKey() + " is not interruptive: summary");
- }
- return false;
- }
-
final String oldTitle = String.valueOf(oldN.extras.get(Notification.EXTRA_TITLE));
final String newTitle = String.valueOf(newN.extras.get(Notification.EXTRA_TITLE));
if (!Objects.equals(oldTitle, newTitle)) {
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 39d0bf5..75b9f13 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -128,6 +128,11 @@
// The most recent update time, or the creation time if no updates.
private long mUpdateTimeMs;
+ // The most recent interruption time, or the creation time if no updates. Differs from the
+ // above value because updates are filtered based on whether they actually interrupted the
+ // user
+ private long mInterruptionTimeMs;
+
// Is this record an update of an old record?
public boolean isUpdate;
private int mPackagePriority;
@@ -180,6 +185,7 @@
mRankingTimeMs = calculateRankingTimeMs(0L);
mCreationTimeMs = sbn.getPostTime();
mUpdateTimeMs = mCreationTimeMs;
+ mInterruptionTimeMs = mCreationTimeMs;
mContext = context;
stats = new NotificationUsageStats.SingleNotificationStats();
mChannel = channel;
@@ -525,6 +531,7 @@
pw.println(prefix + "mCreationTimeMs=" + mCreationTimeMs);
pw.println(prefix + "mVisibleSinceMs=" + mVisibleSinceMs);
pw.println(prefix + "mUpdateTimeMs=" + mUpdateTimeMs);
+ pw.println(prefix + "mInterruptionTimeMs=" + mInterruptionTimeMs);
pw.println(prefix + "mSuppressedVisualEffects= " + mSuppressedVisualEffects);
if (mPreChannelsNotification) {
pw.println(prefix + String.format("defaults=0x%08x flags=0x%08x",
@@ -786,6 +793,10 @@
return mVisibleSinceMs == 0 ? 0 : (int) (now - mVisibleSinceMs);
}
+ public int getInterruptionMs(long now) {
+ return (int) (now - mInterruptionTimeMs);
+ }
+
/**
* Set the visibility of the notification.
*/
@@ -844,7 +855,7 @@
public void setSeen() {
mStats.setSeen();
if (mTextChanged) {
- mIsInterruptive = true;
+ setInterruptive(true);
}
}
@@ -940,6 +951,17 @@
public void setInterruptive(boolean interruptive) {
mIsInterruptive = interruptive;
+ final long now = System.currentTimeMillis();
+ mInterruptionTimeMs = interruptive ? now : mInterruptionTimeMs;
+
+ if (interruptive) {
+ MetricsLogger.action(getLogMaker()
+ .setCategory(MetricsEvent.NOTIFICATION_INTERRUPTION)
+ .setType(MetricsEvent.TYPE_OPEN)
+ .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_INTERRUPTION_MILLIS,
+ getInterruptionMs(now)));
+ MetricsLogger.histogram(mContext, "note_interruptive", getInterruptionMs(now));
+ }
}
public void setTextChanged(boolean textChanged) {
@@ -1116,7 +1138,9 @@
sbn.getNotification().isGroupSummary() ? 1 : 0)
.addTaggedData(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS, getLifespanMs(now))
.addTaggedData(MetricsEvent.NOTIFICATION_SINCE_UPDATE_MILLIS, getFreshnessMs(now))
- .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS, getExposureMs(now));
+ .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS, getExposureMs(now))
+ .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_INTERRUPTION_MILLIS,
+ getInterruptionMs(now));
}
public LogMaker getLogMaker() {
diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
index 079f3ea..65ccecd 100644
--- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
+++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
@@ -21,7 +21,6 @@
import android.annotation.UserIdInt;
import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
-import android.app.ActivityTaskManagerInternal;
import android.app.AppOpsManager;
import android.app.IApplicationThread;
import android.content.ComponentName;
@@ -42,6 +41,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
+import com.android.server.wm.ActivityTaskManagerInternal;
import java.util.ArrayList;
import java.util.List;
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index a52470d..9323040 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -20,7 +20,6 @@
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
-import android.app.ActivityTaskManagerInternal;
import android.app.AppGlobals;
import android.app.IApplicationThread;
import android.app.PendingIntent;
@@ -64,6 +63,7 @@
import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.wm.ActivityTaskManagerInternal;
import java.util.Collections;
import java.util.List;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e5e8648..c536e4d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -60,7 +60,6 @@
import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
import static android.content.pm.PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
import static android.content.pm.PackageManager.INSTALL_INTERNAL;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
@@ -91,12 +90,10 @@
import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
import static android.system.OsConstants.O_CREAT;
import static android.system.OsConstants.O_RDWR;
-
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT;
import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
-import static com.android.internal.util.ArrayUtils.appendInt;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
@@ -123,7 +120,6 @@
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
-import android.app.ActivityTaskManagerInternal;
import android.app.AppOpsManager;
import android.app.IActivityManager;
import android.app.ResourcesManager;
@@ -323,11 +319,7 @@
import com.android.server.pm.permission.PermissionsState.PermissionState;
import com.android.server.security.VerityUtils;
import com.android.server.storage.DeviceStorageMonitorInternal;
-
-import dalvik.system.CloseGuard;
-import dalvik.system.VMRuntime;
-
-import libcore.io.IoUtils;
+import com.android.server.wm.ActivityTaskManagerInternal;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -373,6 +365,10 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Predicate;
+import dalvik.system.CloseGuard;
+import dalvik.system.VMRuntime;
+import libcore.io.IoUtils;
+
/**
* Keep track of all those APKs everywhere.
* <p>
@@ -434,7 +430,6 @@
private static final boolean DEBUG_ABI_SELECTION = false;
private static final boolean DEBUG_INSTANT = Build.IS_DEBUGGABLE;
- private static final boolean DEBUG_TRIAGED_MISSING = false;
private static final boolean DEBUG_APP_DATA = false;
/** REMOVE. According to Svet, this was only used to reset permissions during development. */
@@ -452,10 +447,6 @@
private static final int SHELL_UID = Process.SHELL_UID;
private static final int SE_UID = Process.SE_UID;
- // Suffix used during package installation when copying/moving
- // package apks to install directory.
- private static final String INSTALL_PACKAGE_SUFFIX = "-";
-
static final int SCAN_NO_DEX = 1<<0;
static final int SCAN_UPDATE_SIGNATURE = 1<<1;
static final int SCAN_NEW_INSTALL = 1<<2;
@@ -693,11 +684,7 @@
// as the lock for the global state. Methods that must be called with
// this lock held have the prefix "LP".
@GuardedBy("mPackages")
- final ArrayMap<String, PackageParser.Package> mPackages =
- new ArrayMap<String, PackageParser.Package>();
-
- final ArrayMap<String, Set<String>> mKnownCodebase =
- new ArrayMap<String, Set<String>>();
+ final ArrayMap<String, PackageParser.Package> mPackages = new ArrayMap<>();
// Keys are isolated uids and values are the uid of the application
// that created the isolated proccess.
@@ -796,18 +783,15 @@
for (PackageParser.Package p : allPackages) {
if (targetPackageName.equals(p.mOverlayTarget) && p.mOverlayIsStatic) {
if (overlayPackages == null) {
- overlayPackages = new ArrayList<PackageParser.Package>();
+ overlayPackages = new ArrayList<>();
}
overlayPackages.add(p);
}
}
if (overlayPackages != null) {
- Comparator<PackageParser.Package> cmp = new Comparator<PackageParser.Package>() {
- public int compare(PackageParser.Package p1, PackageParser.Package p2) {
- return p1.mOverlayPriority - p2.mOverlayPriority;
- }
- };
- Collections.sort(overlayPackages, cmp);
+ Comparator<PackageParser.Package> cmp =
+ Comparator.comparingInt(p -> p.mOverlayPriority);
+ overlayPackages.sort(cmp);
}
return overlayPackages;
}
@@ -821,7 +805,7 @@
for (PackageParser.Package overlayPackage : overlayPackages) {
if (targetPath == null) {
if (overlayPathList == null) {
- overlayPathList = new ArrayList<String>();
+ overlayPathList = new ArrayList<>();
}
overlayPathList.add(overlayPackage.baseCodePath);
continue;
@@ -837,7 +821,7 @@
UserHandle.getSharedAppGid(
UserHandle.getUserGid(UserHandle.USER_SYSTEM)));
if (overlayPathList == null) {
- overlayPathList = new ArrayList<String>();
+ overlayPathList = new ArrayList<>();
}
overlayPathList.add(overlayPackage.baseCodePath);
} catch (InstallerException e) {
@@ -879,7 +863,7 @@
for (PackageParser.Package p : mPackages.values()) {
if (p.mOverlayIsStatic) {
if (mOverlayPackages == null) {
- mOverlayPackages = new ArrayList<PackageParser.Package>();
+ mOverlayPackages = new ArrayList<>();
}
mOverlayPackages.add(p);
}
@@ -940,24 +924,22 @@
// Mapping from provider base names (first directory in content URI codePath)
// to the provider information.
- final ArrayMap<String, PackageParser.Provider> mProvidersByAuthority =
- new ArrayMap<String, PackageParser.Provider>();
+ final ArrayMap<String, PackageParser.Provider> mProvidersByAuthority = new ArrayMap<>();
// Mapping from instrumentation class names to info about them.
final ArrayMap<ComponentName, PackageParser.Instrumentation> mInstrumentation =
- new ArrayMap<ComponentName, PackageParser.Instrumentation>();
+ new ArrayMap<>();
// Packages whose data we have transfered into another package, thus
// should no longer exist.
- final ArraySet<String> mTransferedPackages = new ArraySet<String>();
+ final ArraySet<String> mTransferedPackages = new ArraySet<>();
// Broadcast actions that are only available to the system.
@GuardedBy("mProtectedBroadcasts")
final ArraySet<String> mProtectedBroadcasts = new ArraySet<>();
/** List of packages waiting for verification. */
- final SparseArray<PackageVerificationState> mPendingVerification
- = new SparseArray<PackageVerificationState>();
+ final SparseArray<PackageVerificationState> mPendingVerification = new SparseArray<>();
final PackageInstallerService mInstallerService;
@@ -1008,7 +990,7 @@
final ResolveInfo mInstantAppInstallerInfo = new ResolveInfo();
final SparseArray<IntentFilterVerificationState> mIntentFilterVerificationStates
- = new SparseArray<IntentFilterVerificationState>();
+ = new SparseArray<>();
// TODO remove this and go through mPermissonManager directly
final DefaultPermissionGrantPolicy mDefaultPermissionPolicy;
@@ -1038,7 +1020,6 @@
pkg = _pkg;
replacing = _replacing;
userId = _userId;
- replacing = _replacing;
verifierUid = _verifierUid;
}
}
@@ -1053,7 +1034,7 @@
private class IntentVerifierProxy implements IntentFilterVerifier<ActivityIntentInfo> {
private Context mContext;
private ComponentName mIntentFilterVerifierComponent;
- private ArrayList<Integer> mCurrentIntentFilterVerifications = new ArrayList<Integer>();
+ private ArrayList<Integer> mCurrentIntentFilterVerifications = new ArrayList<>();
public IntentVerifierProxy(Context context, ComponentName verifierComponent) {
mContext = context;
@@ -1143,7 +1124,7 @@
mIntentFilterVerificationStates.remove(verificationId);
final String packageName = ivs.getPackageName();
- IntentFilterVerificationInfo ivi = null;
+ IntentFilterVerificationInfo ivi;
synchronized (mPackages) {
ivi = mSettings.getIntentFilterVerificationLPr(packageName);
@@ -1248,7 +1229,7 @@
final SparseArray<ArrayMap<String, ArrayList<String>>> mUidMap;
public PendingPackageBroadcasts() {
- mUidMap = new SparseArray<ArrayMap<String, ArrayList<String>>>(2);
+ mUidMap = new SparseArray<>(2);
}
public ArrayList<String> get(int userId, String packageName) {
@@ -1300,7 +1281,7 @@
private ArrayMap<String, ArrayList<String>> getOrAllocate(int userId) {
ArrayMap<String, ArrayList<String>> map = mUidMap.get(userId);
if (map == null) {
- map = new ArrayMap<String, ArrayList<String>>();
+ map = new ArrayMap<>();
mUidMap.put(userId, map);
}
return map;
@@ -1315,11 +1296,9 @@
static final int SEND_PENDING_BROADCAST = 1;
static final int MCS_BOUND = 3;
- static final int END_COPY = 4;
static final int INIT_COPY = 5;
static final int MCS_UNBIND = 6;
static final int START_CLEANING_PACKAGE = 7;
- static final int FIND_INSTALL_LOC = 8;
static final int POST_INSTALL = 9;
static final int MCS_RECONNECT = 10;
static final int MCS_GIVE_UP = 11;
@@ -1344,7 +1323,7 @@
static UserManagerService sUserManager;
// Stores a list of users whose package restrictions file needs to be updated
- private ArraySet<Integer> mDirtyUsers = new ArraySet<Integer>();
+ private ArraySet<Integer> mDirtyUsers = new ArraySet<>();
final private DefaultContainerConnection mDefContainerConn =
new DefaultContainerConnection();
@@ -1373,7 +1352,7 @@
}
}
- final SparseArray<PostInstallData> mRunningInstalls = new SparseArray<PostInstallData>();
+ final SparseArray<PostInstallData> mRunningInstalls = new SparseArray<>();
int mNextInstallToken = 1; // nonzero; will be wrapped back to 1 when ++ overflows
// XML tags for backup/restore of various bits of state
@@ -1420,7 +1399,7 @@
class PackageHandler extends Handler {
private boolean mBound = false;
final ArrayList<HandlerParams> mPendingInstalls =
- new ArrayList<HandlerParams>();
+ new ArrayList<>();
private boolean connectToService() {
if (DEBUG_INSTALL) Log.i(TAG, "Trying to bind to DefaultContainerService");
@@ -1626,9 +1605,6 @@
int uids[];
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
synchronized (mPackages) {
- if (mPendingBroadcasts == null) {
- return;
- }
size = mPendingBroadcasts.size();
if (size <= 0) {
// Nothing to be done. Just return
@@ -1903,12 +1879,7 @@
private PermissionCallback mPermissionCallback = new PermissionCallback() {
@Override
public void onGidsChanged(int appId, int userId) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- killUid(appId, userId, KILL_APP_REASON_GIDS_CHANGED);
- }
- });
+ mHandler.post(() -> killUid(appId, userId, KILL_APP_REASON_GIDS_CHANGED));
}
@Override
public void onPermissionGranted(int uid, int userId) {
@@ -2548,13 +2519,11 @@
requestCopyPreoptedFiles();
}
- String customResolverActivity = Resources.getSystem().getString(
+ String customResolverActivityName = Resources.getSystem().getString(
R.string.config_customResolverActivity);
- if (TextUtils.isEmpty(customResolverActivity)) {
- customResolverActivity = null;
- } else {
+ if (!TextUtils.isEmpty(customResolverActivityName)) {
mCustomResolverComponentName = ComponentName.unflattenFromString(
- customResolverActivity);
+ customResolverActivityName);
}
long startTime = SystemClock.uptimeMillis();
@@ -3404,7 +3373,7 @@
}
}
if (ret != PackageManager.INSTALL_SUCCEEDED) {
- if (dstCodePath == null || !dstCodePath.exists()) {
+ if (!dstCodePath.exists()) {
return null;
}
removeCodePathLI(dstCodePath);
@@ -3755,7 +3724,7 @@
for (ActivityIntentInfo filter : a.intents) {
if (hasValidDomains(filter)) {
if (domains == null) {
- domains = new ArraySet<String>();
+ domains = new ArraySet<>();
}
domains.addAll(filter.getHostsList());
}
@@ -3822,7 +3791,7 @@
PackageManager.MATCH_ALL, userId);
final int count = list.size();
- List<String> result = new ArrayList<String>(count);
+ List<String> result = new ArrayList<>(count);
for (int i=0; i<count; i++) {
ResolveInfo info = list.get(i);
if (info.activityInfo == null
@@ -3877,16 +3846,6 @@
}
}
- static int[] appendInts(int[] cur, int[] add) {
- if (add == null) return cur;
- if (cur == null) return add;
- final int N = add.length;
- for (int i=0; i<N; i++) {
- cur = appendInt(cur, add[i]);
- }
- return cur;
- }
-
/**
* Returns whether or not a full application can see an instant application.
* <p>
@@ -3950,7 +3909,7 @@
? EMPTY_INT_ARRAY : permissionsState.computeGids(userId);
// Compute granted permissions only if package has requested permissions
final Set<String> permissions = ArrayUtils.isEmpty(p.requestedPermissions)
- ? Collections.<String>emptySet() : permissionsState.getPermissions(userId);
+ ? Collections.emptySet() : permissionsState.getPermissions(userId);
PackageInfo packageInfo = PackageParser.generatePackageInfo(p, gids, flags,
ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId);
@@ -4790,22 +4749,6 @@
*/
private int updateFlagsForPackage(int flags, int userId, Object cookie) {
final boolean isCallerSystemUser = UserHandle.getCallingUserId() == UserHandle.USER_SYSTEM;
- boolean triaged = true;
- if ((flags & (PackageManager.GET_ACTIVITIES | PackageManager.GET_RECEIVERS
- | PackageManager.GET_SERVICES | PackageManager.GET_PROVIDERS)) != 0) {
- // Caller is asking for component details, so they'd better be
- // asking for specific encryption matching behavior, or be triaged
- if ((flags & (PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DEBUG_TRIAGED_MISSING)) == 0) {
- triaged = false;
- }
- }
- if ((flags & (PackageManager.MATCH_UNINSTALLED_PACKAGES
- | PackageManager.MATCH_SYSTEM_ONLY
- | PackageManager.MATCH_DEBUG_TRIAGED_MISSING)) == 0) {
- triaged = false;
- }
if ((flags & PackageManager.MATCH_ANY_USER) != 0) {
// require the permission to be held; the calling uid and given user id referring
// to the same user is not sufficient
@@ -4822,10 +4765,6 @@
// MATCH_UNINSTALLED_PACKAGES to query apps in other profiles. b/31000380
flags |= PackageManager.MATCH_ANY_USER;
}
- if (DEBUG_TRIAGED_MISSING && (Binder.getCallingUid() == Process.SYSTEM_UID) && !triaged) {
- Log.w(TAG, "Caller hasn't been triaged for missing apps; they asked about " + cookie
- + " with flags 0x" + Integer.toHexString(flags), new Throwable());
- }
return updateFlags(flags, userId);
}
@@ -4840,25 +4779,6 @@
* Update given flags when being used to request {@link ComponentInfo}.
*/
private int updateFlagsForComponent(int flags, int userId, Object cookie) {
- if (cookie instanceof Intent) {
- if ((((Intent) cookie).getFlags() & Intent.FLAG_DEBUG_TRIAGED_MISSING) != 0) {
- flags |= PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
- }
- }
-
- boolean triaged = true;
- // Caller is asking for component details, so they'd better be
- // asking for specific encryption matching behavior, or be triaged
- if ((flags & (PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DEBUG_TRIAGED_MISSING)) == 0) {
- triaged = false;
- }
- if (DEBUG_TRIAGED_MISSING && (Binder.getCallingUid() == Process.SYSTEM_UID) && !triaged) {
- Log.w(TAG, "Caller hasn't been triaged for missing apps; they asked about " + cookie
- + " with flags 0x" + Integer.toHexString(flags), new Throwable());
- }
-
return updateFlags(flags, userId);
}
@@ -5766,7 +5686,7 @@
final int callingUserId = UserHandle.getUserId(callingUid);
synchronized (mPackages) {
if (canViewInstantApps(callingUid, callingUserId)) {
- return new ArrayList<String>(mPackages.keySet());
+ return new ArrayList<>(mPackages.keySet());
}
final String instantAppPkgName = getInstantAppPackageName(callingUid);
final List<String> result = new ArrayList<>();
@@ -6638,7 +6558,7 @@
flags = updateFlagsForResolve(flags, userId, intent, filterCallingUid, resolveForStart,
comp != null || pkgName != null /*onlyExposedExplicitly*/);
if (comp != null) {
- final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
+ final List<ResolveInfo> list = new ArrayList<>(1);
final ActivityInfo ai = getActivityInfo(comp, flags, userId);
if (ai != null) {
// When specifying an explicit component, we prevent the activity from being
@@ -6694,7 +6614,7 @@
ResolveInfo xpResolveInfo = querySkipCurrentProfileIntents(matchingFilters, intent,
resolvedType, flags, userId);
if (xpResolveInfo != null) {
- List<ResolveInfo> xpResult = new ArrayList<ResolveInfo>(1);
+ List<ResolveInfo> xpResult = new ArrayList<>(1);
xpResult.add(xpResolveInfo);
return applyPostResolutionFilter(
filterIfNotSystemUser(xpResult, userId), instantAppPkgName,
@@ -7119,12 +7039,12 @@
candidates.size());
}
- ArrayList<ResolveInfo> result = new ArrayList<ResolveInfo>();
- ArrayList<ResolveInfo> alwaysList = new ArrayList<ResolveInfo>();
- ArrayList<ResolveInfo> undefinedList = new ArrayList<ResolveInfo>();
- ArrayList<ResolveInfo> alwaysAskList = new ArrayList<ResolveInfo>();
- ArrayList<ResolveInfo> neverList = new ArrayList<ResolveInfo>();
- ArrayList<ResolveInfo> matchAllList = new ArrayList<ResolveInfo>();
+ final ArrayList<ResolveInfo> result = new ArrayList<>();
+ final ArrayList<ResolveInfo> alwaysList = new ArrayList<>();
+ final ArrayList<ResolveInfo> undefinedList = new ArrayList<>();
+ final ArrayList<ResolveInfo> alwaysAskList = new ArrayList<>();
+ final ArrayList<ResolveInfo> neverList = new ArrayList<>();
+ final ArrayList<ResolveInfo> matchAllList = new ArrayList<>();
synchronized (mPackages) {
final int count = candidates.size();
@@ -7599,7 +7519,7 @@
}
}
if (comp != null) {
- final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
+ final List<ResolveInfo> list = new ArrayList<>(1);
final ActivityInfo ai = getReceiverInfo(comp, flags, userId);
if (ai != null) {
// When specifying an explicit component, we prevent the activity from being
@@ -7713,7 +7633,7 @@
}
}
if (comp != null) {
- final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
+ final List<ResolveInfo> list = new ArrayList<>(1);
final ServiceInfo si = getServiceInfo(comp, flags, userId);
if (si != null) {
// When specifying an explicit component, we prevent the service from being
@@ -7831,7 +7751,7 @@
}
}
if (comp != null) {
- final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
+ final List<ResolveInfo> list = new ArrayList<>(1);
final ProviderInfo pi = getProviderInfo(comp, flags, userId);
if (pi != null) {
// When specifying an explicit component, we prevent the provider from being
@@ -8030,7 +7950,7 @@
// writer
synchronized (mPackages) {
- ArrayList<PackageInfo> list = new ArrayList<PackageInfo>();
+ ArrayList<PackageInfo> list = new ArrayList<>();
boolean[] tmpBools = new boolean[permissions.length];
if (listUninstalled) {
for (PackageSetting ps : mSettings.mPackages.values()) {
@@ -8047,7 +7967,7 @@
}
}
- return new ParceledListSlice<PackageInfo>(list);
+ return new ParceledListSlice<>(list);
}
}
@@ -8248,7 +8168,7 @@
}
private @NonNull List<ApplicationInfo> getPersistentApplicationsInternal(int flags) {
- final ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>();
+ final ArrayList<ApplicationInfo> finalList = new ArrayList<>();
// reader
synchronized (mPackages) {
@@ -8377,7 +8297,7 @@
continue;
}
if (finalList == null) {
- finalList = new ArrayList<ProviderInfo>(3);
+ finalList = new ArrayList<>(3);
}
ProviderInfo info = PackageParser.generateProviderInfo(p, flags,
ps.readUserState(userId), userId);
@@ -8389,8 +8309,8 @@
}
if (finalList != null) {
- Collections.sort(finalList, mProviderInitOrderSorter);
- return new ParceledListSlice<ProviderInfo>(finalList);
+ finalList.sort(mProviderInitOrderSorter);
+ return new ParceledListSlice<>(finalList);
}
return ParceledListSlice.emptyList();
@@ -8426,7 +8346,7 @@
private @NonNull List<InstrumentationInfo> queryInstrumentationInternal(String targetPackage,
int flags) {
- ArrayList<InstrumentationInfo> finalList = new ArrayList<InstrumentationInfo>();
+ ArrayList<InstrumentationInfo> finalList = new ArrayList<>();
// reader
synchronized (mPackages) {
@@ -8496,10 +8416,8 @@
renameStaticSharedLibraryPackage(parseResult.pkg);
}
try {
- if (errorCode == PackageManager.INSTALL_SUCCEEDED) {
- scanPackageChildLI(parseResult.pkg, parseFlags, scanFlags,
- currentTime, null);
- }
+ scanPackageChildLI(parseResult.pkg, parseFlags, scanFlags,
+ currentTime, null);
} catch (PackageManagerException e) {
errorCode = e.error;
Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": " + e.getMessage());
@@ -8701,7 +8619,7 @@
* match one in a trusted source, and should be done separately.
*/
private boolean canSkipFullApkVerification(String apkPath) {
- byte[] rootHashObserved = null;
+ final byte[] rootHashObserved;
try {
rootHashObserved = VerityUtils.generateFsverityRootHash(apkPath);
if (rootHashObserved == null) {
@@ -8967,7 +8885,7 @@
* @param message used as message if SecurityException is thrown
* @throws SecurityException if the caller is not system or root
*/
- private static final void enforceSystemOrRoot(String message) {
+ private static void enforceSystemOrRoot(String message) {
final int uid = Binder.getCallingUid();
if (uid != Process.SYSTEM_UID && uid != Process.ROOT_UID) {
throw new SecurityException(message);
@@ -9370,7 +9288,7 @@
}
public ArraySet<String> getOptimizablePackages() {
- ArraySet<String> pkgs = new ArraySet<String>();
+ ArraySet<String> pkgs = new ArraySet<>();
synchronized (mPackages) {
for (PackageParser.Package p : mPackages.values()) {
if (PackageDexOptimizer.canOptimizePackage(p)) {
@@ -12946,9 +12864,7 @@
if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {
res.filter = info;
}
- if (info != null) {
- res.handleAllWebDataURI = info.handleAllWebDataURI();
- }
+ res.handleAllWebDataURI = info.handleAllWebDataURI();
res.priority = info.getPriority();
res.preferredOrder = activity.owner.mPreferredOrder;
//System.out.println("Result: " + res.activityInfo.className +
@@ -12970,7 +12886,7 @@
@Override
protected void sortResults(List<ResolveInfo> results) {
- Collections.sort(results, mResolvePrioritySorter);
+ results.sort(mResolvePrioritySorter);
}
@Override
@@ -13003,7 +12919,7 @@
// Keys are String (activity class name), values are Activity.
private final ArrayMap<ComponentName, PackageParser.Activity> mActivities
- = new ArrayMap<ComponentName, PackageParser.Activity>();
+ = new ArrayMap<>();
private int mFlags;
}
@@ -13033,8 +12949,7 @@
mFlags = flags;
final boolean defaultOnly = (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0;
final int N = packageServices.size();
- ArrayList<PackageParser.ServiceIntentInfo[]> listCut =
- new ArrayList<PackageParser.ServiceIntentInfo[]>(N);
+ ArrayList<PackageParser.ServiceIntentInfo[]> listCut = new ArrayList<>(N);
ArrayList<PackageParser.ServiceIntentInfo> intentFilters;
for (int i = 0; i < N; ++i) {
@@ -13187,7 +13102,7 @@
@Override
protected void sortResults(List<ResolveInfo> results) {
- Collections.sort(results, mResolvePrioritySorter);
+ results.sort(mResolvePrioritySorter);
}
@Override
@@ -13236,8 +13151,7 @@
// }
// Keys are String (activity class name), values are Activity.
- private final ArrayMap<ComponentName, PackageParser.Service> mServices
- = new ArrayMap<ComponentName, PackageParser.Service>();
+ private final ArrayMap<ComponentName, PackageParser.Service> mServices = new ArrayMap<>();
private int mFlags;
}
@@ -13269,8 +13183,7 @@
mFlags = flags;
final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0;
final int N = packageProviders.size();
- ArrayList<PackageParser.ProviderIntentInfo[]> listCut =
- new ArrayList<PackageParser.ProviderIntentInfo[]>(N);
+ ArrayList<PackageParser.ProviderIntentInfo[]> listCut = new ArrayList<>(N);
ArrayList<PackageParser.ProviderIntentInfo> intentFilters;
for (int i = 0; i < N; ++i) {
@@ -13430,7 +13343,7 @@
@Override
protected void sortResults(List<ResolveInfo> results) {
- Collections.sort(results, mResolvePrioritySorter);
+ results.sort(mResolvePrioritySorter);
}
@Override
@@ -13463,7 +13376,7 @@
}
private final ArrayMap<ComponentName, PackageParser.Provider> mProviders
- = new ArrayMap<ComponentName, PackageParser.Provider>();
+ = new ArrayMap<>();
private int mFlags;
}
@@ -13548,78 +13461,69 @@
}
}
- private static final Comparator<ResolveInfo> mResolvePrioritySorter =
- new Comparator<ResolveInfo>() {
- public int compare(ResolveInfo r1, ResolveInfo r2) {
- int v1 = r1.priority;
- int v2 = r2.priority;
- //System.out.println("Comparing: q1=" + q1 + " q2=" + q2);
- if (v1 != v2) {
- return (v1 > v2) ? -1 : 1;
- }
- v1 = r1.preferredOrder;
- v2 = r2.preferredOrder;
- if (v1 != v2) {
- return (v1 > v2) ? -1 : 1;
- }
- if (r1.isDefault != r2.isDefault) {
- return r1.isDefault ? -1 : 1;
- }
- v1 = r1.match;
- v2 = r2.match;
- //System.out.println("Comparing: m1=" + m1 + " m2=" + m2);
- if (v1 != v2) {
- return (v1 > v2) ? -1 : 1;
- }
- if (r1.system != r2.system) {
- return r1.system ? -1 : 1;
- }
- if (r1.activityInfo != null) {
- return r1.activityInfo.packageName.compareTo(r2.activityInfo.packageName);
- }
- if (r1.serviceInfo != null) {
- return r1.serviceInfo.packageName.compareTo(r2.serviceInfo.packageName);
- }
- if (r1.providerInfo != null) {
- return r1.providerInfo.packageName.compareTo(r2.providerInfo.packageName);
- }
- return 0;
+ private static final Comparator<ResolveInfo> mResolvePrioritySorter = (r1, r2) -> {
+ int v1 = r1.priority;
+ int v2 = r2.priority;
+ //System.out.println("Comparing: q1=" + q1 + " q2=" + q2);
+ if (v1 != v2) {
+ return (v1 > v2) ? -1 : 1;
}
+ v1 = r1.preferredOrder;
+ v2 = r2.preferredOrder;
+ if (v1 != v2) {
+ return (v1 > v2) ? -1 : 1;
+ }
+ if (r1.isDefault != r2.isDefault) {
+ return r1.isDefault ? -1 : 1;
+ }
+ v1 = r1.match;
+ v2 = r2.match;
+ //System.out.println("Comparing: m1=" + m1 + " m2=" + m2);
+ if (v1 != v2) {
+ return (v1 > v2) ? -1 : 1;
+ }
+ if (r1.system != r2.system) {
+ return r1.system ? -1 : 1;
+ }
+ if (r1.activityInfo != null) {
+ return r1.activityInfo.packageName.compareTo(r2.activityInfo.packageName);
+ }
+ if (r1.serviceInfo != null) {
+ return r1.serviceInfo.packageName.compareTo(r2.serviceInfo.packageName);
+ }
+ if (r1.providerInfo != null) {
+ return r1.providerInfo.packageName.compareTo(r2.providerInfo.packageName);
+ }
+ return 0;
};
- private static final Comparator<ProviderInfo> mProviderInitOrderSorter =
- new Comparator<ProviderInfo>() {
- public int compare(ProviderInfo p1, ProviderInfo p2) {
- final int v1 = p1.initOrder;
- final int v2 = p2.initOrder;
- return (v1 > v2) ? -1 : ((v1 < v2) ? 1 : 0);
- }
+ private static final Comparator<ProviderInfo> mProviderInitOrderSorter = (p1, p2) -> {
+ final int v1 = p1.initOrder;
+ final int v2 = p2.initOrder;
+ return (v1 > v2) ? -1 : ((v1 < v2) ? 1 : 0);
};
@Override
public void sendPackageBroadcast(final String action, final String pkg, final Bundle extras,
final int flags, final String targetPkg, final IIntentReceiver finishedReceiver,
final int[] userIds, int[] instantUserIds) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- try {
- final IActivityManager am = ActivityManager.getService();
- if (am == null) return;
- final int[] resolvedUserIds;
- if (userIds == null) {
- resolvedUserIds = am.getRunningUserIds();
- } else {
- resolvedUserIds = userIds;
- }
- doSendBroadcast(am, action, pkg, extras, flags, targetPkg, finishedReceiver,
- resolvedUserIds, false);
- if (instantUserIds != null && instantUserIds != EMPTY_INT_ARRAY) {
- doSendBroadcast(am, action, pkg, extras, flags, targetPkg, finishedReceiver,
- instantUserIds, true);
- }
- } catch (RemoteException ex) {
+ mHandler.post(() -> {
+ try {
+ final IActivityManager am = ActivityManager.getService();
+ if (am == null) return;
+ final int[] resolvedUserIds;
+ if (userIds == null) {
+ resolvedUserIds = am.getRunningUserIds();
+ } else {
+ resolvedUserIds = userIds;
}
+ doSendBroadcast(am, action, pkg, extras, flags, targetPkg, finishedReceiver,
+ resolvedUserIds, false);
+ if (instantUserIds != null && instantUserIds != EMPTY_INT_ARRAY) {
+ doSendBroadcast(am, action, pkg, extras, flags, targetPkg, finishedReceiver,
+ instantUserIds, true);
+ }
+ } catch (RemoteException ex) {
}
});
}
@@ -14018,6 +13922,68 @@
return false;
}
+ @Override
+ public void setSystemAppHiddenUntilInstalled(String packageName, boolean hidden) {
+ enforceSystemOrPhoneCaller("setSystemAppHiddenUntilInstalled");
+ synchronized (mPackages) {
+ final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
+ if (pkgSetting == null || !pkgSetting.isSystem()) {
+ return;
+ }
+ PackageParser.Package pkg = pkgSetting.pkg;
+ if (pkg != null && pkg.applicationInfo != null) {
+ pkg.applicationInfo.hiddenUntilInstalled = hidden;
+ }
+ final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(packageName);
+ if (disabledPs == null) {
+ return;
+ }
+ pkg = disabledPs.pkg;
+ if (pkg != null && pkg.applicationInfo != null) {
+ pkg.applicationInfo.hiddenUntilInstalled = hidden;
+ }
+ }
+ }
+
+ @Override
+ public boolean setSystemAppInstallState(String packageName, boolean installed, int userId) {
+ enforceSystemOrPhoneCaller("setSystemAppInstallState");
+ synchronized (mPackages) {
+ final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
+ // The target app should always be in system
+ if (pkgSetting == null || !pkgSetting.isSystem()) {
+ return false;
+ }
+ // Check if the install state is the same
+ if (pkgSetting.getInstalled(userId) == installed) {
+ return false;
+ }
+ }
+
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ if (installed) {
+ // install the app from uninstalled state
+ installExistingPackageAsUser(
+ packageName,
+ userId,
+ 0 /*installFlags*/,
+ PackageManager.INSTALL_REASON_DEVICE_SETUP);
+ return true;
+ }
+
+ // uninstall the app from installed state
+ deletePackageVersioned(
+ new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST),
+ new LegacyPackageDeleteObserver(null).getBinder(),
+ userId,
+ PackageManager.DELETE_SYSTEM_APP);
+ return true;
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+
private void sendApplicationHiddenForUser(String packageName, PackageSetting pkgSetting,
int userId) {
final PackageRemovedInfo info = new PackageRemovedInfo(this);
@@ -14082,10 +14048,16 @@
@Override
public int installExistingPackageAsUser(String packageName, int userId, int installFlags,
int installReason) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES,
- null);
- PackageSetting pkgSetting;
final int callingUid = Binder.getCallingUid();
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES)
+ != PackageManager.PERMISSION_GRANTED
+ && mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.INSTALL_EXISTING_PACKAGES)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Neither user " + callingUid + " nor current process has "
+ + android.Manifest.permission.INSTALL_PACKAGES + ".");
+ }
+ PackageSetting pkgSetting;
mPermissionManager.enforceCrossUserPermission(callingUid, userId,
true /* requireFullPermission */, true /* checkShell */,
"installExistingPackage for user " + userId);
@@ -14286,25 +14258,22 @@
} else {
action = Intent.ACTION_MY_PACKAGE_UNSUSPENDED;
}
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- try {
- final IActivityManager am = ActivityManager.getService();
- if (am == null) {
- Slog.wtf(TAG, "IActivityManager null. Cannot send MY_PACKAGE_ "
- + (suspended ? "" : "UN") + "SUSPENDED broadcasts");
- return;
- }
- final int[] targetUserIds = new int[] {userId};
- for (String packageName : affectedPackages) {
- doSendBroadcast(am, action, null, intentExtras,
- Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, packageName, null,
- targetUserIds, false);
- }
- } catch (RemoteException ex) {
- // Shouldn't happen as AMS is in the same process.
+ mHandler.post(() -> {
+ try {
+ final IActivityManager am = ActivityManager.getService();
+ if (am == null) {
+ Slog.wtf(TAG, "IActivityManager null. Cannot send MY_PACKAGE_ "
+ + (suspended ? "" : "UN") + "SUSPENDED broadcasts");
+ return;
}
+ final int[] targetUserIds = new int[] {userId};
+ for (String packageName : affectedPackages) {
+ doSendBroadcast(am, action, null, intentExtras,
+ Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, packageName, null,
+ targetUserIds, false);
+ }
+ } catch (RemoteException ex) {
+ // Shouldn't happen as AMS is in the same process.
}
});
}
@@ -14552,7 +14521,7 @@
}
final int N = pkgInfo.verifiers.length;
- final List<ComponentName> sufficientVerifiers = new ArrayList<ComponentName>(N + 1);
+ final List<ComponentName> sufficientVerifiers = new ArrayList<>(N + 1);
for (int i = 0; i < N; i++) {
final VerifierInfo verifierInfo = pkgInfo.verifiers[i];
@@ -15062,36 +15031,33 @@
// are coherent. In the non-restore case, the app has already completed install
// and been launched through some other means, so it is not in a problematic
// state for observers to see the FIRST_LAUNCH signal.
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- for (int i = 0; i < mRunningInstalls.size(); i++) {
- final PostInstallData data = mRunningInstalls.valueAt(i);
- if (data.res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
- continue;
- }
- if (packageName.equals(data.res.pkg.applicationInfo.packageName)) {
- // right package; but is it for the right user?
- for (int uIndex = 0; uIndex < data.res.newUsers.length; uIndex++) {
- if (userId == data.res.newUsers[uIndex]) {
- if (DEBUG_BACKUP) {
- Slog.i(TAG, "Package " + packageName
- + " being restored so deferring FIRST_LAUNCH");
- }
- return;
+ mHandler.post(() -> {
+ for (int i = 0; i < mRunningInstalls.size(); i++) {
+ final PostInstallData data = mRunningInstalls.valueAt(i);
+ if (data.res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
+ continue;
+ }
+ if (packageName.equals(data.res.pkg.applicationInfo.packageName)) {
+ // right package; but is it for the right user?
+ for (int uIndex = 0; uIndex < data.res.newUsers.length; uIndex++) {
+ if (userId == data.res.newUsers[uIndex]) {
+ if (DEBUG_BACKUP) {
+ Slog.i(TAG, "Package " + packageName
+ + " being restored so deferring FIRST_LAUNCH");
}
+ return;
}
}
}
- // didn't find it, so not being restored
- if (DEBUG_BACKUP) {
- Slog.i(TAG, "Package " + packageName + " sending normal FIRST_LAUNCH");
- }
- final boolean isInstantApp = isInstantApp(packageName, userId);
- final int[] userIds = isInstantApp ? EMPTY_INT_ARRAY : new int[] { userId };
- final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY;
- sendFirstLaunchBroadcast(packageName, installerPackage, userIds, instantUserIds);
}
+ // didn't find it, so not being restored
+ if (DEBUG_BACKUP) {
+ Slog.i(TAG, "Package " + packageName + " sending normal FIRST_LAUNCH");
+ }
+ final boolean isInstantApp = isInstantApp(packageName, userId);
+ final int[] userIds = isInstantApp ? EMPTY_INT_ARRAY : new int[] { userId };
+ final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY;
+ sendFirstLaunchBroadcast(packageName, installerPackage, userIds, instantUserIds);
});
}
@@ -15920,8 +15886,7 @@
}
};
- int ret = PackageManager.INSTALL_SUCCEEDED;
- ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);
+ int ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);
if (ret != PackageManager.INSTALL_SUCCEEDED) {
Slog.e(TAG, "Failed to copy package");
return ret;
@@ -16066,17 +16031,6 @@
}
/**
- * Extract the StorageManagerService "container ID" from the full code path of an
- * .apk.
- */
- static String cidFromCodePath(String fullCodePath) {
- int eidx = fullCodePath.lastIndexOf("/");
- String subStr1 = fullCodePath.substring(0, eidx);
- int sidx = subStr1.lastIndexOf("/");
- return subStr1.substring(sidx+1, eidx);
- }
-
- /**
* Logic to handle movement of existing installed applications.
*/
class MoveInstallArgs extends InstallArgs {
@@ -16187,51 +16141,6 @@
}
}
- static String getAsecPackageName(String packageCid) {
- int idx = packageCid.lastIndexOf("-");
- if (idx == -1) {
- return packageCid;
- }
- return packageCid.substring(0, idx);
- }
-
- // Utility method used to create code paths based on package name and available index.
- private static String getNextCodePath(String oldCodePath, String prefix, String suffix) {
- String idxStr = "";
- int idx = 1;
- // Fall back to default value of idx=1 if prefix is not
- // part of oldCodePath
- if (oldCodePath != null) {
- String subStr = oldCodePath;
- // Drop the suffix right away
- if (suffix != null && subStr.endsWith(suffix)) {
- subStr = subStr.substring(0, subStr.length() - suffix.length());
- }
- // If oldCodePath already contains prefix find out the
- // ending index to either increment or decrement.
- int sidx = subStr.lastIndexOf(prefix);
- if (sidx != -1) {
- subStr = subStr.substring(sidx + prefix.length());
- if (subStr != null) {
- if (subStr.startsWith(INSTALL_PACKAGE_SUFFIX)) {
- subStr = subStr.substring(INSTALL_PACKAGE_SUFFIX.length());
- }
- try {
- idx = Integer.parseInt(subStr);
- if (idx <= 1) {
- idx++;
- } else {
- idx--;
- }
- } catch(NumberFormatException e) {
- }
- }
- }
- }
- idxStr = INSTALL_PACKAGE_SUFFIX + Integer.toString(idx);
- return prefix + idxStr;
- }
-
private File getNextCodePath(File targetDir, String packageName) {
File result;
SecureRandom random = new SecureRandom();
@@ -16442,7 +16351,7 @@
// don't allow a system upgrade unless the upgrade hash matches
if (oldPackage.restrictUpdateHash != null && oldPackage.isSystem()) {
- byte[] digestBytes = null;
+ final byte[] digestBytes;
try {
final MessageDigest digest = MessageDigest.getInstance("SHA-512");
updateDigest(digest, new File(pkg.baseCodePath));
@@ -16567,18 +16476,10 @@
boolean sysPkg = (isSystemApp(oldPackage));
if (sysPkg) {
// Set the system/privileged/oem/vendor/product flags as needed
- final boolean privileged =
- (oldPackage.applicationInfo.privateFlags
- & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
- final boolean oem =
- (oldPackage.applicationInfo.privateFlags
- & ApplicationInfo.PRIVATE_FLAG_OEM) != 0;
- final boolean vendor =
- (oldPackage.applicationInfo.privateFlags
- & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
- final boolean product =
- (oldPackage.applicationInfo.privateFlags
- & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
+ final boolean privileged = isPrivilegedApp(oldPackage);
+ final boolean oem = isOemApp(oldPackage);
+ final boolean vendor = isVendorApp(oldPackage);
+ final boolean product = isProductApp(oldPackage);
final @ParseFlags int systemParseFlags = parseFlags;
final @ScanFlags int systemScanFlags = scanFlags
| SCAN_AS_SYSTEM
@@ -16629,7 +16530,7 @@
Slog.i(TAG, "upgrading pkg " + deletedPackage + " is ASEC-hosted -> UNAVAILABLE");
}
final int[] uidArray = new int[] { deletedPackage.applicationInfo.uid };
- final ArrayList<String> pkgList = new ArrayList<String>(1);
+ final ArrayList<String> pkgList = new ArrayList<>(1);
pkgList.add(deletedPackage.applicationInfo.packageName);
sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);
}
@@ -17855,11 +17756,8 @@
}
private void deleteTempPackageFiles() {
- final FilenameFilter filter = new FilenameFilter() {
- public boolean accept(File dir, String name) {
- return name.startsWith("vmdl") && name.endsWith(".tmp");
- }
- };
+ final FilenameFilter filter =
+ (dir, name) -> name.startsWith("vmdl") && name.endsWith(".tmp");
for (File file : sDrmAppPrivateInstallDir.listFiles(filter)) {
file.delete();
}
@@ -18196,8 +18094,8 @@
return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
}
- PackageSetting uninstalledPs = null;
- PackageParser.Package pkg = null;
+ PackageSetting uninstalledPs;
+ PackageParser.Package pkg;
// for the uninstall-updates case and restricted profiles, remember the per-
// user handle installed state
@@ -18507,13 +18405,10 @@
if (userIdToKill == UserHandle.USER_ALL
|| userIdToKill >= UserHandle.USER_SYSTEM) {
// If gids changed for this user, kill all affected packages.
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- // This has to happen with no lock held.
- killApplication(deletedPs.name, deletedPs.appId,
- KILL_APP_REASON_GIDS_CHANGED);
- }
+ mHandler.post(() -> {
+ // This has to happen with no lock held.
+ killApplication(deletedPs.name, deletedPs.appId,
+ KILL_APP_REASON_GIDS_CHANGED);
});
break;
}
@@ -19455,12 +19350,8 @@
case PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: {
writeRuntimePermissions = true;
final int appId = ps.appId;
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED);
- }
- });
+ mHandler.post(
+ () -> killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED));
} break;
}
}
@@ -19538,33 +19429,31 @@
}
// Queue up an async operation since the package deletion may take a little while.
- mHandler.post(new Runnable() {
- public void run() {
- final PackageSetting ps = pkg == null ? null : (PackageSetting) pkg.mExtras;
- boolean doClearData = true;
- if (ps != null) {
- final boolean targetIsInstantApp =
- ps.getInstantApp(UserHandle.getUserId(callingUid));
- doClearData = !targetIsInstantApp
- || hasAccessInstantApps == PackageManager.PERMISSION_GRANTED;
+ mHandler.post(() -> {
+ final PackageSetting ps = pkg == null ? null : (PackageSetting) pkg.mExtras;
+ boolean doClearData = true;
+ if (ps != null) {
+ final boolean targetIsInstantApp =
+ ps.getInstantApp(UserHandle.getUserId(callingUid));
+ doClearData = !targetIsInstantApp
+ || hasAccessInstantApps == PackageManager.PERMISSION_GRANTED;
+ }
+ if (doClearData) {
+ synchronized (mInstallLock) {
+ final int flags = StorageManager.FLAG_STORAGE_DE
+ | StorageManager.FLAG_STORAGE_CE;
+ // We're only clearing cache files, so we don't care if the
+ // app is unfrozen and still able to run
+ clearAppDataLIF(pkg, userId, flags | Installer.FLAG_CLEAR_CACHE_ONLY);
+ clearAppDataLIF(pkg, userId, flags | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
}
- if (doClearData) {
- synchronized (mInstallLock) {
- final int flags = StorageManager.FLAG_STORAGE_DE
- | StorageManager.FLAG_STORAGE_CE;
- // We're only clearing cache files, so we don't care if the
- // app is unfrozen and still able to run
- clearAppDataLIF(pkg, userId, flags | Installer.FLAG_CLEAR_CACHE_ONLY);
- clearAppDataLIF(pkg, userId, flags | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
- }
- clearExternalStorageDataSync(packageName, userId, false);
- }
- if (observer != null) {
- try {
- observer.onRemoveCompleted(packageName, true);
- } catch (RemoteException e) {
- Log.i(TAG, "Observer no longer exists.");
- }
+ clearExternalStorageDataSync(packageName, userId, false);
+ }
+ if (observer != null) {
+ try {
+ observer.onRemoveCompleted(packageName, true);
+ } catch (RemoteException e) {
+ Log.i(TAG, "Observer no longer exists.");
}
}
});
@@ -19847,7 +19736,7 @@
(pa.mPref.mComponent.getPackageName().equals(packageName)
&& pa.mPref.mAlways)) {
if (removed == null) {
- removed = new ArrayList<PreferredActivity>();
+ removed = new ArrayList<>();
}
removed.add(pa);
}
@@ -20011,7 +19900,7 @@
// Mark entry for removal only if it matches the package name.
if (ppa.mComponent.getPackageName().equals(packageName)) {
if (removed == null) {
- removed = new ArrayList<PersistentPreferredActivity>();
+ removed = new ArrayList<>();
}
removed.add(ppa);
}
@@ -20050,7 +19939,6 @@
}
return;
}
-Slog.v(TAG, ":: restoreFromXml() : got to tag " + parser.getName());
// this is supposed to be TAG_PREFERRED_BACKUP
if (!expectedStartTag.equals(parser.getName())) {
if (DEBUG_BACKUP) {
@@ -20061,12 +19949,11 @@
// skip interfering stuff, then we're aligned with the backing implementation
while ((type = parser.next()) == XmlPullParser.TEXT) { }
-Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
functor.apply(parser, userId);
}
private interface BlobXmlRestorer {
- public void apply(XmlPullParser parser, int userId) throws IOException, XmlPullParserException;
+ void apply(XmlPullParser parser, int userId) throws IOException, XmlPullParserException;
}
/**
@@ -20114,15 +20001,11 @@
final XmlPullParser parser = Xml.newPullParser();
parser.setInput(new ByteArrayInputStream(backup), StandardCharsets.UTF_8.name());
restoreFromXml(parser, userId, TAG_PREFERRED_BACKUP,
- new BlobXmlRestorer() {
- @Override
- public void apply(XmlPullParser parser, int userId)
- throws XmlPullParserException, IOException {
- synchronized (mPackages) {
- mSettings.readPreferredActivitiesLPw(parser, userId);
- }
+ (readParser, readUserId) -> {
+ synchronized (mPackages) {
+ mSettings.readPreferredActivitiesLPw(readParser, readUserId);
}
- } );
+ });
} catch (Exception e) {
if (DEBUG_BACKUP) {
Slog.e(TAG, "Exception restoring preferred activities: " + e.getMessage());
@@ -20175,15 +20058,11 @@
final XmlPullParser parser = Xml.newPullParser();
parser.setInput(new ByteArrayInputStream(backup), StandardCharsets.UTF_8.name());
restoreFromXml(parser, userId, TAG_DEFAULT_APPS,
- new BlobXmlRestorer() {
- @Override
- public void apply(XmlPullParser parser, int userId)
- throws XmlPullParserException, IOException {
- synchronized (mPackages) {
- mSettings.readDefaultAppsLPw(parser, userId);
- }
+ (parser1, userId1) -> {
+ synchronized (mPackages) {
+ mSettings.readDefaultAppsLPw(parser1, userId1);
}
- } );
+ });
} catch (Exception e) {
if (DEBUG_BACKUP) {
Slog.e(TAG, "Exception restoring default apps: " + e.getMessage());
@@ -20231,16 +20110,12 @@
final XmlPullParser parser = Xml.newPullParser();
parser.setInput(new ByteArrayInputStream(backup), StandardCharsets.UTF_8.name());
restoreFromXml(parser, userId, TAG_INTENT_FILTER_VERIFICATION,
- new BlobXmlRestorer() {
- @Override
- public void apply(XmlPullParser parser, int userId)
- throws XmlPullParserException, IOException {
- synchronized (mPackages) {
- mSettings.readAllDomainVerificationsLPr(parser, userId);
- mSettings.writeLPr();
- }
+ (parser1, userId1) -> {
+ synchronized (mPackages) {
+ mSettings.readAllDomainVerificationsLPr(parser1, userId1);
+ mSettings.writeLPr();
}
- } );
+ });
} catch (Exception e) {
if (DEBUG_BACKUP) {
Slog.e(TAG, "Exception restoring preferred activities: " + e.getMessage());
@@ -20288,15 +20163,11 @@
final XmlPullParser parser = Xml.newPullParser();
parser.setInput(new ByteArrayInputStream(backup), StandardCharsets.UTF_8.name());
restoreFromXml(parser, userId, TAG_PERMISSION_BACKUP,
- new BlobXmlRestorer() {
- @Override
- public void apply(XmlPullParser parser, int userId)
- throws XmlPullParserException, IOException {
- synchronized (mPackages) {
- processRestoredPermissionGrantsLPr(parser, userId);
- }
+ (parser1, userId1) -> {
+ synchronized (mPackages) {
+ processRestoredPermissionGrantsLPr(parser1, userId1);
}
- } );
+ });
} catch (Exception e) {
if (DEBUG_BACKUP) {
Slog.e(TAG, "Exception restoring preferred activities: " + e.getMessage());
@@ -20484,7 +20355,7 @@
CrossProfileIntentResolver resolver =
mSettings.editCrossProfileIntentResolverLPw(sourceUserId);
ArraySet<CrossProfileIntentFilter> set =
- new ArraySet<CrossProfileIntentFilter>(resolver.filterSet());
+ new ArraySet<>(resolver.filterSet());
for (CrossProfileIntentFilter filter : set) {
if (filter.getOwnerPackage().equals(ownerPackage)) {
resolver.removeFilter(filter);
@@ -20589,9 +20460,7 @@
allHomeCandidates.clear();
if (list != null) {
- for (ResolveInfo ri : list) {
- allHomeCandidates.add(ri);
- }
+ allHomeCandidates.addAll(list);
}
return (preferred == null || preferred.activityInfo == null)
? null
@@ -20721,7 +20590,6 @@
boolean isApp = (className == null);
final boolean isCallerInstantApp = (getInstantAppPackageName(callingUid) != null);
String componentName = isApp ? packageName : className;
- int packageUid = -1;
ArrayList<String> components;
// reader
@@ -20961,7 +20829,7 @@
components = mPendingBroadcasts.get(userId, packageName);
final boolean newPackage = components == null;
if (newPackage) {
- components = new ArrayList<String>();
+ components = new ArrayList<>();
}
if (!components.contains(componentName)) {
components.add(componentName);
@@ -20985,7 +20853,7 @@
long callingId = Binder.clearCallingIdentity();
try {
if (sendNow) {
- packageUid = UserHandle.getUid(userId, pkgSetting.appId);
+ int packageUid = UserHandle.getUid(userId, pkgSetting.appId);
sendPackageChangedBroadcast(packageName,
(flags&PackageManager.DONT_KILL_APP) != 0, components, packageUid);
}
@@ -21168,7 +21036,7 @@
// possible for the user flow to never be able to return to that
// situation so here we do a sanity check to make sure we haven't
// left any junk around.
- ArrayList<PreferredActivity> removed = new ArrayList<PreferredActivity>();
+ ArrayList<PreferredActivity> removed = new ArrayList<>();
for (int i=0; i<mSettings.mPreferredActivities.size(); i++) {
PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i);
removed.clear();
@@ -21296,16 +21164,16 @@
}
static String arrayToString(int[] array) {
- StringBuffer buf = new StringBuffer(128);
- buf.append('[');
+ StringBuilder stringBuilder = new StringBuilder(128);
+ stringBuilder.append('[');
if (array != null) {
for (int i=0; i<array.length; i++) {
- if (i > 0) buf.append(", ");
- buf.append(array[i]);
+ if (i > 0) stringBuilder.append(", ");
+ stringBuilder.append(array[i]);
}
}
- buf.append(']');
- return buf.toString();
+ stringBuilder.append(']');
+ return stringBuilder.toString();
}
@Override
@@ -22016,7 +21884,7 @@
ipw.println();
ipw.println("Dexopt state:");
ipw.increaseIndent();
- Collection<PackageParser.Package> packages = null;
+ Collection<PackageParser.Package> packages;
if (packageName != null) {
PackageParser.Package targetPackage = mPackages.get(packageName);
if (targetPackage != null) {
@@ -22043,7 +21911,7 @@
ipw.println();
ipw.println("Compiler stats:");
ipw.increaseIndent();
- Collection<PackageParser.Package> packages = null;
+ Collection<PackageParser.Package> packages;
if (packageName != null) {
PackageParser.Package targetPackage = mPackages.get(packageName);
if (targetPackage != null) {
@@ -22078,9 +21946,7 @@
ArraySet<String> result = new ArraySet<>();
if (iviList.size() > 0) {
for (IntentFilterVerificationInfo ivi : iviList) {
- for (String host : ivi.getDomains()) {
- result.add(host);
- }
+ result.addAll(ivi.getDomains());
}
}
if (filters != null && filters.size() > 0) {
@@ -22172,12 +22038,7 @@
}
private void loadPrivatePackages(final VolumeInfo vol) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- loadPrivatePackagesInner(vol);
- }
- });
+ mHandler.post(() -> loadPrivatePackagesInner(vol));
}
private void loadPrivatePackagesInner(VolumeInfo vol) {
@@ -22268,12 +22129,7 @@
}
private void unloadPrivatePackages(final VolumeInfo vol) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- unloadPrivatePackagesInner(vol);
- }
- });
+ mHandler.post(() -> unloadPrivatePackagesInner(vol));
}
private void unloadPrivatePackagesInner(VolumeInfo vol) {
@@ -22328,23 +22184,6 @@
}
}
- private void assertPackageKnown(String volumeUuid, String packageName)
- throws PackageManagerException {
- synchronized (mPackages) {
- // Normalize package name to handle renamed packages
- packageName = normalizePackageNameLPr(packageName);
-
- final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (ps == null) {
- throw new PackageManagerException("Package " + packageName + " is unknown");
- } else if (!TextUtils.equals(volumeUuid, ps.volumeUuid)) {
- throw new PackageManagerException(
- "Package " + packageName + " found on unknown volume " + volumeUuid
- + "; expected volume " + ps.volumeUuid);
- }
- }
- }
-
private void assertPackageKnownAndInstalled(String volumeUuid, String packageName, int userId)
throws PackageManagerException {
synchronized (mPackages) {
@@ -22457,7 +22296,7 @@
* <p>
* Verifies that directories exist and that ownership and labeling is
* correct for all installed apps.
- * @returns list of skipped non-core packages (if {@code onlyCoreApps} is true)
+ * @return list of skipped non-core packages (if {@code onlyCoreApps} is true)
*/
private List<String> reconcileAppsDataLI(String volumeUuid, int userId, int flags,
boolean migrateAppData, boolean onlyCoreApps) {
@@ -22827,10 +22666,7 @@
@Override
protected void finalize() throws Throwable {
try {
- if (mCloseGuard != null) {
- mCloseGuard.warnIfOpen();
- }
-
+ mCloseGuard.warnIfOpen();
close();
} finally {
super.finalize();
@@ -22874,15 +22710,12 @@
final int callingUid = Binder.getCallingUid();
final UserHandle user = new UserHandle(UserHandle.getUserId(callingUid));
final int moveId = mNextMoveId.getAndIncrement();
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- try {
- movePackageInternal(packageName, volumeUuid, moveId, callingUid, user);
- } catch (PackageManagerException e) {
- Slog.w(TAG, "Failed to move " + packageName, e);
- mMoveCallbacks.notifyStatusChanged(moveId, e.error);
- }
+ mHandler.post(() -> {
+ try {
+ movePackageInternal(packageName, volumeUuid, moveId, callingUid, user);
+ } catch (PackageManagerException e) {
+ Slog.w(TAG, "Failed to move " + packageName, e);
+ mMoveCallbacks.notifyStatusChanged(moveId, e.error);
}
});
return moveId;
@@ -23082,24 +22915,21 @@
final MoveInfo move;
if (moveCompleteApp) {
// Kick off a thread to report progress estimates
- new Thread() {
- @Override
- public void run() {
- while (true) {
- try {
- if (installedLatch.await(1, TimeUnit.SECONDS)) {
- break;
- }
- } catch (InterruptedException ignored) {
+ new Thread(() -> {
+ while (true) {
+ try {
+ if (installedLatch.await(1, TimeUnit.SECONDS)) {
+ break;
}
-
- final long deltaFreeBytes = startFreeBytes - measurePath.getUsableSpace();
- final int progress = 10 + (int) MathUtils.constrain(
- ((deltaFreeBytes * 80) / sizeBytes), 0, 80);
- mMoveCallbacks.notifyStatusChanged(moveId, progress);
+ } catch (InterruptedException ignored) {
}
+
+ final long deltaFreeBytes = startFreeBytes - measurePath.getUsableSpace();
+ final int progress = 10 + (int) MathUtils.constrain(
+ ((deltaFreeBytes * 80) / sizeBytes), 0, 80);
+ mMoveCallbacks.notifyStatusChanged(moveId, progress);
}
- }.start();
+ }).start();
final String dataAppName = codeFile.getName();
move = new MoveInfo(moveId, currentVolumeUuid, volumeUuid, packageName,
@@ -23253,12 +23083,9 @@
if (DEBUG_CLEAN_APKS) {
Slog.i(TAG, " Removing package " + packageName);
}
- mHandler.post(new Runnable() {
- public void run() {
- deletePackageX(packageName, PackageManager.VERSION_CODE_HIGHEST,
- userHandle, 0);
- } //end run
- });
+ //end run
+ mHandler.post(() -> deletePackageX(packageName, PackageManager.VERSION_CODE_HIGHEST,
+ userHandle, 0));
}
}
}
@@ -23505,12 +23332,8 @@
// TODO Implement atomic delete if package is unused
// It is currently possible that the package will be deleted even if it is installed
// after this method returns.
- mHandler.post(new Runnable() {
- public void run() {
- deletePackageX(packageName, PackageManager.VERSION_CODE_HIGHEST,
- 0, PackageManager.DELETE_ALL_USERS);
- }
- });
+ mHandler.post(() -> deletePackageX(packageName, PackageManager.VERSION_CODE_HIGHEST,
+ 0, PackageManager.DELETE_ALL_USERS));
}
}
@@ -24362,11 +24185,9 @@
String[] packageNames, int userId) {
enforceSystemOrPhoneCaller("grantDefaultPermissionsToEnabledTelephonyDataServices");
synchronized (mPackages) {
- Binder.withCleanCallingIdentity( () -> {
- mDefaultPermissionPolicy.
- grantDefaultPermissionsToEnabledTelephonyDataServices(
- packageNames, userId);
- });
+ Binder.withCleanCallingIdentity( () -> mDefaultPermissionPolicy.
+ grantDefaultPermissionsToEnabledTelephonyDataServices(
+ packageNames, userId));
}
}
@@ -24375,11 +24196,9 @@
String[] packageNames, int userId) {
enforceSystemOrPhoneCaller("revokeDefaultPermissionsFromDisabledTelephonyDataServices");
synchronized (mPackages) {
- Binder.withCleanCallingIdentity( () -> {
- mDefaultPermissionPolicy.
- revokeDefaultPermissionsFromDisabledTelephonyDataServices(
- packageNames, userId);
- });
+ Binder.withCleanCallingIdentity( () -> mDefaultPermissionPolicy.
+ revokeDefaultPermissionsFromDisabledTelephonyDataServices(
+ packageNames, userId));
}
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index d963afb..d17697b 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4121,7 +4121,8 @@
continue;
}
final boolean shouldInstall = ps.isSystem() &&
- !ArrayUtils.contains(disallowedPackages, ps.name);
+ !ArrayUtils.contains(disallowedPackages, ps.name) &&
+ !ps.pkg.applicationInfo.hiddenUntilInstalled;
// Only system apps are initially installed.
ps.setInstalled(shouldInstall, userHandle);
if (!shouldInstall) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 407cb93..46935f0 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -31,7 +31,6 @@
import android.app.IStopUserCallback;
import android.app.KeyguardManager;
import android.app.PendingIntent;
-import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -72,7 +71,6 @@
import android.os.UserManagerInternal;
import android.os.UserManagerInternal.UserRestrictionsListener;
import android.os.storage.StorageManager;
-import android.provider.Settings;
import android.security.GateKeeper;
import android.service.gatekeeper.IGateKeeperService;
import android.util.AtomicFile;
@@ -82,7 +80,6 @@
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
-import android.util.SparseLongArray;
import android.util.TimeUtils;
import android.util.Xml;
@@ -101,8 +98,7 @@
import com.android.server.SystemService;
import com.android.server.am.UserState;
import com.android.server.storage.DeviceStorageMonitorInternal;
-
-import libcore.io.IoUtils;
+import com.android.server.wm.ActivityTaskManagerInternal;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -125,6 +121,8 @@
import java.util.List;
import java.util.Objects;
+import libcore.io.IoUtils;
+
/**
* Service for {@link UserManager}.
*
@@ -2968,9 +2966,9 @@
new Thread() {
@Override
public void run() {
- // Clean up any ActivityManager state
- LocalServices.getService(ActivityManagerInternal.class)
- .onUserRemoved(userHandle);
+ // Clean up any ActivityTaskManager state
+ LocalServices.getService(ActivityTaskManagerInternal.class)
+ .onUserStopped(userHandle);
removeUserState(userHandle);
}
}.start();
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 71e342e..b99f8d6 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -124,7 +124,6 @@
import static android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION;
import static android.view.WindowManagerGlobal.ADD_OKAY;
import static android.view.WindowManagerGlobal.ADD_PERMISSION_DENIED;
-
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
@@ -155,8 +154,6 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
-import android.app.ActivityTaskManagerInternal;
-import android.app.ActivityTaskManagerInternal.SleepToken;
import android.app.ActivityTaskManager;
import android.app.ActivityThread;
import android.app.AppOpsManager;
@@ -275,8 +272,8 @@
import com.android.internal.policy.PhoneWindow;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.ScreenshotHelper;
import com.android.internal.util.ScreenShapeHelper;
+import com.android.internal.util.ScreenshotHelper;
import com.android.internal.widget.PointerLocationView;
import com.android.server.GestureLauncherService;
import com.android.server.LocalServices;
@@ -286,6 +283,8 @@
import com.android.server.policy.keyguard.KeyguardStateMonitor.StateCallback;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.vr.VrManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal.SleepToken;
import com.android.server.wm.AppTransition;
import com.android.server.wm.DisplayFrames;
import com.android.server.wm.WindowManagerInternal;
diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java
index c3b9841..ea34346 100644
--- a/services/core/java/com/android/server/slice/SliceManagerService.java
+++ b/services/core/java/com/android/server/slice/SliceManagerService.java
@@ -197,6 +197,7 @@
public SliceSpec[] getPinnedSpecs(Uri uri, String pkg) throws RemoteException {
verifyCaller(pkg);
enforceAccess(pkg, uri);
+ uri = maybeAddUserId(uri, Binder.getCallingUserHandle().getIdentifier());
return getPinnedSlice(uri).getSpecs();
}
diff --git a/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
index e5207cb..7bdc8a3 100644
--- a/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
@@ -20,38 +20,213 @@
import android.annotation.Nullable;
import android.app.AlarmManager;
import android.app.timedetector.TimeSignal;
+import android.content.Intent;
import android.util.Slog;
+import android.util.TimestampedValue;
-import java.io.FileDescriptor;
+import com.android.internal.telephony.TelephonyIntents;
+
import java.io.PrintWriter;
/**
- * A placeholder implementation of TimeDetectorStrategy that passes NITZ suggestions immediately
- * to {@link AlarmManager}.
+ * An implementation of TimeDetectorStrategy that passes only NITZ suggestions to
+ * {@link AlarmManager}. The TimeDetectorService handles thread safety: all calls to
+ * this class can be assumed to be single threaded (though the thread used may vary).
*/
+// @NotThreadSafe
public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
private final static String TAG = "timedetector.SimpleTimeDetectorStrategy";
- private Callback mHelper;
+ /**
+ * CLOCK_PARANOIA: The maximum difference allowed between the expected system clock time and the
+ * actual system clock time before a warning is logged. Used to help identify situations where
+ * there is something other than this class setting the system clock.
+ */
+ private static final long SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS = 2 * 1000;
+
+ // @NonNull after initialize()
+ private Callback mCallback;
+
+ // NITZ state.
+ @Nullable private TimestampedValue<Long> mLastNitzTime;
+
+
+ // Information about the last time signal received: Used when toggling auto-time.
+ @Nullable private TimestampedValue<Long> mLastSystemClockTime;
+ private boolean mLastSystemClockTimeSendNetworkBroadcast;
+
+ // System clock state.
+ @Nullable private TimestampedValue<Long> mLastSystemClockTimeSet;
@Override
public void initialize(@NonNull Callback callback) {
- mHelper = callback;
+ mCallback = callback;
}
@Override
public void suggestTime(@NonNull TimeSignal timeSignal) {
if (!TimeSignal.SOURCE_ID_NITZ.equals(timeSignal.getSourceId())) {
- Slog.w(TAG, "Ignoring signal from unknown source: " + timeSignal);
+ Slog.w(TAG, "Ignoring signal from unsupported source: " + timeSignal);
return;
}
- mHelper.setTime(timeSignal.getUtcTime());
+ // NITZ logic
+
+ TimestampedValue<Long> newNitzUtcTime = timeSignal.getUtcTime();
+ boolean nitzTimeIsValid = validateNewNitzTime(newNitzUtcTime, mLastNitzTime);
+ if (!nitzTimeIsValid) {
+ return;
+ }
+ // Always store the last NITZ value received, regardless of whether we go on to use it to
+ // update the system clock. This is so that we can validate future NITZ signals.
+ mLastNitzTime = newNitzUtcTime;
+
+ // System clock update logic.
+
+ // Historically, Android has sent a telephony broadcast only when setting the time using
+ // NITZ.
+ final boolean sendNetworkBroadcast =
+ TimeSignal.SOURCE_ID_NITZ.equals(timeSignal.getSourceId());
+
+ final TimestampedValue<Long> newUtcTime = newNitzUtcTime;
+ setSystemClockIfRequired(newUtcTime, sendNetworkBroadcast);
+ }
+
+ private static boolean validateNewNitzTime(TimestampedValue<Long> newNitzUtcTime,
+ TimestampedValue<Long> lastNitzTime) {
+
+ if (lastNitzTime != null) {
+ long referenceTimeDifference =
+ TimestampedValue.referenceTimeDifference(newNitzUtcTime, lastNitzTime);
+ if (referenceTimeDifference < 0 || referenceTimeDifference > Integer.MAX_VALUE) {
+ // Out of order or bogus.
+ Slog.w(TAG, "validateNewNitzTime: Bad NITZ signal received."
+ + " referenceTimeDifference=" + referenceTimeDifference
+ + " lastNitzTime=" + lastNitzTime
+ + " newNitzUtcTime=" + newNitzUtcTime);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private void setSystemClockIfRequired(
+ TimestampedValue<Long> time, boolean sendNetworkBroadcast) {
+
+ // Store the last candidate we've seen in all cases so we can set the system clock
+ // when/if time detection is enabled.
+ mLastSystemClockTime = time;
+ mLastSystemClockTimeSendNetworkBroadcast = sendNetworkBroadcast;
+
+ if (!mCallback.isTimeDetectionEnabled()) {
+ Slog.d(TAG, "setSystemClockIfRequired: Time detection is not enabled. time=" + time);
+ return;
+ }
+
+ mCallback.acquireWakeLock();
+ try {
+ long elapsedRealtimeMillis = mCallback.elapsedRealtimeMillis();
+ long actualTimeMillis = mCallback.systemClockMillis();
+
+ // CLOCK_PARANOIA : Check to see if this class owns the clock or if something else
+ // may be setting the clock.
+ if (mLastSystemClockTimeSet != null) {
+ long expectedTimeMillis = TimeDetectorStrategy.getTimeAt(
+ mLastSystemClockTimeSet, elapsedRealtimeMillis);
+ long absSystemClockDifference = Math.abs(expectedTimeMillis - actualTimeMillis);
+ if (absSystemClockDifference > SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS) {
+ Slog.w(TAG, "System clock has not tracked elapsed real time clock. A clock may"
+ + " be inaccurate or something unexpectedly set the system clock."
+ + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ + " expectedTimeMillis=" + expectedTimeMillis
+ + " actualTimeMillis=" + actualTimeMillis);
+ }
+ }
+
+ final String reason = "New time signal";
+ adjustAndSetDeviceSystemClock(
+ time, sendNetworkBroadcast, elapsedRealtimeMillis, actualTimeMillis, reason);
+ } finally {
+ mCallback.releaseWakeLock();
+ }
}
@Override
- public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @Nullable String[] args) {
- // No state to dump.
+ public void handleAutoTimeDetectionToggle(boolean enabled) {
+ // If automatic time detection is enabled we update the system clock instantly if we can.
+ // Conversely, if automatic time detection is disabled we leave the clock as it is.
+ if (enabled) {
+ if (mLastSystemClockTime != null) {
+ // Only send the network broadcast if the last candidate would have caused one.
+ final boolean sendNetworkBroadcast = mLastSystemClockTimeSendNetworkBroadcast;
+
+ mCallback.acquireWakeLock();
+ try {
+ long elapsedRealtimeMillis = mCallback.elapsedRealtimeMillis();
+ long actualTimeMillis = mCallback.systemClockMillis();
+
+ final String reason = "Automatic time detection enabled.";
+ adjustAndSetDeviceSystemClock(mLastSystemClockTime, sendNetworkBroadcast,
+ elapsedRealtimeMillis, actualTimeMillis, reason);
+ } finally {
+ mCallback.releaseWakeLock();
+ }
+ }
+ } else {
+ // CLOCK_PARANOIA: We are losing "control" of the system clock so we cannot predict what
+ // it should be in future.
+ mLastSystemClockTimeSet = null;
+ }
+ }
+
+ @Override
+ public void dump(@NonNull PrintWriter pw, @Nullable String[] args) {
+ pw.println("mLastNitzTime=" + mLastNitzTime);
+ pw.println("mLastSystemClockTimeSet=" + mLastSystemClockTimeSet);
+ pw.println("mLastSystemClockTime=" + mLastSystemClockTime);
+ pw.println("mLastSystemClockTimeSendNetworkBroadcast="
+ + mLastSystemClockTimeSendNetworkBroadcast);
+ }
+
+ private void adjustAndSetDeviceSystemClock(
+ TimestampedValue<Long> newTime, boolean sendNetworkBroadcast,
+ long elapsedRealtimeMillis, long actualSystemClockMillis, String reason) {
+
+ // Adjust for the time that has elapsed since the signal was received.
+ long newSystemClockMillis = TimeDetectorStrategy.getTimeAt(newTime, elapsedRealtimeMillis);
+
+ // Check if the new signal would make sufficient difference to the system clock. If it's
+ // below the threshold then ignore it.
+ long absTimeDifference = Math.abs(newSystemClockMillis - actualSystemClockMillis);
+ long systemClockUpdateThreshold = mCallback.systemClockUpdateThresholdMillis();
+ if (absTimeDifference < systemClockUpdateThreshold) {
+ Slog.d(TAG, "adjustAndSetDeviceSystemClock: Not setting system clock. New time and"
+ + " system clock are close enough."
+ + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ + " newTime=" + newTime
+ + " reason=" + reason
+ + " systemClockUpdateThreshold=" + systemClockUpdateThreshold
+ + " absTimeDifference=" + absTimeDifference);
+ return;
+ }
+
+ Slog.d(TAG, "Setting system clock using time=" + newTime
+ + " reason=" + reason
+ + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ + " newTimeMillis=" + newSystemClockMillis);
+ mCallback.setSystemClock(newSystemClockMillis);
+
+ // CLOCK_PARANOIA : Record the last time this class set the system clock.
+ mLastSystemClockTimeSet = newTime;
+
+ if (sendNetworkBroadcast) {
+ // Send a broadcast that telephony code used to send after setting the clock.
+ // TODO Remove this broadcast as soon as there are no remaining listeners.
+ Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+ intent.putExtra("time", newSystemClockMillis);
+ mCallback.sendStickyBroadcast(intent);
+ }
}
}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index 0ec24d8..9c83000 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -20,24 +20,29 @@
import android.annotation.Nullable;
import android.app.timedetector.ITimeDetectorService;
import android.app.timedetector.TimeSignal;
+import android.content.ContentResolver;
import android.content.Context;
+import android.database.ContentObserver;
import android.os.Binder;
+import android.provider.Settings;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
+import com.android.server.FgThread;
import com.android.server.SystemService;
+import com.android.server.timedetector.TimeDetectorStrategy.Callback;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Objects;
public final class TimeDetectorService extends ITimeDetectorService.Stub {
-
private static final String TAG = "timedetector.TimeDetectorService";
public static class Lifecycle extends SystemService {
- public Lifecycle(Context context) {
+ public Lifecycle(@NonNull Context context) {
super(context);
}
@@ -51,31 +56,65 @@
}
}
- private final Context mContext;
- private final TimeDetectorStrategy mTimeDetectorStrategy;
+ @NonNull private final Context mContext;
+ @NonNull private final Callback mCallback;
- private static TimeDetectorService create(Context context) {
- TimeDetectorStrategy timeDetector = new SimpleTimeDetectorStrategy();
- timeDetector.initialize(new TimeDetectorStrategyCallbackImpl(context));
- return new TimeDetectorService(context, timeDetector);
+ // The lock used when call the strategy to ensure thread safety.
+ @NonNull private final Object mStrategyLock = new Object();
+
+ @GuardedBy("mStrategyLock")
+ @NonNull private final TimeDetectorStrategy mTimeDetectorStrategy;
+
+ private static TimeDetectorService create(@NonNull Context context) {
+ final TimeDetectorStrategy timeDetector = new SimpleTimeDetectorStrategy();
+ final TimeDetectorStrategyCallbackImpl callback =
+ new TimeDetectorStrategyCallbackImpl(context);
+ timeDetector.initialize(callback);
+
+ TimeDetectorService timeDetectorService =
+ new TimeDetectorService(context, callback, timeDetector);
+
+ // Wire up event listening.
+ ContentResolver contentResolver = context.getContentResolver();
+ contentResolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.AUTO_TIME), true,
+ new ContentObserver(FgThread.getHandler()) {
+ public void onChange(boolean selfChange) {
+ timeDetectorService.handleAutoTimeDetectionToggle();
+ }
+ });
+
+ return timeDetectorService;
}
@VisibleForTesting
- public TimeDetectorService(@NonNull Context context,
+ public TimeDetectorService(@NonNull Context context, @NonNull Callback callback,
@NonNull TimeDetectorStrategy timeDetectorStrategy) {
mContext = Objects.requireNonNull(context);
+ mCallback = Objects.requireNonNull(callback);
mTimeDetectorStrategy = Objects.requireNonNull(timeDetectorStrategy);
}
@Override
public void suggestTime(@NonNull TimeSignal timeSignal) {
enforceSetTimePermission();
+ Objects.requireNonNull(timeSignal);
- long callerIdToken = Binder.clearCallingIdentity();
+ long idToken = Binder.clearCallingIdentity();
try {
- mTimeDetectorStrategy.suggestTime(timeSignal);
+ synchronized (mStrategyLock) {
+ mTimeDetectorStrategy.suggestTime(timeSignal);
+ }
} finally {
- Binder.restoreCallingIdentity(callerIdToken);
+ Binder.restoreCallingIdentity(idToken);
+ }
+ }
+
+ @VisibleForTesting
+ public void handleAutoTimeDetectionToggle() {
+ synchronized (mStrategyLock) {
+ final boolean timeDetectionEnabled = mCallback.isTimeDetectionEnabled();
+ mTimeDetectorStrategy.handleAutoTimeDetectionToggle(timeDetectionEnabled);
}
}
@@ -84,7 +123,9 @@
@Nullable String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
- mTimeDetectorStrategy.dump(fd, pw, args);
+ synchronized (mStrategyLock) {
+ mTimeDetectorStrategy.dump(pw, args);
+ }
}
private void enforceSetTimePermission() {
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
index 5cb2eed..e050865 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -19,26 +19,66 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.timedetector.TimeSignal;
+import android.content.Intent;
import android.util.TimestampedValue;
-import java.io.FileDescriptor;
import java.io.PrintWriter;
/**
* The interface for classes that implement the time detection algorithm used by the
- * TimeDetectorService.
+ * TimeDetectorService. The TimeDetectorService handles thread safety: all calls to implementations
+ * of this interface can be assumed to be single threaded (though the thread used may vary).
*
* @hide
*/
+// @NotThreadSafe
public interface TimeDetectorStrategy {
+ /**
+ * The interface used by the strategy to interact with the surrounding service.
+ */
interface Callback {
- void setTime(TimestampedValue<Long> time);
+
+ /**
+ * The absolute threshold below which the system clock need not be updated. i.e. if setting
+ * the system clock would adjust it by less than this (either backwards or forwards) then it
+ * need not be set.
+ */
+ int systemClockUpdateThresholdMillis();
+
+ /** Returns true if automatic time detection is enabled. */
+ boolean isTimeDetectionEnabled();
+
+ /** Acquire a suitable wake lock. Must be followed by {@link #releaseWakeLock()} */
+ void acquireWakeLock();
+
+ /** Returns the elapsedRealtimeMillis clock value. The WakeLock must be held. */
+ long elapsedRealtimeMillis();
+
+ /** Returns the system clock value. The WakeLock must be held. */
+ long systemClockMillis();
+
+ /** Sets the device system clock. The WakeLock must be held. */
+ void setSystemClock(long newTimeMillis);
+
+ /** Release the wake lock acquired by a call to {@link #acquireWakeLock()}. */
+ void releaseWakeLock();
+
+ /** Send the supplied intent as a stick broadcast. */
+ void sendStickyBroadcast(@NonNull Intent intent);
}
+ /** Initialize the strategy. */
void initialize(@NonNull Callback callback);
+
+ /** Process the suggested time. */
void suggestTime(@NonNull TimeSignal timeSignal);
- void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @Nullable String[] args);
+
+ /** Handle the auto-time setting being toggled on or off. */
+ void handleAutoTimeDetectionToggle(boolean enabled);
+
+ /** Dump debug information. */
+ void dump(@NonNull PrintWriter pw, @Nullable String[] args);
// Utility methods below are to be moved to a better home when one becomes more obvious.
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
index 568d73a..77b9e62 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
@@ -18,41 +18,108 @@
import android.annotation.NonNull;
import android.app.AlarmManager;
+import android.content.ContentResolver;
import android.content.Context;
+import android.content.Intent;
import android.os.PowerManager;
import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.provider.Settings;
import android.util.Slog;
-import android.util.TimestampedValue;
+
+import java.util.Objects;
/**
* The real implementation of {@link TimeDetectorStrategy.Callback} used on device.
*/
-public class TimeDetectorStrategyCallbackImpl implements TimeDetectorStrategy.Callback {
+public final class TimeDetectorStrategyCallbackImpl implements TimeDetectorStrategy.Callback {
private final static String TAG = "timedetector.TimeDetectorStrategyCallbackImpl";
- @NonNull private PowerManager.WakeLock mWakeLock;
- @NonNull private AlarmManager mAlarmManager;
+ private static final int SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT = 2 * 1000;
- public TimeDetectorStrategyCallbackImpl(Context context) {
+ /**
+ * If a newly calculated system clock time and the current system clock time differs by this or
+ * more the system clock will actually be updated. Used to prevent the system clock being set
+ * for only minor differences.
+ */
+ private final int mSystemClockUpdateThresholdMillis;
+
+ @NonNull private final Context mContext;
+ @NonNull private final ContentResolver mContentResolver;
+ @NonNull private final PowerManager.WakeLock mWakeLock;
+ @NonNull private final AlarmManager mAlarmManager;
+
+ public TimeDetectorStrategyCallbackImpl(@NonNull Context context) {
+ mContext = Objects.requireNonNull(context);
+ mContentResolver = Objects.requireNonNull(context.getContentResolver());
+
PowerManager powerManager = context.getSystemService(PowerManager.class);
+ mWakeLock = Objects.requireNonNull(
+ powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG));
- mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+ mAlarmManager = Objects.requireNonNull(context.getSystemService(AlarmManager.class));
- mAlarmManager = context.getSystemService(AlarmManager.class);
+ mSystemClockUpdateThresholdMillis =
+ SystemProperties.getInt("ro.sys.time_detector_update_diff",
+ SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT);
}
@Override
- public void setTime(TimestampedValue<Long> time) {
- mWakeLock.acquire();
+ public int systemClockUpdateThresholdMillis() {
+ return mSystemClockUpdateThresholdMillis;
+ }
+
+ @Override
+ public boolean isTimeDetectionEnabled() {
try {
- long elapsedRealtimeMillis = SystemClock.elapsedRealtime();
- long currentTimeMillis = TimeDetectorStrategy.getTimeAt(time, elapsedRealtimeMillis);
- Slog.d(TAG, "Setting system clock using time=" + time
- + ", elapsedRealtimeMillis=" + elapsedRealtimeMillis);
- mAlarmManager.setTime(currentTimeMillis);
- } finally {
- mWakeLock.release();
+ return Settings.Global.getInt(mContentResolver, Settings.Global.AUTO_TIME) != 0;
+ } catch (Settings.SettingNotFoundException snfe) {
+ return true;
+ }
+ }
+
+ @Override
+ public void acquireWakeLock() {
+ if (mWakeLock.isHeld()) {
+ Slog.wtf(TAG, "WakeLock " + mWakeLock + " already held");
+ }
+ mWakeLock.acquire();
+ }
+
+ @Override
+ public long elapsedRealtimeMillis() {
+ checkWakeLockHeld();
+ return SystemClock.elapsedRealtime();
+ }
+
+ @Override
+ public long systemClockMillis() {
+ checkWakeLockHeld();
+ return System.currentTimeMillis();
+ }
+
+ @Override
+ public void setSystemClock(long newTimeMillis) {
+ checkWakeLockHeld();
+ mAlarmManager.setTime(newTimeMillis);
+ }
+
+ @Override
+ public void releaseWakeLock() {
+ checkWakeLockHeld();
+ mWakeLock.release();
+ }
+
+ @Override
+ public void sendStickyBroadcast(@NonNull Intent intent) {
+ mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+ }
+
+ private void checkWakeLockHeld() {
+ if (!mWakeLock.isHeld()) {
+ Slog.wtf(TAG, "WakeLock " + mWakeLock + " not held");
}
}
}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
new file mode 100644
index 0000000..5f71b0b
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 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.timezonedetector;
+
+import com.android.internal.util.DumpUtils;
+import com.android.server.SystemService;
+import android.app.timezonedetector.ITimeZoneDetectorService;
+import android.content.Context;
+import android.util.Slog;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub {
+ private static final String TAG = "timezonedetector.TimeZoneDetectorService";
+
+ public static class Lifecycle extends SystemService {
+
+ public Lifecycle(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ TimeZoneDetectorService service = TimeZoneDetectorService.create(getContext());
+ // Publish the binder service so it can be accessed from other (appropriately
+ // permissioned) processes.
+ publishBinderService(Context.TIME_ZONE_DETECTOR_SERVICE, service);
+ }
+ }
+
+ private final Context mContext;
+
+ private static TimeZoneDetectorService create(Context context) {
+ return new TimeZoneDetectorService(context);
+ }
+
+ public TimeZoneDetectorService(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public void stubbedCall() {
+ // Empty call for initial tests.
+ Slog.d(TAG, "stubbedCall() called");
+ // TODO: Remove when there are real methods.
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+ // TODO: Implement when there is state.
+ }
+}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 4413666..8a135b8 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -20,6 +20,7 @@
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager;
+import android.hardware.biometrics.BiometricSourceType;
import android.app.trust.ITrustListener;
import android.app.trust.ITrustManager;
import android.content.BroadcastReceiver;
@@ -130,8 +131,8 @@
private final SparseBooleanArray mTrustUsuallyManagedForUser = new SparseBooleanArray();
// set to true only if user can skip bouncer
- @GuardedBy("mUsersUnlockedByFingerprint")
- private final SparseBooleanArray mUsersUnlockedByFingerprint = new SparseBooleanArray();
+ @GuardedBy("mUsersUnlockedByBiometric")
+ private final SparseBooleanArray mUsersUnlockedByBiometric = new SparseBooleanArray();
private final StrongAuthTracker mStrongAuthTracker;
@@ -440,11 +441,11 @@
boolean secure = mLockPatternUtils.isSecure(id);
boolean trusted = aggregateIsTrusted(id);
boolean showingKeyguard = true;
- boolean fingerprintAuthenticated = false;
+ boolean biometricAuthenticated = false;
if (mCurrentUser == id) {
- synchronized(mUsersUnlockedByFingerprint) {
- fingerprintAuthenticated = mUsersUnlockedByFingerprint.get(id, false);
+ synchronized(mUsersUnlockedByBiometric) {
+ biometricAuthenticated = mUsersUnlockedByBiometric.get(id, false);
}
try {
showingKeyguard = wm.isKeyguardLocked();
@@ -452,7 +453,7 @@
}
}
boolean deviceLocked = secure && showingKeyguard && !trusted &&
- !fingerprintAuthenticated;
+ !biometricAuthenticated;
setDeviceLockedForUser(id, deviceLocked);
}
}
@@ -1021,20 +1022,20 @@
}
@Override
- public void unlockedByFingerprintForUser(int userId) {
+ public void unlockedByBiometricForUser(int userId, BiometricSourceType biometricSource) {
enforceReportPermission();
- synchronized(mUsersUnlockedByFingerprint) {
- mUsersUnlockedByFingerprint.put(userId, true);
+ synchronized(mUsersUnlockedByBiometric) {
+ mUsersUnlockedByBiometric.put(userId, true);
}
mHandler.obtainMessage(MSG_REFRESH_DEVICE_LOCKED_FOR_USER, userId,
0 /* arg2 */).sendToTarget();
}
@Override
- public void clearAllFingerprints() {
+ public void clearAllBiometricRecognized(BiometricSourceType biometricSource) {
enforceReportPermission();
- synchronized(mUsersUnlockedByFingerprint) {
- mUsersUnlockedByFingerprint.clear();
+ synchronized(mUsersUnlockedByBiometric) {
+ mUsersUnlockedByBiometric.clear();
}
mHandler.obtainMessage(MSG_REFRESH_DEVICE_LOCKED_FOR_USER, UserHandle.USER_ALL,
0 /* arg2 */).sendToTarget();
@@ -1188,8 +1189,8 @@
synchronized (mTrustUsuallyManagedForUser) {
mTrustUsuallyManagedForUser.delete(userId);
}
- synchronized (mUsersUnlockedByFingerprint) {
- mUsersUnlockedByFingerprint.delete(userId);
+ synchronized (mUsersUnlockedByBiometric) {
+ mUsersUnlockedByBiometric.delete(userId);
}
refreshAgentList(userId);
refreshDeviceLockedForUser(userId);
diff --git a/services/core/java/com/android/server/vr/Vr2dDisplay.java b/services/core/java/com/android/server/vr/Vr2dDisplay.java
index 9183b08..a16dbb7 100644
--- a/services/core/java/com/android/server/vr/Vr2dDisplay.java
+++ b/services/core/java/com/android/server/vr/Vr2dDisplay.java
@@ -3,9 +3,7 @@
import static android.view.Display.INVALID_DISPLAY;
import android.app.ActivityManagerInternal;
-import android.app.ActivityTaskManagerInternal;
import android.app.Vr2dDisplayProperties;
-import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -14,19 +12,15 @@
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.ImageReader;
-import android.os.Build;
import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemProperties;
import android.service.vr.IPersistentVrStateCallbacks;
import android.service.vr.IVrManager;
import android.util.Log;
import android.view.Surface;
import com.android.server.LocalServices;
+import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
/**
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 50bf57f..5c45afc 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -18,15 +18,13 @@
import static android.view.Display.INVALID_DISPLAY;
import android.Manifest;
-import android.app.ActivityManagerInternal;
-import android.app.ActivityTaskManagerInternal;
-import android.app.ActivityTaskManagerInternal.ScreenObserver;
+import android.annotation.NonNull;
import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
import android.app.INotificationManager;
-import android.app.Vr2dDisplayProperties;
import android.app.NotificationManager;
-import android.annotation.NonNull;
+import android.app.Vr2dDisplayProperties;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -60,30 +58,30 @@
import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
-
-import com.android.server.FgThread;
-import com.android.server.wm.WindowManagerInternal;
import android.view.inputmethod.InputMethodManagerInternal;
import com.android.internal.R;
import com.android.internal.util.DumpUtils;
+import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
import com.android.server.SystemService;
-import com.android.server.utils.ManagedApplicationService.PendingEvent;
-import com.android.server.utils.ManagedApplicationService.LogEvent;
-import com.android.server.utils.ManagedApplicationService.LogFormattable;
-import com.android.server.vr.EnabledComponentsObserver.EnabledComponentChangeListener;
import com.android.server.utils.ManagedApplicationService;
import com.android.server.utils.ManagedApplicationService.BinderChecker;
+import com.android.server.utils.ManagedApplicationService.LogEvent;
+import com.android.server.utils.ManagedApplicationService.LogFormattable;
+import com.android.server.utils.ManagedApplicationService.PendingEvent;
+import com.android.server.vr.EnabledComponentsObserver.EnabledComponentChangeListener;
+import com.android.server.wm.ActivityTaskManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal.ScreenObserver;
+import com.android.server.wm.WindowManagerInternal;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.lang.StringBuilder;
import java.text.SimpleDateFormat;
-import java.util.Arrays;
import java.util.ArrayDeque;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
diff --git a/core/java/android/app/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
similarity index 86%
rename from core/java/android/app/ActivityTaskManagerInternal.java
rename to services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 170cb52..3885cf9 100644
--- a/core/java/android/app/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -14,10 +14,13 @@
* limitations under the License
*/
-package android.app;
+package com.android.server.wm;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.AppProtoEnums;
+import android.app.IActivityManager;
+import android.app.IApplicationThread;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
@@ -28,6 +31,7 @@
import android.view.RemoteAnimationAdapter;
import com.android.internal.app.IVoiceInteractor;
+import com.android.server.am.WindowProcessController;
import java.util.List;
@@ -210,11 +214,6 @@
*/
public abstract void setFocusedActivity(IBinder token);
- /**
- * Returns {@code true} if {@code uid} is running an activity from {@code packageName}.
- */
- public abstract boolean hasRunningActivity(int uid, @Nullable String packageName);
-
public abstract void registerScreenObserver(ScreenObserver observer);
/**
@@ -243,4 +242,28 @@
*/
public abstract void notifyActiveVoiceInteractionServiceChanged(ComponentName component);
+ /**
+ * Set a uid that is allowed to bypass stopped app switches, launching an app
+ * whenever it wants.
+ *
+ * @param type Type of the caller -- unique string the caller supplies to identify itself
+ * and disambiguate with other calles.
+ * @param uid The uid of the app to be allowed, or -1 to clear the uid for this type.
+ * @param userId The user it is allowed for.
+ */
+ public abstract void setAllowAppSwitches(@NonNull String type, int uid, int userId);
+
+ /**
+ * Called when a user has been deleted. This can happen during normal device usage
+ * or just at startup, when partially removed users are purged. Any state persisted by the
+ * ActivityManager should be purged now.
+ *
+ * @param userId The user being cleaned up.
+ */
+ public abstract void onUserStopped(int userId);
+ public abstract boolean isGetTasksAllowed(String caller, int callingPid, int callingUid);
+
+ public abstract void onProcessAdded(WindowProcessController proc);
+ public abstract void onProcessRemoved(String name, int uid);
+ public abstract void onCleanUpApplicationRecord(WindowProcessController proc);
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0cbf8a7..f74216a 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2507,11 +2507,12 @@
if (DEBUG_INPUT_METHOD && updateImeTarget) Slog.v(TAG_WM,
"Proposed new IME target: " + target);
- // Now, a special case -- if the last target's window is in the process of exiting, and the
- // new target is home, keep on the last target to avoid flicker. Home is a special case
- // since its above other stacks in the ordering list, but layed out below the others.
- if (curTarget != null && curTarget.isDisplayedLw() && curTarget.isClosing()
- && (target == null || target.isActivityTypeHome())) {
+ // Now, a special case -- if the last target's window is in the process of exiting, but
+ // not removed, and the new target is home, keep on the last target to avoid flicker.
+ // Home is a special case since its above other stacks in the ordering list, but layed
+ // out below the others.
+ if (curTarget != null && !curTarget.mRemoved && curTarget.isDisplayedLw()
+ && curTarget.isClosing() && (target == null || target.isActivityTypeHome())) {
if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "New target is home while current target is "
+ "closing, not changing");
return curTarget;
@@ -3427,50 +3428,53 @@
* @return The proper position for the stack.
*/
private int findPositionForStack(int requestedPosition, TaskStack stack, boolean adding) {
- final int topChildPosition = mChildren.size() - 1;
- boolean toTop = requestedPosition == POSITION_TOP;
- toTop |= adding ? requestedPosition >= topChildPosition + 1
- : requestedPosition >= topChildPosition;
-
if (stack.inPinnedWindowingMode()) {
- // Stack in pinned windowing mode is z-ordered on-top of all other stacks so okay to
- // just return the candidate position.
- return requestedPosition;
+ return POSITION_TOP;
}
- // We might call mChildren.get() with targetPosition below, but targetPosition might be
- // POSITION_TOP (INTEGER_MAX). We need to adjust the value to the actual index in the
- // array.
- int targetPosition = toTop ? topChildPosition : requestedPosition;
- // Note that the index we should return varies depending on the value of adding.
- // When we're adding a new stack the index is the current target position.
- // When we're positioning an existing stack the index is the position below the target
- // stack, because WindowContainer#positionAt() first removes element and then adds
- // it to specified place.
- if (toTop && adding) {
+ final int topChildPosition = mChildren.size() - 1;
+ int belowAlwaysOnTopPosition = POSITION_BOTTOM;
+ for (int i = topChildPosition; i >= 0; --i) {
+ if (getStacks().get(i) != stack && !getStacks().get(i).isAlwaysOnTop()) {
+ belowAlwaysOnTopPosition = i;
+ break;
+ }
+ }
+
+ // The max possible position we can insert the stack at.
+ int maxPosition = POSITION_TOP;
+ // The min possible position we can insert the stack at.
+ int minPosition = POSITION_BOTTOM;
+
+ if (stack.isAlwaysOnTop()) {
+ if (hasPinnedStack()) {
+ // Always-on-top stacks go below the pinned stack.
+ maxPosition = getStacks().indexOf(mPinnedStack) - 1;
+ }
+ // Always-on-top stacks need to be above all other stacks.
+ minPosition = belowAlwaysOnTopPosition !=
+ POSITION_BOTTOM ? belowAlwaysOnTopPosition : topChildPosition;
+ } else {
+ // Other stacks need to be below the always-on-top stacks.
+ maxPosition = belowAlwaysOnTopPosition !=
+ POSITION_BOTTOM ? belowAlwaysOnTopPosition : topChildPosition;
+ }
+
+ int targetPosition = requestedPosition;
+ targetPosition = Math.min(targetPosition, maxPosition);
+ targetPosition = Math.max(targetPosition, minPosition);
+
+ int prevPosition = getStacks().indexOf(stack);
+ // The positions we calculated above (maxPosition, minPosition) do not take into
+ // consideration the following edge cases.
+ // 1) We need to adjust the position depending on the value "adding".
+ // 2) When we are moving a stack to another position, we also need to adjust the
+ // position depending on whether the stack is moving to a higher or lower position.
+ if ((targetPosition != requestedPosition) &&
+ (adding || targetPosition < prevPosition)) {
targetPosition++;
}
- // Note we might have multiple always on top windows.
- while (targetPosition >= 0) {
- int adjustedTargetStackId = adding ? targetPosition - 1 : targetPosition;
- if (adjustedTargetStackId < 0 || adjustedTargetStackId > topChildPosition) {
- break;
- }
- TaskStack targetStack = mChildren.get(adjustedTargetStackId);
- if (!targetStack.isAlwaysOnTop()) {
- // We reached a stack that isn't always-on-top.
- break;
- }
- if (stack.isAlwaysOnTop() && !targetStack.inPinnedWindowingMode()) {
- // Always on-top non-pinned windowing mode stacks can go anywhere below pinned
- // stack.
- break;
- }
- // We go one level down, looking for the place on which the new stack can be put.
- targetPosition--;
- }
-
return targetPosition;
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index b610695..6f5fea9 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -16,13 +16,13 @@
package com.android.server.wm;
-import static android.app.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM;
import static com.android.server.wm.AnimationAdapterProto.REMOTE;
import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS;
@@ -48,11 +48,14 @@
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.inputmethod.InputMethodManagerInternal;
+
+import com.google.android.collect.Sets;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import com.android.server.wm.utils.InsetUtils;
-import com.google.android.collect.Sets;
+
import java.io.PrintWriter;
import java.util.ArrayList;
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index a642e6a..21e807e 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -39,6 +39,7 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayDeque;
+import java.util.Arrays;
/**
* Persists {@link TaskSnapshot}s to disk.
@@ -399,8 +400,8 @@
@VisibleForTesting
RemoveObsoleteFilesQueueItem(ArraySet<Integer> persistentTaskIds,
int[] runningUserIds) {
- mPersistentTaskIds = persistentTaskIds;
- mRunningUserIds = runningUserIds;
+ mPersistentTaskIds = new ArraySet<>(persistentTaskIds);
+ mRunningUserIds = Arrays.copyOf(runningUserIds, runningUserIds.length);
}
@Override
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 76a060e..e01cebd 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -726,18 +726,33 @@
@Override
public void onConfigurationChanged(Configuration newParentConfig) {
final int prevWindowingMode = getWindowingMode();
+ final boolean prevIsAlwaysOnTop = isAlwaysOnTop();
super.onConfigurationChanged(newParentConfig);
// Only need to update surface size here since the super method will handle updating
// surface position.
updateSurfaceSize(getPendingTransaction());
final int windowingMode = getWindowingMode();
+ final boolean isAlwaysOnTop = isAlwaysOnTop();
- if (mDisplayContent == null || prevWindowingMode == windowingMode) {
+ if (mDisplayContent == null) {
return;
}
- mDisplayContent.onStackWindowingModeChanged(this);
- updateBoundsForWindowModeChange();
+
+ if (prevWindowingMode != windowingMode) {
+ mDisplayContent.onStackWindowingModeChanged(this);
+ updateBoundsForWindowModeChange();
+ }
+
+ if (prevIsAlwaysOnTop != isAlwaysOnTop) {
+ // positionStackAt(POSITION_TOP, this) must be called even when always on top gets
+ // turned off because we need to make sure that the stack is moved from among always on
+ // top windows to below other always on top windows. Since the position the stack should
+ // be inserted into is calculated properly in
+ // {@link DisplayContent#findPositionForStack()} in both cases, we can just request that
+ // the stack is put at top here.
+ mDisplayContent.positionStackAt(POSITION_TOP, this);
+ }
}
private void updateSurfaceBounds() {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 8fe7063..fee0fcb 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -246,6 +246,19 @@
+ " is already a child of container=" + child.getParent().getName()
+ " can't add to container=" + getName());
}
+
+ if ((index < 0 && index != POSITION_BOTTOM)
+ || (index > mChildren.size() && index != POSITION_TOP)) {
+ throw new IllegalArgumentException("addChild: invalid position=" + index
+ + ", children number=" + mChildren.size());
+ }
+
+ if (index == POSITION_TOP) {
+ index = mChildren.size();
+ } else if (index == POSITION_BOTTOM) {
+ index = 0;
+ }
+
mChildren.add(index, child);
onChildAdded(child);
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 6686b80..0c65518 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -368,14 +368,25 @@
* to be synchronized with state in WindowManagerService.
* @param dismissImeOnBackKeyPressed {@code true} if the software keyboard is shown and the back
* key is expected to dismiss the software keyboard.
- * @param targetWindowToken token to identify the target window that the IME is associated with.
- * {@code null} when application, system, or the IME itself decided to
- * change its window visibility before being associated with any target
- * window.
*/
public abstract void updateInputMethodWindowStatus(@NonNull IBinder imeToken,
- boolean imeWindowVisible, boolean dismissImeOnBackKeyPressed,
- @Nullable IBinder targetWindowToken);
+ boolean imeWindowVisible, boolean dismissImeOnBackKeyPressed);
+
+ /**
+ * Notifies WindowManagerService that the current IME window status is being changed.
+ *
+ * <p>Only {@link com.android.server.InputMethodManagerService} is the expected and tested
+ * caller of this method.</p>
+ *
+ * @param imeToken token to track the active input method. Corresponding IME windows can be
+ * identified by checking {@link android.view.WindowManager.LayoutParams#token}.
+ * Note that there is no guarantee that the corresponding window is already
+ * created
+ * @param imeTargetWindowToken token to identify the target window that the IME is associated
+ * with
+ */
+ public abstract void updateInputMethodTargetWindow(@NonNull IBinder imeToken,
+ @NonNull IBinder imeTargetWindowToken);
/**
* Returns true when the hardware keyboard is available.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2c7ab7e..399078a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -117,7 +117,6 @@
import android.app.ActivityManager.TaskSnapshot;
import android.app.ActivityManagerInternal;
import android.app.ActivityTaskManager;
-import android.app.ActivityTaskManagerInternal;
import android.app.ActivityThread;
import android.app.AppOpsManager;
import android.app.IActivityManager;
@@ -7364,16 +7363,18 @@
@Override
public void updateInputMethodWindowStatus(@NonNull IBinder imeToken,
- boolean imeWindowVisible, boolean dismissImeOnBackKeyPressed,
- @Nullable IBinder targetWindowToken) {
+ boolean imeWindowVisible, boolean dismissImeOnBackKeyPressed) {
+ mPolicy.setDismissImeOnBackKeyPressed(dismissImeOnBackKeyPressed);
+ }
+
+ @Override
+ public void updateInputMethodTargetWindow(@NonNull IBinder imeToken,
+ @NonNull IBinder imeTargetWindowToken) {
// TODO (b/34628091): Use this method to address the window animation issue.
if (DEBUG_INPUT_METHOD) {
- Slog.w(TAG_WM, "updateInputMethodWindowStatus: imeToken=" + imeToken
- + " dismissImeOnBackKeyPressed=" + dismissImeOnBackKeyPressed
- + " imeWindowVisible=" + imeWindowVisible
- + " targetWindowToken=" + targetWindowToken);
+ Slog.w(TAG_WM, "updateInputMethodTargetWindow: imeToken=" + imeToken
+ + " imeTargetWindowToken=" + imeTargetWindowToken);
}
- mPolicy.setDismissImeOnBackKeyPressed(dismissImeOnBackKeyPressed);
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 1a8753d..aced8e4 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -16,18 +16,10 @@
package com.android.server.wm;
-import static android.app.ActivityTaskManagerInternal.APP_TRANSITION_SNAPSHOT;
-import static android.app.ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN;
-import static android.app.ActivityTaskManagerInternal.APP_TRANSITION_WINDOWS_DRAWN;
-
-import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
-import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
-import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
-import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
-import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
-import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
+import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
+import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
@@ -39,10 +31,17 @@
import static android.view.WindowManager.TRANSIT_TASK_OPEN;
import static android.view.WindowManager.TRANSIT_TASK_TO_BACK;
import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
+import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
+import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_WALLPAPER_CLOSE;
import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_CLOSE;
import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_OPEN;
import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
+import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SNAPSHOT;
+import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN;
+import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_WINDOWS_DRAWN;
import static com.android.server.wm.AppTransition.isKeyguardGoingAwayTransit;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 1c9782f..84de6b4 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -152,6 +152,11 @@
}
@Override
+ public long forceNetworkLogs() {
+ return 0;
+ }
+
+ @Override
public long forceSecurityLogs() {
return 0;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 414cf47..9ef806e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -6259,7 +6259,7 @@
}
@Override
- public void reportFailedFingerprintAttempt(int userHandle) {
+ public void reportFailedBiometricAttempt(int userHandle) {
enforceFullCrossUsersPermission(userHandle);
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
@@ -6270,7 +6270,7 @@
}
@Override
- public void reportSuccessfulFingerprintAttempt(int userHandle) {
+ public void reportSuccessfulBiometricAttempt(int userHandle) {
enforceFullCrossUsersPermission(userHandle);
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
@@ -10694,7 +10694,6 @@
return false;
}
}
-
return false;
}
@@ -12282,6 +12281,20 @@
}
}
+ @Override
+ public long forceNetworkLogs() {
+ enforceShell("forceNetworkLogs");
+ synchronized (getLockObject()) {
+ if (!isNetworkLoggingEnabledInternalLocked()) {
+ throw new IllegalStateException("logging is not available");
+ }
+ if (mNetworkLogger != null) {
+ return mNetworkLogger.forceBatchFinalization();
+ }
+ return 0;
+ }
+ }
+
/** Pauses security and network logging if there are unaffiliated users on the device */
private void maybePauseDeviceWideLoggingLocked() {
if (!areAllUsersAffiliatedWithDeviceLocked()) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
index 0967652..4514492 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
@@ -187,4 +187,8 @@
List<NetworkEvent> retrieveLogs(long batchToken) {
return mNetworkLoggingHandler.retrieveFullLogBatch(batchToken);
}
+
+ long forceBatchFinalization() {
+ return mNetworkLoggingHandler.forceBatchFinalization();
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
index f91f959..0a7070f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
@@ -16,6 +16,8 @@
package com.android.server.devicepolicy;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
import android.app.AlarmManager;
import android.app.AlarmManager.OnAlarmListener;
import android.app.admin.DeviceAdminReceiver;
@@ -33,6 +35,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.TimeUnit;
/**
* A Handler class for managing network logging on a background thread.
@@ -60,6 +63,12 @@
/** Delay after which older batches get discarded after a retrieval. */
private static final long RETRIEVED_BATCH_DISCARD_DELAY_MS = 5 * 60 * 1000; // 5m
+ /** Throttle batch finalization to 10 seconds.*/
+ private static final long FORCE_FETCH_THROTTLE_NS = TimeUnit.SECONDS.toNanos(10);
+ /** Timestamp of the last call to finalise a batch. Used for throttling forced finalization.*/
+ @GuardedBy("this")
+ private long mLastFinalizationNanos = -1;
+
/** Do not call into mDpm with locks held */
private final DevicePolicyManagerService mDpm;
private final AlarmManager mAlarmManager;
@@ -155,6 +164,26 @@
+ "ms from now.");
}
+ /**
+ * Forces batch finalisation. Throttled to 10 seconds per batch finalisation.
+ * @return the number of milliseconds to wait until batch finalisation can be forced.
+ */
+ long forceBatchFinalization() {
+ Bundle notificationExtras;
+ synchronized (this) {
+ final long toWaitNanos =
+ mLastFinalizationNanos + FORCE_FETCH_THROTTLE_NS - System.nanoTime();
+ if (toWaitNanos > 0) {
+ return NANOSECONDS.toMillis(toWaitNanos) + 1; // Round up.
+ }
+ notificationExtras = finalizeBatchAndBuildDeviceOwnerMessageLocked();
+ }
+ if (notificationExtras != null) {
+ notifyDeviceOwner(notificationExtras);
+ }
+ return 0;
+ }
+
synchronized void pause() {
Slog.d(TAG, "Paused network logging");
mPaused = true;
@@ -192,6 +221,7 @@
@GuardedBy("this")
/** @returns extras if a message should be sent to the device owner */
private Bundle finalizeBatchAndBuildDeviceOwnerMessageLocked() {
+ mLastFinalizationNanos = System.nanoTime();
Bundle notificationExtras = null;
if (mNetworkEvents.size() > 0) {
// Assign ids to the events.
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 2811f71..1f1b3f8 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -75,7 +75,8 @@
import com.android.server.display.DisplayManagerService;
import com.android.server.dreams.DreamManagerService;
import com.android.server.emergency.EmergencyAffordanceService;
-import com.android.server.fingerprint.FingerprintService;
+import com.android.server.biometrics.face.FaceService;
+import com.android.server.biometrics.fingerprint.FingerprintService;
import com.android.server.hdmi.HdmiControlService;
import com.android.server.input.InputManagerService;
import com.android.server.job.JobSchedulerService;
@@ -232,6 +233,8 @@
"com.android.internal.car.CarServiceHelperService";
private static final String TIME_DETECTOR_SERVICE_CLASS =
"com.android.server.timedetector.TimeDetectorService$Lifecycle";
+ private static final String TIME_ZONE_DETECTOR_SERVICE_CLASS =
+ "com.android.server.timezonedetector.TimeZoneDetectorService$Lifecycle";
private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
@@ -562,11 +565,10 @@
// TODO: Might need to move after migration to WM.
ActivityTaskManagerService atm = mSystemServiceManager.startService(
ActivityTaskManagerService.Lifecycle.class).getService();
- mActivityManagerService = mSystemServiceManager.startService(
- ActivityManagerService.Lifecycle.class).getService();
+ mActivityManagerService = ActivityManagerService.Lifecycle.startService(
+ mSystemServiceManager, atm);
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
mActivityManagerService.setInstaller(installer);
- mActivityManagerService.setActivityTaskManager(atm);
traceEnd();
// Power manager needs to be started early because other services need it.
@@ -1243,13 +1245,24 @@
}
traceEnd();
- traceBeginAndSlog("StartTimeDetectorService");
- try {
- mSystemServiceManager.startService(TIME_DETECTOR_SERVICE_CLASS);
- } catch (Throwable e) {
- reportWtf("starting StartTimeDetectorService service", e);
+ final boolean useNewTimeServices = true;
+ if (useNewTimeServices) {
+ traceBeginAndSlog("StartTimeDetectorService");
+ try {
+ mSystemServiceManager.startService(TIME_DETECTOR_SERVICE_CLASS);
+ } catch (Throwable e) {
+ reportWtf("starting StartTimeDetectorService service", e);
+ }
+ traceEnd();
+
+ traceBeginAndSlog("StartTimeZoneDetectorService");
+ try {
+ mSystemServiceManager.startService(TIME_ZONE_DETECTOR_SERVICE_CLASS);
+ } catch (Throwable e) {
+ reportWtf("starting StartTimeZoneDetectorService service", e);
+ }
+ traceEnd();
}
- traceEnd();
if (!isWatch) {
traceBeginAndSlog("StartSearchManagerService");
@@ -1416,7 +1429,12 @@
if (!isWatch) {
traceBeginAndSlog("StartNetworkTimeUpdateService");
try {
- networkTimeUpdater = new NetworkTimeUpdateService(context);
+ if (useNewTimeServices) {
+ networkTimeUpdater = new NewNetworkTimeUpdateService(context);
+ } else {
+ networkTimeUpdater = new OldNetworkTimeUpdateService(context);
+ }
+ Slog.d(TAG, "Using networkTimeUpdater class=" + networkTimeUpdater.getClass());
ServiceManager.addService("network_time_update_service", networkTimeUpdater);
} catch (Throwable e) {
reportWtf("starting NetworkTimeUpdate service", e);
@@ -1513,6 +1531,12 @@
}
traceEnd();
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) {
+ traceBeginAndSlog("StartFaceSensor");
+ mSystemServiceManager.startService(FaceService.class);
+ traceEnd();
+ }
+
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
traceBeginAndSlog("StartFingerprintSensor");
mSystemServiceManager.startService(FingerprintService.class);
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityLaunchParamsModifierTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityLaunchParamsModifierTests.java
index f741c70..583a9dd 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityLaunchParamsModifierTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityLaunchParamsModifierTests.java
@@ -50,7 +50,7 @@
@RunWith(AndroidJUnit4.class)
public class ActivityLaunchParamsModifierTests extends ActivityTestsBase {
private ActivityLaunchParamsModifier mModifier;
- private ActivityManagerService mService;
+ private ActivityTaskManagerService mService;
private ActivityStack mStack;
private TaskRecord mTask;
private ActivityRecord mActivity;
@@ -62,7 +62,7 @@
@Override
public void setUp() throws Exception {
super.setUp();
- mService = createActivityManagerService();
+ mService = createActivityTaskManagerService();
mModifier = new ActivityLaunchParamsModifier(mService.mStackSupervisor);
mCurrent = new LaunchParams();
mResult = new LaunchParams();
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
index 5ee1c40..dd3e5a8 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
@@ -73,7 +73,7 @@
@Presubmit
@RunWith(AndroidJUnit4.class)
public class ActivityRecordTests extends ActivityTestsBase {
- private ActivityManagerService mService;
+ private ActivityTaskManagerService mService;
private TestActivityStack mStack;
private TaskRecord mTask;
private ActivityRecord mActivity;
@@ -83,7 +83,7 @@
public void setUp() throws Exception {
super.setUp();
- mService = createActivityManagerService();
+ mService = createActivityTaskManagerService();
mStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
mTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
@@ -126,7 +126,7 @@
pauseFound.value = true;
}
return null;
- }).when(mActivity.app.thread).scheduleTransaction(any());
+ }).when(mActivity.app.getThread()).scheduleTransaction(any());
mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped");
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
index 0674d85..f92ca5f 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
@@ -68,7 +68,7 @@
@Presubmit
@RunWith(AndroidJUnit4.class)
public class ActivityStackSupervisorTests extends ActivityTestsBase {
- private ActivityManagerService mService;
+ private ActivityTaskManagerService mService;
private ActivityStackSupervisor mSupervisor;
private ActivityStack mFullscreenStack;
@@ -77,7 +77,7 @@
public void setUp() throws Exception {
super.setUp();
- mService = createActivityManagerService();
+ mService = createActivityTaskManagerService();
mSupervisor = mService.mStackSupervisor;
mFullscreenStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
@@ -278,7 +278,7 @@
assertEquals(originalStackCount + 1, defaultDisplay.getChildCount());
// Let's pretend that the app has crashed.
- firstActivity.app.thread = null;
+ firstActivity.app.setThread(null);
mService.mStackSupervisor.finishTopCrashedActivitiesLocked(firstActivity.app, "test");
// Verify that the stack was removed.
@@ -407,4 +407,27 @@
// Assert that the primary stack is returned.
assertEquals(primaryStack, result);
}
+
+ /**
+ * Verify split-screen primary stack & task can resized by
+ * {@link android.app.IActivityTaskManager#resizeDockedStack} as expect.
+ */
+ @Test
+ public void testResizeDockedStackForSplitScreenPrimary() throws Exception {
+ final Rect TASK_SIZE = new Rect(0, 0, 600, 600);
+ final Rect STACK_SIZE = new Rect(0, 0, 300, 300);
+
+ // Create primary split-screen stack with a task.
+ final ActivityStack primaryStack = mService.mStackSupervisor.getDefaultDisplay()
+ .createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
+ true /* onTop */);
+ final TaskRecord task = new TaskBuilder(mSupervisor).setStack(primaryStack).build();
+
+ // Resize dock stack.
+ mService.resizeDockedStack(STACK_SIZE, TASK_SIZE, null, null, null);
+
+ // Verify dock stack & its task bounds if is equal as resized result.
+ assertEquals(primaryStack.getBounds(), STACK_SIZE);
+ assertEquals(task.getBounds(), TASK_SIZE);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
index 01425ed..4094716 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
@@ -19,6 +19,7 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
@@ -61,7 +62,7 @@
@Presubmit
@RunWith(AndroidJUnit4.class)
public class ActivityStackTests extends ActivityTestsBase {
- private ActivityManagerService mService;
+ private ActivityTaskManagerService mService;
private ActivityStackSupervisor mSupervisor;
private ActivityDisplay mDefaultDisplay;
private ActivityStack mStack;
@@ -72,7 +73,7 @@
public void setUp() throws Exception {
super.setUp();
- mService = createActivityManagerService();
+ mService = createActivityTaskManagerService();
mSupervisor = mService.mStackSupervisor;
mDefaultDisplay = mService.mStackSupervisor.getDefaultDisplay();
mStack = mDefaultDisplay.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
@@ -473,6 +474,42 @@
}
@Test
+ public void testSetAlwaysOnTop() {
+ final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
+ final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ assertTrue(mDefaultDisplay.getStackAbove(homeStack) == pinnedStack);
+
+ final TestActivityStack alwaysOnTopStack = createStackForShouldBeVisibleTest(
+ mDefaultDisplay, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD,
+ true /* onTop */);
+ alwaysOnTopStack.setAlwaysOnTop(true);
+ assertTrue(alwaysOnTopStack.isAlwaysOnTop());
+ // Ensure (non-pinned) always on top stack is put below pinned stack.
+ assertTrue(mDefaultDisplay.getStackAbove(alwaysOnTopStack) == pinnedStack);
+
+ final TestActivityStack nonAlwaysOnTopStack = createStackForShouldBeVisibleTest(
+ mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
+ true /* onTop */);
+ // Ensure non always on top stack is put below always on top stacks.
+ assertTrue(mDefaultDisplay.getStackAbove(nonAlwaysOnTopStack) == alwaysOnTopStack);
+
+ final TestActivityStack alwaysOnTopStack2 = createStackForShouldBeVisibleTest(
+ mDefaultDisplay, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD,
+ true /* onTop */);
+ alwaysOnTopStack2.setAlwaysOnTop(true);
+ assertTrue(alwaysOnTopStack2.isAlwaysOnTop());
+ // Ensure newly created always on top stack is placed above other all always on top stacks.
+ assertTrue(mDefaultDisplay.getStackAbove(alwaysOnTopStack2) == pinnedStack);
+
+ alwaysOnTopStack2.setAlwaysOnTop(false);
+ // Ensure, when always on top is turned off for a stack, the stack is put just below all
+ // other always on top stacks.
+ assertTrue(mDefaultDisplay.getStackAbove(alwaysOnTopStack2) == alwaysOnTopStack);
+ }
+
+ @Test
public void testSplitScreenMoveToFront() throws Exception {
final TestActivityStack splitScreenPrimary = createStackForShouldBeVisibleTest(
mDefaultDisplay, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java
index a86372a..f5ae46cd 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java
@@ -19,7 +19,9 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import android.app.IApplicationThread;
import android.content.Intent;
+import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -49,7 +51,7 @@
@Presubmit
@RunWith(AndroidJUnit4.class)
public class ActivityStartControllerTests extends ActivityTestsBase {
- private ActivityManagerService mService;
+ private ActivityTaskManagerService mService;
private ActivityStartController mController;
private Factory mFactory;
private ActivityStarter mStarter;
@@ -57,11 +59,11 @@
@Override
public void setUp() throws Exception {
super.setUp();
- mService = createActivityManagerService();
+ mService = createActivityTaskManagerService();
mFactory = mock(Factory.class);
- mController = new ActivityStartController(mService.mActivityTaskManager, mService.mStackSupervisor, mFactory);
- mStarter = spy(new ActivityStarter(mController, mService.mActivityTaskManager, mService.mStackSupervisor,
- mock(ActivityStartInterceptor.class)));
+ mController = new ActivityStartController(mService, mService.mStackSupervisor, mFactory);
+ mStarter = spy(new ActivityStarter(mController, mService,
+ mService.mStackSupervisor, mock(ActivityStartInterceptor.class)));
doReturn(mStarter).when(mFactory).obtain();
}
@@ -77,11 +79,14 @@
final int startFlags = random.nextInt();
final ActivityStack stack = mService.mStackSupervisor.getDefaultDisplay().createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final ProcessRecord process= new ProcessRecord(null, null,
- mService.mContext.getApplicationInfo(), "name", 12345);
+ final WindowProcessController wpc = new WindowProcessController(mService,
+ mService.mContext.getApplicationInfo(), "name", 12345,
+ UserHandle.getUserId(12345), mock(Object.class),
+ mock(WindowProcessListener.class));
+ wpc.setThread(mock(IApplicationThread.class));
mController.addPendingActivityLaunch(
- new PendingActivityLaunch(activity, source, startFlags, stack, process));
+ new PendingActivityLaunch(activity, source, startFlags, stack, wpc));
final boolean resume = random.nextBoolean();
mController.doPendingActivityLaunches(resume);
@@ -96,7 +101,7 @@
@Test
public void testRecycling() throws Exception {
final Intent intent = new Intent();
- final ActivityStarter optionStarter = new ActivityStarter(mController, mService.mActivityTaskManager,
+ final ActivityStarter optionStarter = new ActivityStarter(mController, mService,
mService.mStackSupervisor, mock(ActivityStartInterceptor.class));
optionStarter
.setIntent(intent)
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
index 10d255e..267e689 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
@@ -88,7 +88,7 @@
@Presubmit
@RunWith(AndroidJUnit4.class)
public class ActivityStarterTests extends ActivityTestsBase {
- private ActivityManagerService mService;
+ private ActivityTaskManagerService mService;
private ActivityStarter mStarter;
private ActivityStartController mController;
@@ -107,9 +107,9 @@
@Override
public void setUp() throws Exception {
super.setUp();
- mService = createActivityManagerService();
+ mService = createActivityTaskManagerService();
mController = mock(ActivityStartController.class);
- mStarter = new ActivityStarter(mController, mService.mActivityTaskManager, mService.mStackSupervisor,
+ mStarter = new ActivityStarter(mController, mService, mService.mStackSupervisor,
mock(ActivityStartInterceptor.class));
}
@@ -134,7 +134,7 @@
assertTrue(task2.getStack() instanceof PinnedActivityStack);
mStarter.updateBounds(task2, bounds);
- verify(mService.mActivityTaskManager, times(1)).resizeStack(eq(task2.getStack().mStackId),
+ verify(mService, times(1)).resizeStack(eq(task2.getStack().mStackId),
eq(bounds), anyBoolean(), anyBoolean(), anyBoolean(), anyInt());
// In the case of no animation, the stack and task bounds should be set immediately.
@@ -189,20 +189,21 @@
*/
private void verifyStartActivityPreconditions(int preconditions, int launchFlags,
int expectedResult) {
- final ActivityManagerService service = createActivityManagerService();
+ final ActivityTaskManagerService service = mService;
final IPackageManager packageManager = mock(IPackageManager.class);
final ActivityStartController controller = mock(ActivityStartController.class);
- final ActivityStarter starter = new ActivityStarter(controller, service.mActivityTaskManager,
+ final ActivityStarter starter = new ActivityStarter(controller, service,
service.mStackSupervisor, mock(ActivityStartInterceptor.class));
+ prepareStarter(launchFlags);
final IApplicationThread caller = mock(IApplicationThread.class);
// If no caller app, return {@code null} {@link ProcessRecord}.
final ProcessRecord record = containsConditions(preconditions, PRECONDITION_NO_CALLER_APP)
- ? null : new ProcessRecord(null, mock(BatteryStatsImpl.class),
+ ? null : new ProcessRecord(service.mAm, mock(BatteryStatsImpl.class),
mock(ApplicationInfo.class), null, 0);
- doReturn(record).when(service).getRecordForAppLocked(anyObject());
+ doReturn(record).when(service.mAm).getRecordForAppLocked(anyObject());
final Intent intent = new Intent();
intent.setFlags(launchFlags);
@@ -236,8 +237,8 @@
}
if (containsConditions(preconditions, PRECONDITION_DISALLOW_APP_SWITCHING)) {
- doReturn(false).when(service).checkAppSwitchAllowedLocked(anyInt(), anyInt(), anyInt(),
- anyInt(), any());
+ doReturn(false).when(service).checkAppSwitchAllowedLocked(
+ anyInt(), anyInt(), anyInt(), anyInt(), any());
}
if (containsConditions(preconditions,PRECONDITION_CANNOT_START_ANY_ACTIVITY)) {
@@ -282,7 +283,7 @@
// Ensure that {@link ActivityOptions} are aborted with unsuccessful result.
if (expectedResult != START_SUCCESS) {
- final ActivityStarter optionStarter = new ActivityStarter(mController, mService.mActivityTaskManager,
+ final ActivityStarter optionStarter = new ActivityStarter(mController, mService,
mService.mStackSupervisor, mock(ActivityStartInterceptor.class));
final ActivityOptions options = spy(ActivityOptions.makeBasic());
@@ -336,7 +337,7 @@
info.applicationInfo = new ApplicationInfo();
info.applicationInfo.packageName = ActivityBuilder.getDefaultComponent().getPackageName();
- return new ActivityStarter(mController, mService.mActivityTaskManager,
+ return new ActivityStarter(mController, mService,
mService.mStackSupervisor, mock(ActivityStartInterceptor.class))
.setIntent(intent)
.setActivityInfo(info);
@@ -456,7 +457,7 @@
final ActivityStarter starter = prepareStarter(0);
- final LockTaskController lockTaskController = mService.mActivityTaskManager.getLockTaskController();
+ final LockTaskController lockTaskController = mService.getLockTaskController();
doReturn(true).when(lockTaskController).isLockTaskModeViolation(any());
final int result = starter.setReason("testTaskModeViolation").execute();
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index 06ac3b0..1dd7b4c 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -29,11 +29,14 @@
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
import com.android.server.wm.DisplayWindowController;
import org.junit.Rule;
+import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import android.app.IApplicationThread;
@@ -48,6 +51,7 @@
import android.hardware.display.DisplayManager;
import android.os.HandlerThread;
import android.os.Looper;
+import android.os.UserHandle;
import android.service.voice.IVoiceInteractionSession;
import android.support.test.InstrumentationRegistry;
import android.testing.DexmakerShareClassLoaderRule;
@@ -101,31 +105,33 @@
mHandlerThread.quitSafely();
}
- protected ActivityManagerService createActivityManagerService() {
- final ActivityManagerService service =
- setupActivityManagerService(new TestActivityManagerService(mContext));
- AttributeCache.init(mContext);
- return service;
+ protected ActivityTaskManagerService createActivityTaskManagerService() {
+ final TestActivityTaskManagerService atm = spy(new TestActivityTaskManagerService(mContext));
+ setupActivityManagerService(atm);
+ return atm;
}
- protected ActivityManagerService setupActivityManagerService(
- ActivityManagerService service, ActivityTaskManagerService atm) {
- service = spy(service);
- // Makes sure activity task is created with the spy object.
- atm = spy(atm);
- service.setActivityTaskManager(atm);
+ protected ActivityManagerService createActivityManagerService() {
+ final TestActivityTaskManagerService atm = spy(new TestActivityTaskManagerService(mContext));
+ return setupActivityManagerService(atm);
+ }
+
+ ActivityManagerService setupActivityManagerService(TestActivityTaskManagerService atm) {
+ final ActivityManagerService am = spy(new TestActivityManagerService(mContext, atm));
+ setupActivityManagerService(am, atm);
+ AttributeCache.init(mContext);
+ return am;
+ }
+
+ void setupActivityManagerService(ActivityManagerService am, ActivityTaskManagerService atm) {
+ atm.setActivityManagerService(am);
+ atm.mAmInternal = am.new LocalService();
// Makes sure the supervisor is using with the spy object.
atm.mStackSupervisor.setService(atm);
- doReturn(mock(IPackageManager.class)).when(service).getPackageManager();
- doNothing().when(service).grantEphemeralAccessLocked(anyInt(), any(), anyInt(), anyInt());
- service.mWindowManager = prepareMockWindowManager();
- atm.setWindowManager(service.mWindowManager);
- return service;
- }
-
- protected ActivityManagerService setupActivityManagerService(ActivityManagerService service) {
- return setupActivityManagerService(
- service, new TestActivityTaskManagerService(service.mContext));
+ doReturn(mock(IPackageManager.class)).when(am).getPackageManager();
+ doNothing().when(am).grantEphemeralAccessLocked(anyInt(), any(), anyInt(), anyInt());
+ am.mWindowManager = prepareMockWindowManager();
+ atm.setWindowManager(am.mWindowManager);
}
/**
@@ -137,7 +143,7 @@
- private final ActivityManagerService mService;
+ private final ActivityTaskManagerService mService;
private ComponentName mComponent;
private TaskRecord mTaskRecord;
@@ -146,7 +152,7 @@
private ActivityStack mStack;
private int mActivityFlags;
- ActivityBuilder(ActivityManagerService service) {
+ ActivityBuilder(ActivityTaskManagerService service) {
mService = service;
}
@@ -206,8 +212,7 @@
aInfo.applicationInfo.uid = mUid;
aInfo.flags |= mActivityFlags;
- final ActivityRecord activity = new ActivityRecord(mService.mActivityTaskManager,
- null /* caller */,
+ final ActivityRecord activity = new ActivityRecord(mService, null /* caller */,
0 /* launchedFromPid */, 0, null, intent, null,
aInfo /*aInfo*/, new Configuration(), null /* resultTo */, null /* resultWho */,
0 /* reqCode */, false /*componentSpecified*/, false /* rootVoiceInteraction */,
@@ -218,10 +223,12 @@
mTaskRecord.addActivityToTop(activity);
}
- activity.setProcess(new ProcessRecord(null, null,
- mService.mContext.getApplicationInfo(), "name", 12345));
- activity.app.thread = mock(IApplicationThread.class);
-
+ final WindowProcessController wpc = new WindowProcessController(mService,
+ mService.mContext.getApplicationInfo(), "name", 12345,
+ UserHandle.getUserId(12345), mock(Object.class),
+ mock(WindowProcessListener.class));
+ wpc.setThread(mock(IApplicationThread.class));
+ activity.setProcess(wpc);
return activity;
}
}
@@ -351,6 +358,16 @@
TestActivityTaskManagerService(Context context) {
super(context);
+ mSupportsMultiWindow = true;
+ mSupportsMultiDisplay = true;
+ mSupportsSplitScreenMultiWindow = true;
+ mSupportsFreeformWindowManagement = true;
+ mSupportsPictureInPicture = true;
+ }
+
+ @Override
+ int handleIncomingUser(int callingPid, int callingUid, int userId, String name) {
+ return userId;
}
@Override
@@ -398,13 +415,8 @@
*/
protected static class TestActivityManagerService extends ActivityManagerService {
- TestActivityManagerService(Context context) {
- super(context);
- mSupportsMultiWindow = true;
- mSupportsMultiDisplay = true;
- mSupportsSplitScreenMultiWindow = true;
- mSupportsFreeformWindowManagement = true;
- mSupportsPictureInPicture = true;
+ TestActivityManagerService(Context context, TestActivityTaskManagerService atm) {
+ super(context, atm);
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/am/AssistDataRequesterTest.java b/services/tests/servicestests/src/com/android/server/am/AssistDataRequesterTest.java
index 0a436b9..f74d116 100644
--- a/services/tests/servicestests/src/com/android/server/am/AssistDataRequesterTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AssistDataRequesterTest.java
@@ -113,7 +113,7 @@
mHandler = new Handler(Looper.getMainLooper());
mCallbacksLock = new Object();
mCallbacks = new Callbacks();
- mDataRequester = new AssistDataRequester(mContext, mAm, mWm, mAppOpsManager, mCallbacks,
+ mDataRequester = new AssistDataRequester(mContext, mWm, mAppOpsManager, mCallbacks,
mCallbacksLock, OP_ASSIST_STRUCTURE, OP_ASSIST_SCREENSHOT);
// Gate the continuation of the assist data callbacks until we are ready within the tests
diff --git a/services/tests/servicestests/src/com/android/server/am/LaunchParamsControllerTests.java b/services/tests/servicestests/src/com/android/server/am/LaunchParamsControllerTests.java
index 93e0b5a..fbe552d 100644
--- a/services/tests/servicestests/src/com/android/server/am/LaunchParamsControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/LaunchParamsControllerTests.java
@@ -57,14 +57,14 @@
@Presubmit
@RunWith(AndroidJUnit4.class)
public class LaunchParamsControllerTests extends ActivityTestsBase {
- private ActivityManagerService mService;
+ private ActivityTaskManagerService mService;
private LaunchParamsController mController;
@Before
@Override
public void setUp() throws Exception {
super.setUp();
- mService = createActivityManagerService();
+ mService = createActivityTaskManagerService();
mController = new LaunchParamsController(mService);
}
@@ -200,9 +200,9 @@
mController.registerModifier(positioner);
- doNothing().when(mService.mActivityTaskManager).moveStackToDisplay(anyInt(), anyInt());
+ doNothing().when(mService).moveStackToDisplay(anyInt(), anyInt());
mController.layoutTask(task, null /* windowLayout */);
- verify(mService.mActivityTaskManager, times(1)).moveStackToDisplay(eq(task.getStackId()),
+ verify(mService, times(1)).moveStackToDisplay(eq(task.getStackId()),
eq(params.mPreferredDisplayId));
}
diff --git a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
index cd70677..a4e4409 100644
--- a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
@@ -94,7 +94,7 @@
private static int INVALID_STACK_ID = 999;
private Context mContext = InstrumentationRegistry.getContext();
- private ActivityManagerService mService;
+ private TestActivityTaskManagerService mService;
private ActivityDisplay mDisplay;
private ActivityDisplay mOtherDisplay;
private ActivityStack mStack;
@@ -145,9 +145,10 @@
super.setUp();
mTaskPersister = new TestTaskPersister(mContext.getFilesDir());
- mService = setupActivityManagerService(new MyTestActivityManagerService(mContext),
- new MyTestActivityTaskManagerService(mContext));
- mRecentTasks = (TestRecentTasks) mService.mActivityTaskManager.getRecentTasks();
+ mService = spy(new MyTestActivityTaskManagerService(mContext));
+ final ActivityManagerService am = spy(new MyTestActivityManagerService(mContext, mService));
+ setupActivityManagerService(am, mService);
+ mRecentTasks = (TestRecentTasks) mService.getRecentTasks();
mRecentTasks.loadParametersFromResources(mContext.getResources());
mHomeStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
@@ -674,9 +675,8 @@
@Test
public void testNotRecentsComponent_denyApiAccess() throws Exception {
- doReturn(PackageManager.PERMISSION_DENIED).when(mService).checkPermission(anyString(),
- anyInt(), anyInt());
-
+ doReturn(PackageManager.PERMISSION_DENIED).when(mService)
+ .checkGetTasksPermission(anyString(), anyInt(), anyInt());
// Expect the following methods to fail due to recents component not being set
mRecentTasks.setIsCallerRecentsOverride(TestRecentTasks.DENY_THROW_SECURITY_EXCEPTION);
testRecentTasksApis(false /* expectNoSecurityException */);
@@ -687,8 +687,8 @@
@Test
public void testRecentsComponent_allowApiAccessWithoutPermissions() throws Exception {
- doReturn(PackageManager.PERMISSION_DENIED).when(mService).checkPermission(anyString(),
- anyInt(), anyInt());
+ doReturn(PackageManager.PERMISSION_DENIED).when(mService)
+ .checkGetTasksPermission(anyString(), anyInt(), anyInt());
// Set the recents component and ensure that the following calls do not fail
mRecentTasks.setIsCallerRecentsOverride(TestRecentTasks.GRANT);
@@ -697,58 +697,52 @@
}
private void testRecentTasksApis(boolean expectCallable) {
- assertSecurityException(expectCallable, () -> mService.mActivityTaskManager.removeStack(INVALID_STACK_ID));
+ assertSecurityException(expectCallable, () -> mService.removeStack(INVALID_STACK_ID));
assertSecurityException(expectCallable,
- () -> mService.mActivityTaskManager.removeStacksInWindowingModes(
- new int[] {WINDOWING_MODE_UNDEFINED}));
+ () -> mService.removeStacksInWindowingModes(new int[] {WINDOWING_MODE_UNDEFINED}));
assertSecurityException(expectCallable,
- () -> mService.mActivityTaskManager.removeStacksWithActivityTypes(
- new int[] {ACTIVITY_TYPE_UNDEFINED}));
+ () -> mService.removeStacksWithActivityTypes(new int[] {ACTIVITY_TYPE_UNDEFINED}));
assertSecurityException(expectCallable, () -> mService.removeTask(0));
assertSecurityException(expectCallable,
- () -> mService.mActivityTaskManager.setTaskWindowingMode(
- 0, WINDOWING_MODE_UNDEFINED, true));
+ () -> mService.setTaskWindowingMode(0, WINDOWING_MODE_UNDEFINED, true));
assertSecurityException(expectCallable,
() -> mService.moveTaskToStack(0, INVALID_STACK_ID, true));
assertSecurityException(expectCallable,
- () -> mService.mActivityTaskManager.setTaskWindowingModeSplitScreenPrimary(0,
+ () -> mService.setTaskWindowingModeSplitScreenPrimary(0,
SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, true, true, new Rect(), true));
- assertSecurityException(expectCallable, () -> mService.mActivityTaskManager.dismissSplitScreenMode(true));
- assertSecurityException(expectCallable, () -> mService.mActivityTaskManager.dismissPip(true, 0));
+ assertSecurityException(expectCallable, () -> mService.dismissSplitScreenMode(true));
+ assertSecurityException(expectCallable, () -> mService.dismissPip(true, 0));
assertSecurityException(expectCallable,
- () -> mService.mActivityTaskManager.moveTopActivityToPinnedStack(INVALID_STACK_ID, new Rect()));
+ () -> mService.moveTopActivityToPinnedStack(INVALID_STACK_ID, new Rect()));
assertSecurityException(expectCallable,
() -> mService.resizeStack(INVALID_STACK_ID, new Rect(), true, true, true, 0));
assertSecurityException(expectCallable,
- () -> mService.mActivityTaskManager.resizeDockedStack(new Rect(), new Rect(), new Rect(), new Rect(),
+ () -> mService.resizeDockedStack(new Rect(), new Rect(), new Rect(), new Rect(),
new Rect()));
assertSecurityException(expectCallable,
- () -> mService.mActivityTaskManager.resizePinnedStack(new Rect(), new Rect()));
- assertSecurityException(expectCallable, () -> mService.mActivityTaskManager.getAllStackInfos());
+ () -> mService.resizePinnedStack(new Rect(), new Rect()));
+ assertSecurityException(expectCallable, () -> mService.getAllStackInfos());
assertSecurityException(expectCallable,
- () -> mService.mActivityTaskManager.getStackInfo(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED));
+ () -> mService.getStackInfo(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED));
assertSecurityException(expectCallable, () -> {
try {
- mService.mActivityTaskManager.getFocusedStackInfo();
+ mService.getFocusedStackInfo();
} catch (RemoteException e) {
// Ignore
}
});
assertSecurityException(expectCallable,
- () -> mService.mActivityTaskManager.moveTasksToFullscreenStack(INVALID_STACK_ID, true));
+ () -> mService.moveTasksToFullscreenStack(INVALID_STACK_ID, true));
assertSecurityException(expectCallable,
- () -> mService.mActivityTaskManager.startActivityFromRecents(0, new Bundle()));
- assertSecurityException(expectCallable,
- () -> mService.mActivityTaskManager.getTaskSnapshot(0, true));
- assertSecurityException(expectCallable,
- () -> mService.mActivityTaskManager.registerTaskStackListener(null));
- assertSecurityException(expectCallable,
- () -> mService.mActivityTaskManager.unregisterTaskStackListener(null));
- assertSecurityException(expectCallable, () -> mService.mActivityTaskManager.getTaskDescription(0));
- assertSecurityException(expectCallable, () -> mService.mActivityTaskManager.cancelTaskWindowTransition(0));
- assertSecurityException(expectCallable, () -> mService.mActivityTaskManager.startRecentsActivity(null, null,
+ () -> mService.startActivityFromRecents(0, new Bundle()));
+ assertSecurityException(expectCallable,() -> mService.getTaskSnapshot(0, true));
+ assertSecurityException(expectCallable,() -> mService.registerTaskStackListener(null));
+ assertSecurityException(expectCallable,() -> mService.unregisterTaskStackListener(null));
+ assertSecurityException(expectCallable, () -> mService.getTaskDescription(0));
+ assertSecurityException(expectCallable, () -> mService.cancelTaskWindowTransition(0));
+ assertSecurityException(expectCallable, () -> mService.startRecentsActivity(null, null,
null));
- assertSecurityException(expectCallable, () -> mService.mActivityTaskManager.cancelRecentsAnimation(true));
+ assertSecurityException(expectCallable, () -> mService.cancelRecentsAnimation(true));
assertSecurityException(expectCallable, () -> mService.stopAppSwitches());
assertSecurityException(expectCallable, () -> mService.resumeAppSwitches());
}
@@ -846,8 +840,8 @@
}
private class MyTestActivityManagerService extends TestActivityManagerService {
- MyTestActivityManagerService(Context context) {
- super(context);
+ MyTestActivityManagerService(Context context, TestActivityTaskManagerService atm) {
+ super(context, atm);
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/am/RecentsAnimationTest.java b/services/tests/servicestests/src/com/android/server/am/RecentsAnimationTest.java
index 91a02e4..b642d26 100644
--- a/services/tests/servicestests/src/com/android/server/am/RecentsAnimationTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/RecentsAnimationTest.java
@@ -16,18 +16,16 @@
package com.android.server.am;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -51,10 +49,9 @@
@Presubmit
@RunWith(AndroidJUnit4.class)
public class RecentsAnimationTest extends ActivityTestsBase {
- private static final int TEST_CALLING_PID = 3;
private Context mContext = InstrumentationRegistry.getContext();
- private ActivityManagerService mService;
+ private TestActivityTaskManagerService mService;
private ComponentName mRecentsComponent;
@Before
@@ -63,9 +60,8 @@
super.setUp();
mRecentsComponent = new ComponentName(mContext.getPackageName(), "RecentsActivity");
- mService = setupActivityManagerService(new TestActivityManagerService(mContext),
- new MyTestActivityTaskManagerService(mContext));
- AttributeCache.init(mContext);
+ mService = spy(new MyTestActivityTaskManagerService(mContext));
+ setupActivityManagerService(mService);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/am/RunningTasksTest.java b/services/tests/servicestests/src/com/android/server/am/RunningTasksTest.java
index c6ce7e1..944f20f 100644
--- a/services/tests/servicestests/src/com/android/server/am/RunningTasksTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/RunningTasksTest.java
@@ -50,7 +50,7 @@
public class RunningTasksTest extends ActivityTestsBase {
private Context mContext = InstrumentationRegistry.getContext();
- private ActivityManagerService mService;
+ private ActivityTaskManagerService mService;
private RunningTasks mRunningTasks;
@@ -59,7 +59,7 @@
public void setUp() throws Exception {
super.setUp();
- mService = createActivityManagerService();
+ mService = createActivityTaskManagerService();
mRunningTasks = new RunningTasks();
}
diff --git a/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java b/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java
index 3d323f0..f71a6e7 100644
--- a/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java
@@ -57,7 +57,7 @@
private final static Rect STACK_BOUNDS = new Rect(0, 0, STACK_WIDTH, STACK_HEIGHT);
- private ActivityManagerService mService;
+ private ActivityTaskManagerService mService;
private ActivityStack mStack;
private TaskRecord mTask;
@@ -71,7 +71,7 @@
public void setUp() throws Exception {
super.setUp();
- mService = createActivityManagerService();
+ mService = createActivityTaskManagerService();
mStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */);
mStack.requestResize(STACK_BOUNDS);
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 3d64f2a..2de5d87 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -41,7 +41,6 @@
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
-import android.app.ActivityTaskManagerInternal;
import android.app.IUidObserver;
import android.app.usage.UsageStatsManagerInternal;
import android.content.ActivityNotFoundException;
@@ -93,6 +92,7 @@
import com.android.server.pm.LauncherAppsService.LauncherAppsImpl;
import com.android.server.pm.ShortcutUser.PackageWithUser;
+import com.android.server.wm.ActivityTaskManagerInternal;
import org.junit.Assert;
import org.mockito.ArgumentCaptor;
import org.mockito.invocation.InvocationOnMock;
diff --git a/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java b/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java
index 3514e5a..c4c2ad9 100644
--- a/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java
@@ -14,7 +14,6 @@
import static org.testng.Assert.assertThrows;
import android.app.ActivityManagerInternal;
-import android.app.ActivityTaskManagerInternal;
import android.app.AppOpsManager;
import android.app.IApplicationThread;
import android.content.ComponentName;
@@ -32,6 +31,8 @@
import android.platform.test.annotations.Presubmit;
import android.util.SparseArray;
+import com.android.server.wm.ActivityTaskManagerInternal;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java b/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java
index e4b3b13..62f1433 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java
@@ -16,12 +16,18 @@
package com.android.server.timedetector;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import android.app.timedetector.TimeSignal;
+import android.content.Intent;
+import android.icu.util.Calendar;
+import android.icu.util.GregorianCalendar;
+import android.icu.util.TimeZone;
import android.support.test.runner.AndroidJUnit4;
import android.util.TimestampedValue;
@@ -32,37 +38,476 @@
@RunWith(AndroidJUnit4.class)
public class SimpleTimeZoneDetectorStrategyTest {
- private TimeDetectorStrategy.Callback mMockCallback;
+ private static final Scenario SCENARIO_1 = new Scenario.Builder()
+ .setInitialDeviceSystemClockUtc(1977, 1, 1, 12, 0, 0)
+ .setInitialDeviceRealtimeMillis(123456789L)
+ .setActualTimeUtc(2018, 1, 1, 12, 0, 0)
+ .build();
- private SimpleTimeDetectorStrategy mSimpleTimeZoneDetectorStrategy;
+ private Script mScript;
@Before
public void setUp() {
- mMockCallback = mock(TimeDetectorStrategy.Callback.class);
- mSimpleTimeZoneDetectorStrategy = new SimpleTimeDetectorStrategy();
- mSimpleTimeZoneDetectorStrategy.initialize(mMockCallback);
+ mScript = new Script();
}
@Test
- public void testSuggestTime_nitz() {
- TimestampedValue<Long> utcTime = createUtcTime();
- TimeSignal timeSignal = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime);
+ public void testSuggestTime_nitz_timeDetectionEnabled() {
+ Scenario scenario = SCENARIO_1;
+ mScript.pokeFakeClocks(scenario)
+ .pokeTimeDetectionEnabled(true);
- mSimpleTimeZoneDetectorStrategy.suggestTime(timeSignal);
+ TimeSignal timeSignal = scenario.createTimeSignalForActual(TimeSignal.SOURCE_ID_NITZ);
+ final int clockIncrement = 1000;
+ long expectSystemClockMillis = scenario.getActualTimeMillis() + clockIncrement;
- verify(mMockCallback).setTime(utcTime);
+ mScript.simulateTimePassing(clockIncrement)
+ .simulateTimeSignalReceived(timeSignal)
+ .verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis);
+ }
+
+ @Test
+ public void testSuggestTime_systemClockThreshold() {
+ Scenario scenario = SCENARIO_1;
+ final int systemClockUpdateThresholdMillis = 1000;
+ mScript.pokeFakeClocks(scenario)
+ .pokeThresholds(systemClockUpdateThresholdMillis)
+ .pokeTimeDetectionEnabled(true);
+
+ TimeSignal timeSignal1 = scenario.createTimeSignalForActual(TimeSignal.SOURCE_ID_NITZ);
+ TimestampedValue<Long> utcTime1 = timeSignal1.getUtcTime();
+
+ final int clockIncrement = 100;
+ // Increment the the device clocks to simulate the passage of time.
+ mScript.simulateTimePassing(clockIncrement);
+
+ long expectSystemClockMillis1 =
+ TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
+
+ // Send the first time signal. It should be used.
+ mScript.simulateTimeSignalReceived(timeSignal1)
+ .verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis1);
+
+ // Now send another time signal, but one that is too similar to the last one and should be
+ // ignored.
+ int underThresholdMillis = systemClockUpdateThresholdMillis - 1;
+ TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
+ mScript.peekElapsedRealtimeMillis(),
+ mScript.peekSystemClockMillis() + underThresholdMillis);
+ TimeSignal timeSignal2 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime2);
+ mScript.simulateTimePassing(clockIncrement)
+ .simulateTimeSignalReceived(timeSignal2)
+ .verifySystemClockWasNotSetAndResetCallTracking();
+
+ // Now send another time signal, but one that is on the threshold and so should be used.
+ TimestampedValue<Long> utcTime3 = new TimestampedValue<>(
+ mScript.peekElapsedRealtimeMillis(),
+ mScript.peekSystemClockMillis() + systemClockUpdateThresholdMillis);
+
+ TimeSignal timeSignal3 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime3);
+ mScript.simulateTimePassing(clockIncrement);
+
+ long expectSystemClockMillis3 =
+ TimeDetectorStrategy.getTimeAt(utcTime3, mScript.peekElapsedRealtimeMillis());
+
+ mScript.simulateTimeSignalReceived(timeSignal3)
+ .verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis3);
+ }
+
+ @Test
+ public void testSuggestTime_nitz_timeDetectionDisabled() {
+ Scenario scenario = SCENARIO_1;
+ mScript.pokeFakeClocks(scenario)
+ .pokeTimeDetectionEnabled(false);
+
+ TimeSignal timeSignal = scenario.createTimeSignalForActual(TimeSignal.SOURCE_ID_NITZ);
+ mScript.simulateTimeSignalReceived(timeSignal)
+ .verifySystemClockWasNotSetAndResetCallTracking();
+ }
+
+ @Test
+ public void testSuggestTime_nitz_invalidNitzReferenceTimesIgnored() {
+ Scenario scenario = SCENARIO_1;
+ final int systemClockUpdateThreshold = 2000;
+ mScript.pokeFakeClocks(scenario)
+ .pokeThresholds(systemClockUpdateThreshold)
+ .pokeTimeDetectionEnabled(true);
+ TimeSignal timeSignal1 = scenario.createTimeSignalForActual(TimeSignal.SOURCE_ID_NITZ);
+ TimestampedValue<Long> utcTime1 = timeSignal1.getUtcTime();
+
+ // Initialize the strategy / device with a time set from NITZ.
+ mScript.simulateTimePassing(100);
+ long expectedSystemClockMillis1 =
+ TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
+ mScript.simulateTimeSignalReceived(timeSignal1)
+ .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1);
+
+ // The UTC time increment should be larger than the system clock update threshold so we
+ // know it shouldn't be ignored for other reasons.
+ long validUtcTimeMillis = utcTime1.getValue() + (2 * systemClockUpdateThreshold);
+
+ // Now supply a new signal that has an obviously bogus reference time : older than the last
+ // one.
+ long referenceTimeBeforeLastSignalMillis = utcTime1.getReferenceTimeMillis() - 1;
+ TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
+ referenceTimeBeforeLastSignalMillis, validUtcTimeMillis);
+ TimeSignal timeSignal2 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime2);
+ mScript.simulateTimeSignalReceived(timeSignal2)
+ .verifySystemClockWasNotSetAndResetCallTracking();
+
+ // Now supply a new signal that has an obviously bogus reference time : substantially in the
+ // future.
+ long referenceTimeInFutureMillis =
+ utcTime1.getReferenceTimeMillis() + Integer.MAX_VALUE + 1;
+ TimestampedValue<Long> utcTime3 = new TimestampedValue<>(
+ referenceTimeInFutureMillis, validUtcTimeMillis);
+ TimeSignal timeSignal3 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime3);
+ mScript.simulateTimeSignalReceived(timeSignal3)
+ .verifySystemClockWasNotSetAndResetCallTracking();
+
+ // Just to prove validUtcTimeMillis is valid.
+ long validReferenceTimeMillis = utcTime1.getReferenceTimeMillis() + 100;
+ TimestampedValue<Long> utcTime4 = new TimestampedValue<>(
+ validReferenceTimeMillis, validUtcTimeMillis);
+ long expectedSystemClockMillis4 =
+ TimeDetectorStrategy.getTimeAt(utcTime4, mScript.peekElapsedRealtimeMillis());
+ TimeSignal timeSignal4 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime4);
+ mScript.simulateTimeSignalReceived(timeSignal4)
+ .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis4);
+ }
+
+ @Test
+ public void testSuggestTime_timeDetectionToggled() {
+ Scenario scenario = SCENARIO_1;
+ final int clockIncrementMillis = 100;
+ final int systemClockUpdateThreshold = 2000;
+ mScript.pokeFakeClocks(scenario)
+ .pokeThresholds(systemClockUpdateThreshold)
+ .pokeTimeDetectionEnabled(false);
+
+ TimeSignal timeSignal1 = scenario.createTimeSignalForActual(TimeSignal.SOURCE_ID_NITZ);
+ TimestampedValue<Long> utcTime1 = timeSignal1.getUtcTime();
+
+ // Simulate time passing.
+ mScript.simulateTimePassing(clockIncrementMillis);
+
+ // Simulate the time signal being received. It should not be used because auto time
+ // detection is off but it should be recorded.
+ mScript.simulateTimeSignalReceived(timeSignal1)
+ .verifySystemClockWasNotSetAndResetCallTracking();
+
+ // Simulate more time passing.
+ mScript.simulateTimePassing(clockIncrementMillis);
+
+ long expectedSystemClockMillis1 =
+ TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
+
+ // Turn on auto time detection.
+ mScript.simulateAutoTimeDetectionToggle()
+ .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1);
+
+ // Turn off auto time detection.
+ mScript.simulateAutoTimeDetectionToggle()
+ .verifySystemClockWasNotSetAndResetCallTracking();
+
+ // Receive another valid time signal.
+ // It should be on the threshold and accounting for the clock increments.
+ TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
+ mScript.peekElapsedRealtimeMillis(),
+ mScript.peekSystemClockMillis() + systemClockUpdateThreshold);
+ TimeSignal timeSignal2 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime2);
+
+ // Simulate more time passing.
+ mScript.simulateTimePassing(clockIncrementMillis);
+
+ long expectedSystemClockMillis2 =
+ TimeDetectorStrategy.getTimeAt(utcTime2, mScript.peekElapsedRealtimeMillis());
+
+ // The new time, though valid, should not be set in the system clock because auto time is
+ // disabled.
+ mScript.simulateTimeSignalReceived(timeSignal2)
+ .verifySystemClockWasNotSetAndResetCallTracking();
+
+ // Turn on auto time detection.
+ mScript.simulateAutoTimeDetectionToggle()
+ .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis2);
}
@Test
public void testSuggestTime_unknownSource() {
- TimestampedValue<Long> utcTime = createUtcTime();
- TimeSignal timeSignal = new TimeSignal("unknown", utcTime);
- mSimpleTimeZoneDetectorStrategy.suggestTime(timeSignal);
+ Scenario scenario = SCENARIO_1;
+ mScript.pokeFakeClocks(scenario)
+ .pokeTimeDetectionEnabled(true);
- verify(mMockCallback, never()).setTime(any());
+ TimeSignal timeSignal = scenario.createTimeSignalForActual("unknown");
+ mScript.simulateTimeSignalReceived(timeSignal)
+ .verifySystemClockWasNotSetAndResetCallTracking();
}
- private static TimestampedValue<Long> createUtcTime() {
- return new TimestampedValue<>(321L, 123456L);
+ /**
+ * A fake implementation of TimeDetectorStrategy.Callback. Besides tracking changes and behaving
+ * like the real thing should, it also asserts preconditions.
+ */
+ private static class FakeCallback implements TimeDetectorStrategy.Callback {
+ private boolean mTimeDetectionEnabled;
+ private boolean mWakeLockAcquired;
+ private long mElapsedRealtimeMillis;
+ private long mSystemClockMillis;
+ private int mSystemClockUpdateThresholdMillis = 2000;
+
+ // Tracking operations.
+ private boolean mSystemClockWasSet;
+ private Intent mBroadcastSent;
+
+ @Override
+ public int systemClockUpdateThresholdMillis() {
+ return mSystemClockUpdateThresholdMillis;
+ }
+
+ @Override
+ public boolean isTimeDetectionEnabled() {
+ return mTimeDetectionEnabled;
+ }
+
+ @Override
+ public void acquireWakeLock() {
+ if (mWakeLockAcquired) {
+ fail("Wake lock already acquired");
+ }
+ mWakeLockAcquired = true;
+ }
+
+ @Override
+ public long elapsedRealtimeMillis() {
+ assertWakeLockAcquired();
+ return mElapsedRealtimeMillis;
+ }
+
+ @Override
+ public long systemClockMillis() {
+ assertWakeLockAcquired();
+ return mSystemClockMillis;
+ }
+
+ @Override
+ public void setSystemClock(long newTimeMillis) {
+ assertWakeLockAcquired();
+ mSystemClockWasSet = true;
+ mSystemClockMillis = newTimeMillis;
+ }
+
+ @Override
+ public void releaseWakeLock() {
+ assertWakeLockAcquired();
+ mWakeLockAcquired = false;
+ }
+
+ @Override
+ public void sendStickyBroadcast(Intent intent) {
+ assertNotNull(intent);
+ mBroadcastSent = intent;
+ }
+
+ // Methods below are for managing the fake's behavior.
+
+ public void pokeSystemClockUpdateThreshold(int thresholdMillis) {
+ mSystemClockUpdateThresholdMillis = thresholdMillis;
+ }
+
+ public void pokeElapsedRealtimeMillis(long elapsedRealtimeMillis) {
+ mElapsedRealtimeMillis = elapsedRealtimeMillis;
+ }
+
+ public void pokeSystemClockMillis(long systemClockMillis) {
+ mSystemClockMillis = systemClockMillis;
+ }
+
+ public void pokeTimeDetectionEnabled(boolean enabled) {
+ mTimeDetectionEnabled = enabled;
+ }
+
+ public long peekElapsedRealtimeMillis() {
+ return mElapsedRealtimeMillis;
+ }
+
+ public long peekSystemClockMillis() {
+ return mSystemClockMillis;
+ }
+
+ public void simulateTimePassing(int incrementMillis) {
+ mElapsedRealtimeMillis += incrementMillis;
+ mSystemClockMillis += incrementMillis;
+ }
+
+ public void verifySystemClockNotSet() {
+ assertFalse(mSystemClockWasSet);
+ }
+
+ public void verifySystemClockWasSet(long expectSystemClockMillis) {
+ assertTrue(mSystemClockWasSet);
+ assertEquals(expectSystemClockMillis, mSystemClockMillis);
+ }
+
+ public void verifyIntentWasBroadcast() {
+ assertTrue(mBroadcastSent != null);
+ }
+
+ public void verifyIntentWasNotBroadcast() {
+ assertNull(mBroadcastSent);
+ }
+
+ public void resetCallTracking() {
+ mSystemClockWasSet = false;
+ mBroadcastSent = null;
+ }
+
+ private void assertWakeLockAcquired() {
+ assertTrue("The operation must be performed only after acquiring the wakelock",
+ mWakeLockAcquired);
+ }
+ }
+
+ /**
+ * A fluent helper class for tests.
+ */
+ private class Script {
+
+ private final FakeCallback mFakeCallback;
+ private final SimpleTimeDetectorStrategy mSimpleTimeDetectorStrategy;
+
+ public Script() {
+ mFakeCallback = new FakeCallback();
+ mSimpleTimeDetectorStrategy = new SimpleTimeDetectorStrategy();
+ mSimpleTimeDetectorStrategy.initialize(mFakeCallback);
+
+ }
+
+ Script pokeTimeDetectionEnabled(boolean enabled) {
+ mFakeCallback.pokeTimeDetectionEnabled(enabled);
+ return this;
+ }
+
+ Script pokeFakeClocks(Scenario scenario) {
+ mFakeCallback.pokeElapsedRealtimeMillis(scenario.getInitialRealTimeMillis());
+ mFakeCallback.pokeSystemClockMillis(scenario.getInitialSystemClockMillis());
+ return this;
+ }
+
+ Script pokeThresholds(int systemClockUpdateThreshold) {
+ mFakeCallback.pokeSystemClockUpdateThreshold(systemClockUpdateThreshold);
+ return this;
+ }
+
+ long peekElapsedRealtimeMillis() {
+ return mFakeCallback.peekElapsedRealtimeMillis();
+ }
+
+ long peekSystemClockMillis() {
+ return mFakeCallback.peekSystemClockMillis();
+ }
+
+ Script simulateTimeSignalReceived(TimeSignal timeSignal) {
+ mSimpleTimeDetectorStrategy.suggestTime(timeSignal);
+ return this;
+ }
+
+ Script simulateAutoTimeDetectionToggle() {
+ boolean enabled = !mFakeCallback.isTimeDetectionEnabled();
+ mFakeCallback.pokeTimeDetectionEnabled(enabled);
+ mSimpleTimeDetectorStrategy.handleAutoTimeDetectionToggle(enabled);
+ return this;
+ }
+
+ Script simulateTimePassing(int clockIncrement) {
+ mFakeCallback.simulateTimePassing(clockIncrement);
+ return this;
+ }
+
+ Script verifySystemClockWasNotSetAndResetCallTracking() {
+ mFakeCallback.verifySystemClockNotSet();
+ mFakeCallback.verifyIntentWasNotBroadcast();
+ mFakeCallback.resetCallTracking();
+ return this;
+ }
+
+ Script verifySystemClockWasSetAndResetCallTracking(long expectSystemClockMillis) {
+ mFakeCallback.verifySystemClockWasSet(expectSystemClockMillis);
+ mFakeCallback.verifyIntentWasBroadcast();
+ mFakeCallback.resetCallTracking();
+ return this;
+ }
+ }
+
+ /**
+ * A starting scenario used during tests. Describes a fictional "physical" reality.
+ */
+ private static class Scenario {
+
+ private final long mInitialDeviceSystemClockMillis;
+ private final long mInitialDeviceRealtimeMillis;
+ private final long mActualTimeMillis;
+
+ Scenario(long initialDeviceSystemClock, long elapsedRealtime, long timeMillis) {
+ mInitialDeviceSystemClockMillis = initialDeviceSystemClock;
+ mActualTimeMillis = timeMillis;
+ mInitialDeviceRealtimeMillis = elapsedRealtime;
+ }
+
+ long getInitialRealTimeMillis() {
+ return mInitialDeviceRealtimeMillis;
+ }
+
+ long getInitialSystemClockMillis() {
+ return mInitialDeviceSystemClockMillis;
+ }
+
+ long getActualTimeMillis() {
+ return mActualTimeMillis;
+ }
+
+ TimeSignal createTimeSignalForActual(String sourceId) {
+ TimestampedValue<Long> time = new TimestampedValue<>(
+ mInitialDeviceRealtimeMillis, mActualTimeMillis);
+ return new TimeSignal(sourceId, time);
+ }
+
+ static class Builder {
+
+ private long mInitialDeviceSystemClockMillis;
+ private long mInitialDeviceRealtimeMillis;
+ private long mActualTimeMillis;
+
+ Builder setInitialDeviceSystemClockUtc(int year, int monthInYear, int day,
+ int hourOfDay, int minute, int second) {
+ mInitialDeviceSystemClockMillis = createUtcTime(year, monthInYear, day, hourOfDay,
+ minute, second);
+ return this;
+ }
+
+ Builder setInitialDeviceRealtimeMillis(long realtimeMillis) {
+ mInitialDeviceRealtimeMillis = realtimeMillis;
+ return this;
+ }
+
+ Builder setActualTimeUtc(int year, int monthInYear, int day, int hourOfDay,
+ int minute, int second) {
+ mActualTimeMillis =
+ createUtcTime(year, monthInYear, day, hourOfDay, minute, second);
+ return this;
+ }
+
+ Scenario build() {
+ return new Scenario(mInitialDeviceSystemClockMillis, mInitialDeviceRealtimeMillis,
+ mActualTimeMillis);
+ }
+ }
+ }
+
+ private static long createUtcTime(int year, int monthInYear, int day, int hourOfDay, int minute,
+ int second) {
+ Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("Etc/UTC"));
+ cal.clear();
+ cal.set(year, monthInYear - 1, day, hourOfDay, minute, second);
+ return cal.getTimeInMillis();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index 22dea92..ed74cd7 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -16,6 +16,9 @@
package com.android.server.timedetector;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
@@ -23,36 +26,40 @@
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
import android.app.timedetector.TimeSignal;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.support.test.runner.AndroidJUnit4;
import android.util.TimestampedValue;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import com.android.server.timedetector.TimeDetectorStrategy.Callback;
+
+import java.io.PrintWriter;
+
@RunWith(AndroidJUnit4.class)
public class TimeDetectorServiceTest {
- private TimeDetectorService mTimeDetectorService;
-
private Context mMockContext;
- private TimeDetectorStrategy mMockTimeDetectorStrategy;
+ private StubbedTimeDetectorStrategy mStubbedTimeDetectorStrategy;
+ private Callback mMockCallback;
+
+ private TimeDetectorService mTimeDetectorService;
@Before
public void setUp() {
mMockContext = mock(Context.class);
- mMockTimeDetectorStrategy = mock(TimeDetectorStrategy.class);
- mTimeDetectorService = new TimeDetectorService(mMockContext, mMockTimeDetectorStrategy);
- }
+ mMockCallback = mock(Callback.class);
+ mStubbedTimeDetectorStrategy = new StubbedTimeDetectorStrategy();
- @After
- public void tearDown() {
- verifyNoMoreInteractions(mMockContext, mMockTimeDetectorStrategy);
+ mTimeDetectorService = new TimeDetectorService(
+ mMockContext, mMockCallback,
+ mStubbedTimeDetectorStrategy);
}
@Test(expected=SecurityException.class)
@@ -78,11 +85,86 @@
verify(mMockContext)
.enforceCallingPermission(eq(android.Manifest.permission.SET_TIME), anyString());
- verify(mMockTimeDetectorStrategy).suggestTime(timeSignal);
+ mStubbedTimeDetectorStrategy.verifySuggestTimeCalled(timeSignal);
+ }
+
+ @Test
+ public void testDump() {
+ when(mMockContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
+
+ mTimeDetectorService.dump(null, null, null);
+
+ verify(mMockContext).checkCallingOrSelfPermission(eq(android.Manifest.permission.DUMP));
+ mStubbedTimeDetectorStrategy.verifyDumpCalled();
+ }
+
+ @Test
+ public void testAutoTimeDetectionToggle() {
+ when(mMockCallback.isTimeDetectionEnabled()).thenReturn(true);
+
+ mTimeDetectorService.handleAutoTimeDetectionToggle();
+
+ mStubbedTimeDetectorStrategy.verifyHandleAutoTimeDetectionToggleCalled(true);
+
+ when(mMockCallback.isTimeDetectionEnabled()).thenReturn(false);
+
+ mTimeDetectorService.handleAutoTimeDetectionToggle();
+
+ mStubbedTimeDetectorStrategy.verifyHandleAutoTimeDetectionToggleCalled(false);
}
private static TimeSignal createNitzTimeSignal() {
TimestampedValue<Long> timeValue = new TimestampedValue<>(100L, 1_000_000L);
return new TimeSignal(TimeSignal.SOURCE_ID_NITZ, timeValue);
}
+
+ private static class StubbedTimeDetectorStrategy implements TimeDetectorStrategy {
+
+ // Call tracking.
+ private TimeSignal mLastSuggestedTime;
+ private Boolean mLastAutoTimeDetectionToggle;
+ private boolean mDumpCalled;
+
+ @Override
+ public void initialize(Callback ignored) {
+ }
+
+ @Override
+ public void suggestTime(TimeSignal timeSignal) {
+ resetCallTracking();
+ mLastSuggestedTime = timeSignal;
+ }
+
+ @Override
+ public void handleAutoTimeDetectionToggle(boolean enabled) {
+ resetCallTracking();
+ mLastAutoTimeDetectionToggle = enabled;
+ }
+
+ @Override
+ public void dump(PrintWriter pw, String[] args) {
+ resetCallTracking();
+ mDumpCalled = true;
+ }
+
+ void resetCallTracking() {
+ mLastSuggestedTime = null;
+ mLastAutoTimeDetectionToggle = null;
+ mDumpCalled = false;
+ }
+
+ void verifySuggestTimeCalled(TimeSignal expectedSignal) {
+ assertEquals(expectedSignal, mLastSuggestedTime);
+ }
+
+ void verifyHandleAutoTimeDetectionToggleCalled(boolean expectedEnable) {
+ assertNotNull(mLastAutoTimeDetectionToggle);
+ assertEquals(expectedEnable, mLastAutoTimeDetectionToggle);
+ }
+
+ void verifyDumpCalled() {
+ assertTrue(mDumpCalled);
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
new file mode 100644
index 0000000..19d31cf
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 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.timezonedetector;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Unit tests for the {@link TimeZoneDetectorService}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class TimeZoneDetectorServiceTest {
+
+ private TimeZoneDetectorService mTimeZoneDetectorService;
+
+ @Before
+ public void setUp() {
+ final Context context = InstrumentationRegistry.getContext();
+ mTimeZoneDetectorService = new TimeZoneDetectorService(context);
+ }
+
+ @Test
+ public void testStubbedCall() {
+ mTimeZoneDetectorService.stubbedCall();
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index c3b2f87..ec068db 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -385,9 +385,12 @@
@Test
public void testAlwaysOnTopStackLocation() {
final TaskStack alwaysOnTopStack = createTaskStackOnDisplay(mDisplayContent);
+ final Task task = createTaskInStack(alwaysOnTopStack, 0 /* userId */);
alwaysOnTopStack.setAlwaysOnTop(true);
mDisplayContent.positionStackAt(POSITION_TOP, alwaysOnTopStack);
assertTrue(alwaysOnTopStack.isAlwaysOnTop());
+ // Ensure always on top state is synced to the children of the stack.
+ assertTrue(alwaysOnTopStack.getTopChild().isAlwaysOnTop());
assertEquals(alwaysOnTopStack, mDisplayContent.getTopStack());
final TaskStack pinnedStack = createStackControllerOnStackOnDisplay(
@@ -410,6 +413,14 @@
// Ensure the non-alwaysOnTop stack is put below the three alwaysOnTop stacks, but above the
// existing other non-alwaysOnTop stacks.
assertEquals(nonAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 3));
+
+ anotherAlwaysOnTopStack.setAlwaysOnTop(false);
+ mDisplayContent.positionStackAt(POSITION_TOP, anotherAlwaysOnTopStack);
+ assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop());
+ topPosition = mDisplayContent.getStacks().size() - 1;
+ // Ensure, when always on top is turned off for a stack, the stack is put just below all
+ // other always on top stacks.
+ assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 2));
}
/**
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java
index 513c1ec..10d7aad 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java
@@ -31,6 +31,7 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOW_CONFIG_ALWAYS_ON_TOP;
import static android.app.WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS;
import static android.app.WindowConfiguration.WINDOW_CONFIG_WINDOWING_MODE;
import static android.content.pm.ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
@@ -81,6 +82,11 @@
assertEquals(WINDOW_CONFIG_APP_BOUNDS | WINDOW_CONFIG_WINDOWING_MODE,
winConfig1.diff(winConfig2, false /* compareUndefined */));
+ winConfig2.setAlwaysOnTop(true);
+ assertEquals(WINDOW_CONFIG_APP_BOUNDS | WINDOW_CONFIG_WINDOWING_MODE
+ | WINDOW_CONFIG_ALWAYS_ON_TOP,
+ winConfig1.diff(winConfig2, false /* compareUndefined */));
+
assertEquals(0, config1.diff(config3));
assertEquals(0, config1.diffPublicOnly(config3));
assertEquals(0, winConfig1.diff(winConfig3, false /* compareUndefined */));
@@ -108,6 +114,12 @@
assertNotEquals(winConfig1.compareTo(winConfig2), 0);
winConfig2.setWindowingMode(winConfig1.getWindowingMode());
+ // Different always on top state
+ winConfig2.setAlwaysOnTop(true);
+ assertNotEquals(config1.compareTo(config2), 0);
+ assertNotEquals(winConfig1.compareTo(winConfig2), 0);
+ winConfig2.setAlwaysOnTop(winConfig1.isAlwaysOnTop());
+
// Different bounds
winConfig2.setAppBounds(0, 2, 3, 4);
assertNotEquals(config1.compareTo(config2), 0);
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
index 6c7830e..f8b2828 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
@@ -256,6 +256,33 @@
}
@Test
+ public void testAddChildByIndex() throws Exception {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+ final TestWindowContainer root = builder.setLayer(0).build();
+
+ final TestWindowContainer child = root.addChildWindow();
+
+ final TestWindowContainer child2 = builder.setLayer(1).build();
+ final TestWindowContainer child3 = builder.setLayer(2).build();
+ final TestWindowContainer child4 = builder.setLayer(3).build();
+
+ // Test adding at top.
+ root.addChild(child2, POSITION_TOP);
+ assertEquals(child2, root.getChildAt(root.getChildrenCount() - 1));
+
+ // Test adding at bottom.
+ root.addChild(child3, POSITION_BOTTOM);
+ assertEquals(child3, root.getChildAt(0));
+
+ // Test adding in the middle.
+ root.addChild(child4, 1);
+ assertEquals(child3, root.getChildAt(0));
+ assertEquals(child4, root.getChildAt(1));
+ assertEquals(child, root.getChildAt(2));
+ assertEquals(child2, root.getChildAt(3));
+ }
+
+ @Test
public void testPositionChildAt() throws Exception {
final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
final TestWindowContainer root = builder.setLayer(0).build();
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
index 69cfaad..d13c3c9 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
@@ -29,7 +29,6 @@
import static org.mockito.Mockito.mock;
import android.app.ActivityManagerInternal;
-import android.app.ActivityTaskManagerInternal;
import android.content.Context;
import android.hardware.display.DisplayManagerInternal;
import android.os.PowerManagerInternal;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelTest.java
index 2241047..ca473c6 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelTest.java
@@ -19,20 +19,26 @@
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNull;
import android.app.NotificationChannel;
+import android.net.Uri;
import android.os.Parcel;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Xml;
import com.android.internal.util.FastXmlSerializer;
import com.android.server.UiServiceTestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
+import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@SmallTest
@@ -68,4 +74,23 @@
serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
channel.writeXml(serializer);
}
+
+ @Test
+ public void testBackupEmptySound() throws Exception {
+ NotificationChannel channel = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
+ channel.setSound(Uri.EMPTY, null);
+
+ XmlSerializer serializer = new FastXmlSerializer();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
+ channel.writeXmlForBackup(serializer, getContext());
+
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(baos.toByteArray())), null);
+ NotificationChannel restored = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
+ restored.populateFromXmlForRestore(parser, getContext());
+
+ assertNull(restored.getSound());
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 96c948f..45a3c41 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -3003,6 +3003,20 @@
}
@Test
+ public void testVisualDifference_summaryNewNotification() {
+ Notification.Builder nb2 = new Notification.Builder(mContext, "")
+ .setGroup("bananas")
+ .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
+ .setContentText("bar");
+ StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
+ nb2.build(), new UserHandle(mUid), null, 0);
+ NotificationRecord r2 =
+ new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
+
+ assertFalse(mService.isVisuallyInterruptive(null, r2));
+ }
+
+ @Test
public void testHideAndUnhideNotificationsOnSuspendedPackageBroadcast() {
// post 2 notification from this package
final NotificationRecord notif1 = generateNotificationRecord(
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
index 942a07a..96ac935 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
@@ -121,7 +121,7 @@
cal.set(Calendar.MINUTE, 15);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
- mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay() + 1};
+ mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay(1)};
mScheduleInfo.startHour = 1;
mScheduleInfo.endHour = 3;
mScheduleInfo.startMinute = 15;
@@ -149,7 +149,7 @@
cal.set(Calendar.MINUTE, 15);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
- mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay() + 1};
+ mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay(1)};
mScheduleInfo.startHour = 22;
mScheduleInfo.endHour = 3;
mScheduleInfo.startMinute = 15;
@@ -250,7 +250,7 @@
calAlarm.add(Calendar.DATE, 1); // add a day
// ScheduleInfo: day 1, day 2: 9pm-7am
- mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay() + 1};
+ mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay(1)};
mScheduleInfo.startHour = 21;
mScheduleInfo.endHour = 7;
mScheduleInfo.startMinute = 0;
@@ -418,7 +418,7 @@
now.set(Calendar.MILLISECOND, 0);
now.add(Calendar.DATE, 1); // add a day
- mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay() + 1};
+ mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay(1)};
mScheduleInfo.startHour = 22;
mScheduleInfo.startMinute = 15;
mScheduleInfo.endHour = 3;
@@ -446,7 +446,7 @@
now.set(Calendar.MILLISECOND, 0);
now.add(Calendar.DATE, 1); // add a day
- mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay() + 1};
+ mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay(1)};
mScheduleInfo.startHour = 22;
mScheduleInfo.startMinute = 15;
mScheduleInfo.endHour = 3;
@@ -464,4 +464,10 @@
private int getTodayDay() {
return new GregorianCalendar().get(Calendar.DAY_OF_WEEK);
}
+
+ private int getTodayDay(int offset) {
+ Calendar cal = new GregorianCalendar();
+ cal.add(Calendar.DATE, offset);
+ return cal.get(Calendar.DAY_OF_WEEK);
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
index 43a4e27..1db8967 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
@@ -18,6 +18,7 @@
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
@@ -59,7 +60,7 @@
public class SliceManagerServiceTest extends UiServiceTestCase {
private static final String AUTH = "com.android.services.uitests";
- private static final Uri TEST_URI = maybeAddUserId(Uri.parse("content://" + AUTH + "/path"), 0);
+ private static final Uri TEST_URI = Uri.parse("content://" + AUTH + "/path");
private static final SliceSpec[] EMPTY_SPECS = new SliceSpec[]{
};
@@ -93,7 +94,7 @@
mService.pinSlice("pkg", TEST_URI, EMPTY_SPECS, mToken);
mService.pinSlice("pkg", TEST_URI, EMPTY_SPECS, mToken);
- verify(mService, times(1)).createPinnedSlice(eq(TEST_URI), anyString());
+ verify(mService, times(1)).createPinnedSlice(eq(maybeAddUserId(TEST_URI, 0)), anyString());
}
@Test
@@ -126,4 +127,19 @@
verify(mContextSpy).checkPermission(eq("perm2"), eq(Process.myPid()), eq(Process.myUid()));
}
+ @Test(expected = IllegalStateException.class)
+ public void testNoPinThrow() throws Exception {
+ mService.getPinnedSpecs(TEST_URI, "pkg");
+ }
+
+ @Test
+ public void testGetPinnedSpecs() throws Exception {
+ SliceSpec[] specs = new SliceSpec[] {
+ new SliceSpec("Something", 1) };
+ mService.pinSlice("pkg", TEST_URI, specs, mToken);
+
+ when(mCreatedSliceState.getSpecs()).thenReturn(specs);
+ assertEquals(specs, mService.getPinnedSpecs(TEST_URI, "pkg"));
+ }
+
}
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index a919d38..63945a9 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -20,8 +20,8 @@
import static com.android.internal.util.dump.DumpUtils.writeStringIfNotNull;
import android.app.ActivityManager;
-import android.app.ActivityManagerInternal;
-import android.app.ActivityTaskManagerInternal;
+
+import com.android.server.wm.ActivityTaskManagerInternal;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationChannel;
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index cd1b835..c5d6dc7 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -19,7 +19,7 @@
import android.Manifest;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
-import android.app.ActivityTaskManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal;
import android.app.AppGlobals;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -433,11 +433,11 @@
if (hasComponent) {
mShortcutServiceInternal.setShortcutHostPackage(TAG,
serviceComponent.getPackageName(), mCurUser);
- mAmInternal.setAllowAppSwitches(TAG,
+ mAtmInternal.setAllowAppSwitches(TAG,
serviceInfo.applicationInfo.uid, mCurUser);
} else {
mShortcutServiceInternal.setShortcutHostPackage(TAG, null, mCurUser);
- mAmInternal.setAllowAppSwitches(TAG, -1, mCurUser);
+ mAtmInternal.setAllowAppSwitches(TAG, -1, mCurUser);
}
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 54f99a6..92aa152 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -23,10 +23,9 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import android.app.ActivityManager;
-import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
-import android.app.ActivityTaskManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal;
import android.app.IActivityManager;
import android.app.IActivityTaskManager;
import android.content.BroadcastReceiver;
@@ -50,7 +49,6 @@
import android.util.Slog;
import android.view.IWindowManager;
-import com.android.internal.app.IVoiceInteractionSessionListener;
import com.android.internal.app.IVoiceInteractionSessionShowCallback;
import com.android.internal.app.IVoiceInteractor;
import com.android.server.LocalServices;
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index 4eaed34..01f5d9c 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -16,9 +16,9 @@
package com.android.server.voiceinteraction;
-import static android.app.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT;
-import static android.app.ActivityTaskManagerInternal.ASSIST_KEY_DATA;
-import static android.app.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE;
+import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT;
+import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_DATA;
+import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE;
import static android.app.AppOpsManager.OP_ASSIST_SCREENSHOT;
import static android.app.AppOpsManager.OP_ASSIST_STRUCTURE;
import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
@@ -144,7 +144,7 @@
mIWindowManager = IWindowManager.Stub.asInterface(
ServiceManager.getService(Context.WINDOW_SERVICE));
mAppOps = context.getSystemService(AppOpsManager.class);
- mAssistDataRequester = new AssistDataRequester(mContext, mAm, mIWindowManager,
+ mAssistDataRequester = new AssistDataRequester(mContext, mIWindowManager,
(AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE),
this, mLock, OP_ASSIST_STRUCTURE, OP_ASSIST_SCREENSHOT);
IBinder permOwner = null;
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 3bf951d..3e97c8f 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -45,6 +45,7 @@
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
+import java.nio.channels.Channels;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -861,8 +862,11 @@
public RttTextStream(ParcelFileDescriptor toInCall, ParcelFileDescriptor fromInCall) {
mFdFromInCall = fromInCall;
mFdToInCall = toInCall;
+
+ // Wrap the FileInputStream in a Channel so that it's interruptible.
mPipeFromInCall = new InputStreamReader(
- new FileInputStream(fromInCall.getFileDescriptor()));
+ Channels.newInputStream(Channels.newChannel(
+ new FileInputStream(fromInCall.getFileDescriptor()))));
mPipeToInCall = new OutputStreamWriter(
new FileOutputStream(toInCall.getFileDescriptor()));
}
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 2d096c0..8283e97 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -3542,6 +3542,12 @@
public static final String ICCID_PREFIX = "iccid_prefix";
/**
+ * Certificate for carrier privilege access rules.
+ * <P>Type: TEXT in hex string </P>
+ */
+ public static final String PRIVILEGE_ACCESS_RULE = "privilege_access_rule";
+
+ /**
* The {@code content://} URI for this table.
*/
public static final Uri CONTENT_URI = Uri.parse("content://carrier_id/all");
diff --git a/telephony/java/android/telephony/LocationAccessPolicy.java b/telephony/java/android/telephony/LocationAccessPolicy.java
index 6db8e82..53d69f4 100644
--- a/telephony/java/android/telephony/LocationAccessPolicy.java
+++ b/telephony/java/android/telephony/LocationAccessPolicy.java
@@ -39,7 +39,8 @@
* @hide
*/
public final class LocationAccessPolicy {
- private static final String LOG_TAG = LocationAccessPolicy.class.getSimpleName();
+ private static final String TAG = "LocationAccessPolicy";
+ private static final boolean DBG = false;
/**
* API to determine if the caller has permissions to get cell location.
@@ -52,12 +53,13 @@
*/
public static boolean canAccessCellLocation(@NonNull Context context, @NonNull String pkgName,
int uid, int pid, boolean throwOnDeniedPermission) throws SecurityException {
- Trace.beginSection("TelephonyLohcationCheck");
+ Trace.beginSection("TelephonyLocationCheck");
try {
- // Always allow the phone process to access location. This avoid breaking legacy code
- // that rely on public-facing APIs to access cell location, and it doesn't create a
- // info leak risk because the cell location is stored in the phone process anyway.
- if (uid == Process.PHONE_UID) {
+ // Always allow the phone process and system server to access location. This avoid
+ // breaking legacy code that rely on public-facing APIs to access cell location, and
+ // it doesn't create an info leak risk because the cell location is stored in the phone
+ // process anyway, and the system server already has location access.
+ if (uid == Process.PHONE_UID || uid == Process.SYSTEM_UID || uid == Process.ROOT_UID) {
return true;
}
@@ -72,15 +74,18 @@
pid, uid, "canAccessCellLocation");
} else if (context.checkPermission(Manifest.permission.ACCESS_COARSE_LOCATION,
pid, uid) == PackageManager.PERMISSION_DENIED) {
+ if (DBG) Log.w(TAG, "Permission checked failed (" + pid + "," + uid + ")");
return false;
}
final int opCode = AppOpsManager.permissionToOpCode(
Manifest.permission.ACCESS_COARSE_LOCATION);
if (opCode != AppOpsManager.OP_NONE && context.getSystemService(AppOpsManager.class)
.noteOpNoThrow(opCode, uid, pkgName) != AppOpsManager.MODE_ALLOWED) {
+ if (DBG) Log.w(TAG, "AppOp check failed (" + uid + "," + pkgName + ")");
return false;
}
if (!isLocationModeEnabled(context, UserHandle.getUserId(uid))) {
+ if (DBG) Log.w(TAG, "Location disabled, failed, (" + uid + ")");
return false;
}
// If the user or profile is current, permission is granted.
@@ -94,7 +99,7 @@
private static boolean isLocationModeEnabled(@NonNull Context context, @UserIdInt int userId) {
LocationManager locationManager = context.getSystemService(LocationManager.class);
if (locationManager == null) {
- Log.w(LOG_TAG, "Couldn't get location manager, denying location access");
+ Log.w(TAG, "Couldn't get location manager, denying location access");
return false;
}
return locationManager.isLocationEnabledForUser(UserHandle.of(userId));
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index d7568b4..6e261dd 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -335,11 +335,18 @@
* <p>
* The {@link #EXTRA_STATE} extra indicates the new call state.
* If a receiving app has {@link android.Manifest.permission#READ_CALL_LOG} permission, a second
- * extra {@link #EXTRA_INCOMING_NUMBER} provides the phone number for incoming and outoing calls
- * as a String. Note: If the receiving app has
+ * extra {@link #EXTRA_INCOMING_NUMBER} provides the phone number for incoming and outgoing
+ * calls as a String.
+ * <p>
+ * If the receiving app has
* {@link android.Manifest.permission#READ_CALL_LOG} and
* {@link android.Manifest.permission#READ_PHONE_STATE} permission, it will receive the
- * broadcast twice; one with the phone number and another without it.
+ * broadcast twice; one with the {@link #EXTRA_INCOMING_NUMBER} populated with the phone number,
+ * and another with it blank. Due to the nature of broadcasts, you cannot assume the order
+ * in which these broadcasts will arrive, however you are guaranteed to receive two in this
+ * case. Apps which are interested in the {@link #EXTRA_INCOMING_NUMBER} can ignore the
+ * broadcasts where {@link #EXTRA_INCOMING_NUMBER} is not present in the extras (e.g. where
+ * {@link Intent#hasExtra(String)} returns {@code false}).
* <p class="note">
* This was a {@link android.content.Context#sendStickyBroadcast sticky}
* broadcast in version 1.0, but it is no longer sticky.
@@ -488,10 +495,19 @@
public static final String EXTRA_STATE_OFFHOOK = PhoneConstants.State.OFFHOOK.toString();
/**
- * The lookup key used with the {@link #ACTION_PHONE_STATE_CHANGED} broadcast
- * for a String containing the incoming phone number.
- * Only valid when the new call state is RINGING.
- *
+ * Extra key used with the {@link #ACTION_PHONE_STATE_CHANGED} broadcast
+ * for a String containing the incoming or outgoing phone number.
+ * <p>
+ * This extra is only populated for receivers of the {@link #ACTION_PHONE_STATE_CHANGED}
+ * broadcast which have been granted the {@link android.Manifest.permission#READ_CALL_LOG} and
+ * {@link android.Manifest.permission#READ_PHONE_STATE} permissions.
+ * <p>
+ * For incoming calls, the phone number is only guaranteed to be populated when the
+ * {@link #EXTRA_STATE} changes from {@link #EXTRA_STATE_IDLE} to {@link #EXTRA_STATE_RINGING}.
+ * If the incoming caller is from an unknown number, the extra will be populated with an empty
+ * string.
+ * For outgoing calls, the phone number is only guaranteed to be populated when the
+ * {@link #EXTRA_STATE} changes from {@link #EXTRA_STATE_IDLE} to {@link #EXTRA_STATE_OFFHOOK}.
* <p class="note">
* Retrieve with
* {@link android.content.Intent#getStringExtra(String)}.
@@ -2767,7 +2783,8 @@
}
/**
- * Gets all the UICC slots.
+ * Gets all the UICC slots. The objects in the array can be null if the slot info is not
+ * available, which is possible between phone process starting and getting slot info from modem.
*
* @return UiccSlotInfo array.
*
@@ -5432,23 +5449,6 @@
}
/**
- * @return true if the IMS resolver is busy resolving a binding and should not be considered
- * available, false if the IMS resolver is idle.
- * @hide
- */
- public boolean isResolvingImsBinding() {
- try {
- ITelephony telephony = getITelephony();
- if (telephony != null) {
- return telephony.isResolvingImsBinding();
- }
- } catch (RemoteException e) {
- Rlog.e(TAG, "isResolvingImsBinding, RemoteException: " + e.getMessage());
- }
- return false;
- }
-
- /**
* Set IMS registration state
*
* @param Registration state
diff --git a/telephony/java/android/telephony/ims/ImsExternalCallState.java b/telephony/java/android/telephony/ims/ImsExternalCallState.java
index e82c115..d03c7e1 100644
--- a/telephony/java/android/telephony/ims/ImsExternalCallState.java
+++ b/telephony/java/android/telephony/ims/ImsExternalCallState.java
@@ -45,6 +45,7 @@
private int mCallId;
// Number
private Uri mAddress;
+ private Uri mLocalAddress;
private boolean mIsPullable;
// CALL_STATE_CONFIRMED / CALL_STATE_TERMINATED
private int mCallState;
@@ -69,6 +70,19 @@
}
/** @hide */
+ public ImsExternalCallState(int callId, Uri address, Uri localAddress,
+ boolean isPullable, int callState, int callType, boolean isCallheld) {
+ mCallId = callId;
+ mAddress = address;
+ mLocalAddress = localAddress;
+ mIsPullable = isPullable;
+ mCallState = callState;
+ mCallType = callType;
+ mIsHeld = isCallheld;
+ Rlog.d(TAG, "ImsExternalCallState = " + this);
+ }
+
+ /** @hide */
public ImsExternalCallState(Parcel in) {
mCallId = in.readInt();
ClassLoader classLoader = ImsExternalCallState.class.getClassLoader();
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index d537699..b77881e 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -341,15 +341,15 @@
}
}
+ /** @hide */
+ protected Context mContext;
+ /** @hide */
+ protected final Object mLock = new Object();
+
private final Set<IImsFeatureStatusCallback> mStatusCallbacks = Collections.newSetFromMap(
new WeakHashMap<IImsFeatureStatusCallback, Boolean>());
private @ImsState int mState = STATE_UNAVAILABLE;
private int mSlotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
- /**
- * @hide
- */
- protected Context mContext;
- private final Object mLock = new Object();
private final RemoteCallbackList<IImsCapabilityCallback> mCapabilityCallbacks
= new RemoteCallbackList<>();
private Capabilities mCapabilityStatus = new Capabilities();
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index bc790fb..7681aef 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -22,25 +22,25 @@
import android.os.Message;
import android.os.RemoteException;
import android.telecom.TelecomManager;
-import android.telephony.ims.stub.ImsRegistrationImplBase;
-import android.telephony.ims.stub.ImsCallSessionImplBase;
-import android.telephony.ims.stub.ImsSmsImplBase;
+import android.telephony.ims.ImsCallProfile;
+import android.telephony.ims.ImsCallSession;
+import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.aidl.IImsMmTelFeature;
import android.telephony.ims.aidl.IImsMmTelListener;
import android.telephony.ims.aidl.IImsSmsListener;
+import android.telephony.ims.stub.ImsCallSessionImplBase;
import android.telephony.ims.stub.ImsEcbmImplBase;
import android.telephony.ims.stub.ImsMultiEndpointImplBase;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.telephony.ims.stub.ImsSmsImplBase;
import android.telephony.ims.stub.ImsUtImplBase;
import android.util.Log;
-import android.telephony.ims.ImsCallProfile;
-import android.telephony.ims.ImsReasonInfo;
import com.android.ims.internal.IImsCallSession;
import com.android.ims.internal.IImsEcbm;
import com.android.ims.internal.IImsMultiEndpoint;
import com.android.ims.internal.IImsUt;
-import android.telephony.ims.ImsCallSession;
import com.android.internal.annotations.VisibleForTesting;
import java.lang.annotation.Retention;
@@ -61,20 +61,16 @@
private final IImsMmTelFeature mImsMMTelBinder = new IImsMmTelFeature.Stub() {
@Override
- public void setListener(IImsMmTelListener l) throws RemoteException {
- synchronized (mLock) {
- MmTelFeature.this.setListener(l);
- }
+ public void setListener(IImsMmTelListener l) {
+ MmTelFeature.this.setListener(l);
}
@Override
public int getFeatureState() throws RemoteException {
- synchronized (mLock) {
- try {
- return MmTelFeature.this.getFeatureState();
- } catch (Exception e) {
- throw new RemoteException(e.getMessage());
- }
+ try {
+ return MmTelFeature.this.getFeatureState();
+ } catch (Exception e) {
+ throw new RemoteException(e.getMessage());
}
}
@@ -138,10 +134,8 @@
}
@Override
- public int queryCapabilityStatus() throws RemoteException {
- synchronized (mLock) {
- return MmTelFeature.this.queryCapabilityStatus().mCapabilities;
- }
+ public int queryCapabilityStatus() {
+ return MmTelFeature.this.queryCapabilityStatus().mCapabilities;
}
@Override
@@ -158,7 +152,7 @@
@Override
public void changeCapabilitiesConfiguration(CapabilityChangeRequest request,
- IImsCapabilityCallback c) throws RemoteException {
+ IImsCapabilityCallback c) {
synchronized (mLock) {
MmTelFeature.this.requestChangeEnabledCapabilities(request, c);
}
@@ -173,10 +167,8 @@
}
@Override
- public void setSmsListener(IImsSmsListener l) throws RemoteException {
- synchronized (mLock) {
- MmTelFeature.this.setSmsListener(l);
- }
+ public void setSmsListener(IImsSmsListener l) {
+ MmTelFeature.this.setSmsListener(l);
}
@Override
@@ -364,9 +356,6 @@
@Retention(RetentionPolicy.SOURCE)
public @interface ProcessCallResult {}
-
- // Lock for feature synchronization
- private final Object mLock = new Object();
private IImsMmTelListener mListener;
/**
@@ -376,9 +365,9 @@
private void setListener(IImsMmTelListener listener) {
synchronized (mLock) {
mListener = listener;
- }
- if (mListener != null) {
- onFeatureReady();
+ if (mListener != null) {
+ onFeatureReady();
+ }
}
}
diff --git a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
index bcad554..a1bea4d 100644
--- a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
+++ b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
@@ -21,7 +21,6 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
-import android.content.res.Resources;
import android.os.RemoteException;
import android.provider.Settings;
import android.telephony.TelephonyManager;
@@ -145,6 +144,18 @@
telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) ==
TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
+ // add hiddenUntilInstalled flag for carrier apps and associated apps
+ packageManager.setSystemAppHiddenUntilInstalled(packageName, true);
+ List<ApplicationInfo> associatedAppList = associatedApps.get(packageName);
+ if (associatedAppList != null) {
+ for (ApplicationInfo associatedApp : associatedAppList) {
+ packageManager.setSystemAppHiddenUntilInstalled(
+ associatedApp.packageName,
+ true
+ );
+ }
+ }
+
if (hasPrivileges) {
// Only update enabled state for the app on /system. Once it has been
// updated we shouldn't touch it.
@@ -152,9 +163,14 @@
&& (ai.enabledSetting ==
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
|| ai.enabledSetting ==
- PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) {
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
+ || (ai.flags & ApplicationInfo.FLAG_INSTALLED) == 0)) {
Slog.i(TAG, "Update state(" + packageName + "): ENABLED for user "
+ userId);
+ packageManager.setSystemAppInstallState(
+ packageName,
+ true /*installed*/,
+ userId);
packageManager.setApplicationEnabledSetting(
packageName,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
@@ -164,15 +180,20 @@
}
// Also enable any associated apps for this carrier app.
- List<ApplicationInfo> associatedAppList = associatedApps.get(packageName);
if (associatedAppList != null) {
for (ApplicationInfo associatedApp : associatedAppList) {
if (associatedApp.enabledSetting ==
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
|| associatedApp.enabledSetting ==
- PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
+ || (associatedApp.flags
+ & ApplicationInfo.FLAG_INSTALLED) == 0) {
Slog.i(TAG, "Update associated state(" + associatedApp.packageName
+ "): ENABLED for user " + userId);
+ packageManager.setSystemAppInstallState(
+ associatedApp.packageName,
+ true /*installed*/,
+ userId);
packageManager.setApplicationEnabledSetting(
associatedApp.packageName,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
@@ -190,36 +211,33 @@
// updated we shouldn't touch it.
if (!ai.isUpdatedSystemApp()
&& ai.enabledSetting ==
- PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
+ PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
+ && (ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
Slog.i(TAG, "Update state(" + packageName
+ "): DISABLED_UNTIL_USED for user " + userId);
- packageManager.setApplicationEnabledSetting(
+ packageManager.setSystemAppInstallState(
packageName,
- PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED,
- 0,
- userId,
- callingPackage);
+ false /*installed*/,
+ userId);
}
// Also disable any associated apps for this carrier app if this is the first
// run. We avoid doing this a second time because it is brittle to rely on the
// distinction between "default" and "enabled".
if (!hasRunOnce) {
- List<ApplicationInfo> associatedAppList = associatedApps.get(packageName);
if (associatedAppList != null) {
for (ApplicationInfo associatedApp : associatedAppList) {
if (associatedApp.enabledSetting
- == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
+ == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
+ && (associatedApp.flags
+ & ApplicationInfo.FLAG_INSTALLED) != 0) {
Slog.i(TAG,
"Update associated state(" + associatedApp.packageName
+ "): DISABLED_UNTIL_USED for user " + userId);
- packageManager.setApplicationEnabledSetting(
+ packageManager.setSystemAppInstallState(
associatedApp.packageName,
- PackageManager
- .COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED,
- 0,
- userId,
- callingPackage);
+ false /*installed*/,
+ userId);
}
}
}
@@ -357,7 +375,8 @@
String packageName) {
try {
ApplicationInfo ai = packageManager.getApplicationInfo(packageName,
- PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, userId);
+ PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
+ | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS, userId);
if (ai != null && ai.isSystemApp()) {
return ai;
}
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index d999c13..e546917 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -63,34 +63,25 @@
public static final int EVENT_RADIO_AVAILABLE = BASE + 1;
public static final int EVENT_RECORDS_LOADED = BASE + 2;
public static final int EVENT_TRY_SETUP_DATA = BASE + 3;
- public static final int EVENT_DATA_STATE_CHANGED = BASE + 4;
- public static final int EVENT_POLL_PDP = BASE + 5;
public static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = BASE + 6;
public static final int EVENT_VOICE_CALL_STARTED = BASE + 7;
public static final int EVENT_VOICE_CALL_ENDED = BASE + 8;
public static final int EVENT_DATA_CONNECTION_DETACHED = BASE + 9;
- public static final int EVENT_LINK_STATE_CHANGED = BASE + 10;
public static final int EVENT_ROAMING_ON = BASE + 11;
public static final int EVENT_ROAMING_OFF = BASE + 12;
public static final int EVENT_ENABLE_NEW_APN = BASE + 13;
- public static final int EVENT_RESTORE_DEFAULT_APN = BASE + 14;
public static final int EVENT_DISCONNECT_DONE = BASE + 15;
public static final int EVENT_DATA_CONNECTION_ATTACHED = BASE + 16;
public static final int EVENT_DATA_STALL_ALARM = BASE + 17;
public static final int EVENT_DO_RECOVERY = BASE + 18;
public static final int EVENT_APN_CHANGED = BASE + 19;
- public static final int EVENT_CDMA_DATA_DETACHED = BASE + 20;
- public static final int EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED = BASE + 21;
public static final int EVENT_PS_RESTRICT_ENABLED = BASE + 22;
public static final int EVENT_PS_RESTRICT_DISABLED = BASE + 23;
public static final int EVENT_CLEAN_UP_CONNECTION = BASE + 24;
- public static final int EVENT_CDMA_OTA_PROVISION = BASE + 25;
public static final int EVENT_RESTART_RADIO = BASE + 26;
public static final int EVENT_SET_INTERNAL_DATA_ENABLE = BASE + 27;
- public static final int EVENT_RESET_DONE = BASE + 28;
public static final int EVENT_CLEAN_UP_ALL_CONNECTIONS = BASE + 29;
public static final int CMD_SET_USER_DATA_ENABLE = BASE + 30;
- public static final int CMD_SET_DEPENDENCY_MET = BASE + 31;
public static final int CMD_SET_POLICY_DATA_ENABLE = BASE + 32;
public static final int EVENT_ICC_CHANGED = BASE + 33;
public static final int EVENT_DISCONNECT_DC_RETRYING = BASE + 34;
diff --git a/telephony/java/com/android/internal/telephony/ISmsBaseImpl.java b/telephony/java/com/android/internal/telephony/ISmsBaseImpl.java
new file mode 100644
index 0000000..cc1d105
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ISmsBaseImpl.java
@@ -0,0 +1,199 @@
+/* Copyright (C) 2018 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.internal.telephony;
+
+import android.app.PendingIntent;
+import android.net.Uri;
+import java.lang.UnsupportedOperationException;
+import java.util.List;
+
+public class ISmsBaseImpl extends ISms.Stub {
+
+ @Override
+ public List<SmsRawData> getAllMessagesFromIccEfForSubscriber(int subId, String callingPkg) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean updateMessageOnIccEfForSubscriber(int subId, String callingPkg,
+ int messageIndex, int newStatus, byte[] pdu) throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean copyMessageToIccEfForSubscriber(int subId, String callingPkg, int status,
+ byte[] pdu, byte[] smsc) throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void sendDataForSubscriber(int subId, String callingPkg, String destAddr,
+ String scAddr, int destPort, byte[] data, PendingIntent sentIntent,
+ PendingIntent deliveryIntent) throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void sendDataForSubscriberWithSelfPermissions(int subId, String callingPkg,
+ String destAddr, String scAddr, int destPort, byte[] data,
+ PendingIntent sentIntent, PendingIntent deliveryIntent)
+ throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void sendTextForSubscriber(int subId, String callingPkg, String destAddr,
+ String scAddr, String text, PendingIntent sentIntent,
+ PendingIntent deliveryIntent, boolean persistMessageForNonDefaultSmsApp)
+ throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void sendTextForSubscriberWithSelfPermissions(int subId, String callingPkg,
+ String destAddr, String scAddr, String text, PendingIntent sentIntent,
+ PendingIntent deliveryIntent, boolean persistMessage)
+ throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void sendTextForSubscriberWithOptions(int subId, String callingPkg, String destAddr,
+ String scAddr, String text, PendingIntent sentIntent,
+ PendingIntent deliveryIntent, boolean persistMessageForNonDefaultSmsApp,
+ int priority, boolean expectMore, int validityPeriod)
+ throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void injectSmsPduForSubscriber(
+ int subId, byte[] pdu, String format, PendingIntent receivedIntent)
+ throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void sendMultipartTextForSubscriber(int subId, String callingPkg,
+ String destinationAddress, String scAddress,
+ List<String> parts, List<PendingIntent> sentIntents,
+ List<PendingIntent> deliveryIntents, boolean persistMessageForNonDefaultSmsApp)
+ throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void sendMultipartTextForSubscriberWithOptions(int subId, String callingPkg,
+ String destinationAddress, String scAddress,
+ List<String> parts, List<PendingIntent> sentIntents,
+ List<PendingIntent> deliveryIntents, boolean persistMessageForNonDefaultSmsApp,
+ int priority, boolean expectMore, int validityPeriod)
+ throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean enableCellBroadcastForSubscriber(int subId, int messageIdentifier, int ranType)
+ throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean disableCellBroadcastForSubscriber(int subId, int messageIdentifier, int ranType)
+ throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean enableCellBroadcastRangeForSubscriber(int subId, int startMessageId,
+ int endMessageId, int ranType) throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean disableCellBroadcastRangeForSubscriber(int subId, int startMessageId,
+ int endMessageId, int ranType) throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getPremiumSmsPermission(String packageName) throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getPremiumSmsPermissionForSubscriber(int subId, String packageName)
+ throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setPremiumSmsPermission(String packageName, int permission) throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setPremiumSmsPermissionForSubscriber(int subId, String packageName,
+ int permission) throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isImsSmsSupportedForSubscriber(int subId) throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isSmsSimPickActivityNeeded(int subId) throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getPreferredSmsSubscription() throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getImsSmsFormatForSubscriber(int subId) throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isSMSPromptEnabled() throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void sendStoredText(int subId, String callingPkg, Uri messageUri, String scAddress,
+ PendingIntent sentIntent, PendingIntent deliveryIntent)
+ throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void sendStoredMultipartText(int subId, String callingPkg, Uri messageUri,
+ String scAddress, List<PendingIntent> sentIntents,
+ List<PendingIntent> deliveryIntents) throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String createAppSpecificSmsToken(int subId, String callingPkg, PendingIntent intent)
+ throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 6ea8ccb..84a18b4 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -817,12 +817,6 @@
IImsConfig getImsConfig(int slotId, int feature);
/**
- * @return true if the IMS resolver is busy resolving a binding and should not be considered
- * available, false if the IMS resolver is idle.
- */
- boolean isResolvingImsBinding();
-
- /**
* @return true if the ImsService to bind to for the slot id specified was set, false otherwise.
*/
boolean setImsService(int slotId, boolean isCarrierImsService, String packageName);
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 2208580..dbf81d6 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -57,6 +57,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -95,6 +96,7 @@
import android.net.ConnectivityThread;
import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
+import android.net.InterfaceConfiguration;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
@@ -125,6 +127,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Process;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
@@ -132,6 +135,7 @@
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.test.mock.MockContentResolver;
+import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
@@ -145,6 +149,7 @@
import com.android.server.connectivity.DnsManager;
import com.android.server.connectivity.IpConnectivityMetrics;
import com.android.server.connectivity.MockableSystemProperties;
+import com.android.server.connectivity.Nat464Xlat;
import com.android.server.connectivity.NetworkAgentInfo;
import com.android.server.connectivity.NetworkMonitor;
import com.android.server.connectivity.Vpn;
@@ -161,10 +166,13 @@
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
+import java.net.Inet4Address;
import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
@@ -190,6 +198,7 @@
private static final int TIMEOUT_MS = 500;
private static final int TEST_LINGER_DELAY_MS = 120;
+ private static final String CLAT_PREFIX = "v4-";
private static final String MOBILE_IFNAME = "test_rmnet_data0";
private static final String WIFI_IFNAME = "test_wlan0";
@@ -950,6 +959,10 @@
return monitor;
}
+ public Nat464Xlat getNat464Xlat(MockNetworkAgent mna) {
+ return getNetworkAgentInfoForNetwork(mna.getNetwork()).clatd;
+ }
+
@Override
public MultinetworkPolicyTracker createMultinetworkPolicyTracker(
Context c, Handler h, Runnable r) {
@@ -4422,4 +4435,97 @@
mMockVpn.disconnect();
}
+
+ /**
+ * Make simulated InterfaceConfig for Nat464Xlat to query clat lower layer info.
+ */
+ private InterfaceConfiguration getClatInterfaceConfig(LinkAddress la) {
+ InterfaceConfiguration cfg = new InterfaceConfiguration();
+ cfg.setHardwareAddress("11:22:33:44:55:66");
+ cfg.setLinkAddress(la);
+ return cfg;
+ }
+
+ /**
+ * Make expected stack link properties, copied from Nat464Xlat.
+ */
+ private LinkProperties makeClatLinkProperties(LinkAddress la) {
+ LinkAddress clatAddress = la;
+ LinkProperties stacked = new LinkProperties();
+ stacked.setInterfaceName(CLAT_PREFIX + MOBILE_IFNAME);
+ RouteInfo ipv4Default = new RouteInfo(
+ new LinkAddress(Inet4Address.ANY, 0),
+ clatAddress.getAddress(), CLAT_PREFIX + MOBILE_IFNAME);
+ stacked.addRoute(ipv4Default);
+ stacked.addLinkAddress(clatAddress);
+ return stacked;
+ }
+
+ @Test
+ public void testStackedLinkProperties() throws UnknownHostException, RemoteException {
+ final LinkAddress myIpv4 = new LinkAddress("1.2.3.4/24");
+ final LinkAddress myIpv6 = new LinkAddress("2001:db8:1::1/64");
+ final NetworkRequest networkRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .build();
+ final TestNetworkCallback networkCallback = new TestNetworkCallback();
+ mCm.registerNetworkCallback(networkRequest, networkCallback);
+
+ // Prepare ipv6 only link properties and connect.
+ mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ final LinkProperties cellLp = new LinkProperties();
+ cellLp.setInterfaceName(MOBILE_IFNAME);
+ cellLp.addLinkAddress(myIpv6);
+ cellLp.addRoute(new RouteInfo((IpPrefix) null, myIpv6.getAddress(), MOBILE_IFNAME));
+ cellLp.addRoute(new RouteInfo(myIpv6, null, MOBILE_IFNAME));
+ reset(mNetworkManagementService);
+ when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME))
+ .thenReturn(getClatInterfaceConfig(myIpv4));
+
+ // Connect with ipv6 link properties, then expect clat setup ipv4 and update link
+ // properties properly.
+ mCellNetworkAgent.sendLinkProperties(cellLp);
+ mCellNetworkAgent.connect(true);
+ networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ verify(mNetworkManagementService, times(1)).startClatd(MOBILE_IFNAME);
+ Nat464Xlat clat = mService.getNat464Xlat(mCellNetworkAgent);
+
+ // Clat iface up, expect stack link updated.
+ clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true);
+ waitForIdle();
+ List<LinkProperties> stackedLps = mCm.getLinkProperties(mCellNetworkAgent.getNetwork())
+ .getStackedLinks();
+ assertEquals(makeClatLinkProperties(myIpv4), stackedLps.get(0));
+
+ // Change trivial linkproperties and see if stacked link is preserved.
+ cellLp.addDnsServer(InetAddress.getByName("8.8.8.8"));
+ mCellNetworkAgent.sendLinkProperties(cellLp);
+ waitForIdle();
+ networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+
+ List<LinkProperties> stackedLpsAfterChange =
+ mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getStackedLinks();
+ assertNotEquals(stackedLpsAfterChange, Collections.EMPTY_LIST);
+ assertEquals(makeClatLinkProperties(myIpv4), stackedLpsAfterChange.get(0));
+
+ // Add ipv4 address, expect stacked linkproperties be cleaned up
+ cellLp.addLinkAddress(myIpv4);
+ cellLp.addRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
+ mCellNetworkAgent.sendLinkProperties(cellLp);
+ waitForIdle();
+ networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ verify(mNetworkManagementService, times(1)).stopClatd(MOBILE_IFNAME);
+
+ // Clat iface removed, expect linkproperties revert to original one
+ clat.interfaceRemoved(CLAT_PREFIX + MOBILE_IFNAME);
+ waitForIdle();
+ networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ LinkProperties actualLpAfterIpv4 = mCm.getLinkProperties(mCellNetworkAgent.getNetwork());
+ assertEquals(cellLp, actualLpAfterIpv4);
+
+ // Clean up
+ mCellNetworkAgent.disconnect();
+ mCm.unregisterNetworkCallback(networkCallback);
+ }
}
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index 34ecde8..0d3b8e4 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -71,6 +71,7 @@
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
+import android.net.NetworkRequest;
import android.net.NetworkState;
import android.net.NetworkUtils;
import android.net.RouteInfo;
@@ -128,6 +129,10 @@
private static final String TEST_USB_IFNAME = "test_rndis0";
private static final String TEST_WLAN_IFNAME = "test_wlan0";
+ // Actual contents of the request don't matter for this test. The lack of
+ // any specific TRANSPORT_* is sufficient to identify this request.
+ private static final NetworkRequest mDefaultRequest = new NetworkRequest.Builder().build();
+
@Mock private ApplicationInfo mApplicationInfo;
@Mock private Context mContext;
@Mock private INetworkManagementService mNMService;
@@ -238,6 +243,11 @@
isTetheringSupportedCalls++;
return true;
}
+
+ @Override
+ public NetworkRequest getDefaultNetworkRequest() {
+ return mDefaultRequest;
+ }
}
private static NetworkState buildMobileUpstreamState(boolean withIPv4, boolean withIPv6,
@@ -305,6 +315,8 @@
.thenReturn(new String[0]);
when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
.thenReturn(new int[0]);
+ when(mResources.getBoolean(com.android.internal.R.bool.config_tether_upstream_automatic))
+ .thenReturn(false);
when(mNMService.listInterfaces())
.thenReturn(new String[] {
TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_USB_IFNAME});
@@ -458,6 +470,7 @@
}
private void prepareUsbTethering(NetworkState upstreamState) {
+ when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
.thenReturn(upstreamState);
@@ -519,7 +532,7 @@
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
verifyNoMoreInteractions(mWifiManager);
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_LOCAL_ONLY);
- verify(mUpstreamNetworkMonitor, times(1)).start();
+ verify(mUpstreamNetworkMonitor, times(1)).start(any(NetworkRequest.class));
// TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
assertTrue(1 <= mTetheringDependencies.isTetheringSupportedCalls);
@@ -656,6 +669,24 @@
}
@Test
+ public void configTetherUpstreamAutomaticIgnoresConfigTetherUpstreamTypes() throws Exception {
+ when(mResources.getBoolean(com.android.internal.R.bool.config_tether_upstream_automatic))
+ .thenReturn(true);
+ sendConfigurationChanged();
+
+ // Setup IPv6
+ final NetworkState upstreamState = buildMobileIPv6UpstreamState();
+ runUsbTethering(upstreamState);
+
+ // UpstreamNetworkMonitor should choose upstream automatically
+ // (in this specific case: choose the default network).
+ verify(mUpstreamNetworkMonitor, times(1)).getCurrentPreferredUpstream();
+ verify(mUpstreamNetworkMonitor, never()).selectPreferredUpstreamType(any());
+
+ verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(upstreamState.network);
+ }
+
+ @Test
public void workingLocalOnlyHotspotEnrichedApBroadcastWithIfaceChanged() throws Exception {
workingLocalOnlyHotspotEnrichedApBroadcast(true);
}
@@ -718,7 +749,7 @@
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED);
verifyNoMoreInteractions(mWifiManager);
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_TETHER);
- verify(mUpstreamNetworkMonitor, times(1)).start();
+ verify(mUpstreamNetworkMonitor, times(1)).start(any(NetworkRequest.class));
// In tethering mode, in the default configuration, an explicit request
// for a mobile network is also made.
verify(mUpstreamNetworkMonitor, times(1)).registerMobileNetworkRequest();
diff --git a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
index 9661dc2..3e21a2c 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
@@ -31,6 +31,7 @@
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@@ -73,6 +74,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
@@ -84,6 +86,10 @@
private static final boolean INCLUDES = true;
private static final boolean EXCLUDES = false;
+ // Actual contents of the request don't matter for this test. The lack of
+ // any specific TRANSPORT_* is sufficient to identify this request.
+ private static final NetworkRequest mDefaultRequest = new NetworkRequest.Builder().build();
+
@Mock private Context mContext;
@Mock private IConnectivityManager mCS;
@Mock private SharedLog mLog;
@@ -113,6 +119,13 @@
}
@Test
+ public void testStopWithoutStartIsNonFatal() {
+ mUNM.stop();
+ mUNM.stop();
+ mUNM.stop();
+ }
+
+ @Test
public void testDoesNothingBeforeStarted() {
assertTrue(mCM.hasNoCallbacks());
assertFalse(mUNM.mobileNetworkRequested());
@@ -127,7 +140,7 @@
public void testDefaultNetworkIsTracked() throws Exception {
assertEquals(0, mCM.trackingDefault.size());
- mUNM.start();
+ mUNM.start(mDefaultRequest);
assertEquals(1, mCM.trackingDefault.size());
mUNM.stop();
@@ -138,7 +151,7 @@
public void testListensForAllNetworks() throws Exception {
assertTrue(mCM.listening.isEmpty());
- mUNM.start();
+ mUNM.start(mDefaultRequest);
assertFalse(mCM.listening.isEmpty());
assertTrue(mCM.isListeningForAll());
@@ -148,9 +161,11 @@
@Test
public void testCallbacksRegistered() {
- mUNM.start();
- verify(mCM, times(1)).registerNetworkCallback(any(), any(), any());
- verify(mCM, times(1)).registerDefaultNetworkCallback(any(), any());
+ mUNM.start(mDefaultRequest);
+ verify(mCM, times(1)).registerNetworkCallback(
+ any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
+ verify(mCM, times(1)).requestNetwork(
+ eq(mDefaultRequest), any(NetworkCallback.class), any(Handler.class));
mUNM.stop();
verify(mCM, times(2)).unregisterNetworkCallback(any(NetworkCallback.class));
@@ -161,7 +176,7 @@
assertFalse(mUNM.mobileNetworkRequested());
assertEquals(0, mCM.requested.size());
- mUNM.start();
+ mUNM.start(mDefaultRequest);
assertFalse(mUNM.mobileNetworkRequested());
assertEquals(0, mCM.requested.size());
@@ -184,17 +199,17 @@
assertFalse(mUNM.mobileNetworkRequested());
assertEquals(0, mCM.requested.size());
- mUNM.start();
- verify(mCM, Mockito.times(1)).registerNetworkCallback(
+ mUNM.start(mDefaultRequest);
+ verify(mCM, times(1)).registerNetworkCallback(
any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
- verify(mCM, Mockito.times(1)).registerDefaultNetworkCallback(
- any(NetworkCallback.class), any(Handler.class));
+ verify(mCM, times(1)).requestNetwork(
+ eq(mDefaultRequest), any(NetworkCallback.class), any(Handler.class));
assertFalse(mUNM.mobileNetworkRequested());
assertEquals(0, mCM.requested.size());
mUNM.updateMobileRequiresDun(true);
mUNM.registerMobileNetworkRequest();
- verify(mCM, Mockito.times(1)).requestNetwork(
+ verify(mCM, times(1)).requestNetwork(
any(NetworkRequest.class), any(NetworkCallback.class), anyInt(), anyInt(),
any(Handler.class));
@@ -222,7 +237,7 @@
assertFalse(mUNM.mobileNetworkRequested());
assertEquals(0, mCM.requested.size());
- mUNM.start();
+ mUNM.start(mDefaultRequest);
assertFalse(mUNM.mobileNetworkRequested());
assertEquals(0, mCM.requested.size());
@@ -242,7 +257,7 @@
@Test
public void testUpdateMobileRequiresDun() throws Exception {
- mUNM.start();
+ mUNM.start(mDefaultRequest);
// Test going from no-DUN to DUN correctly re-registers callbacks.
mUNM.updateMobileRequiresDun(false);
@@ -270,7 +285,7 @@
final Collection<Integer> preferredTypes = new ArrayList<>();
preferredTypes.add(TYPE_WIFI);
- mUNM.start();
+ mUNM.start(mDefaultRequest);
// There are no networks, so there is nothing to select.
assertSatisfiesLegacyType(TYPE_NONE, mUNM.selectPreferredUpstreamType(preferredTypes));
@@ -334,8 +349,47 @@
}
@Test
+ public void testGetCurrentPreferredUpstream() throws Exception {
+ mUNM.start(mDefaultRequest);
+ mUNM.updateMobileRequiresDun(false);
+
+ // [0] Mobile connects, DUN not required -> mobile selected.
+ final TestNetworkAgent cellAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
+ cellAgent.fakeConnect();
+ mCM.makeDefaultNetwork(cellAgent);
+ assertEquals(cellAgent.networkId, mUNM.getCurrentPreferredUpstream().network);
+
+ // [1] WiFi connects but not validated/promoted to default -> mobile selected.
+ final TestNetworkAgent wifiAgent = new TestNetworkAgent(mCM, TRANSPORT_WIFI);
+ wifiAgent.fakeConnect();
+ assertEquals(cellAgent.networkId, mUNM.getCurrentPreferredUpstream().network);
+
+ // [2] WiFi validates and is promoted to the default network -> WiFi selected.
+ mCM.makeDefaultNetwork(wifiAgent);
+ assertEquals(wifiAgent.networkId, mUNM.getCurrentPreferredUpstream().network);
+
+ // [3] DUN required, no other changes -> WiFi still selected
+ mUNM.updateMobileRequiresDun(true);
+ assertEquals(wifiAgent.networkId, mUNM.getCurrentPreferredUpstream().network);
+
+ // [4] WiFi no longer validated, mobile becomes default, DUN required -> null selected.
+ mCM.makeDefaultNetwork(cellAgent);
+ assertEquals(null, mUNM.getCurrentPreferredUpstream());
+ // TODO: make sure that a DUN request has been filed. This is currently
+ // triggered by code over in Tethering, but once that has been moved
+ // into UNM we should test for this here.
+
+ // [5] DUN network arrives -> DUN selected
+ final TestNetworkAgent dunAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
+ dunAgent.networkCapabilities.addCapability(NET_CAPABILITY_DUN);
+ dunAgent.networkCapabilities.removeCapability(NET_CAPABILITY_INTERNET);
+ dunAgent.fakeConnect();
+ assertEquals(dunAgent.networkId, mUNM.getCurrentPreferredUpstream().network);
+ }
+
+ @Test
public void testLocalPrefixes() throws Exception {
- mUNM.start();
+ mUNM.start(mDefaultRequest);
// [0] Test minimum set of local prefixes.
Set<IpPrefix> local = mUNM.getLocalPrefixes();
@@ -345,7 +399,7 @@
// [1] Pretend Wi-Fi connects.
final TestNetworkAgent wifiAgent = new TestNetworkAgent(mCM, TRANSPORT_WIFI);
- final LinkProperties wifiLp = new LinkProperties();
+ final LinkProperties wifiLp = wifiAgent.linkProperties;
wifiLp.setInterfaceName("wlan0");
final String[] WIFI_ADDRS = {
"fe80::827a:bfff:fe6f:374d", "100.112.103.18",
@@ -358,7 +412,7 @@
wifiLp.addLinkAddress(new LinkAddress(addrStr + cidr));
}
wifiAgent.fakeConnect();
- wifiAgent.sendLinkProperties(wifiLp);
+ wifiAgent.sendLinkProperties();
local = mUNM.getLocalPrefixes();
assertPrefixSet(local, INCLUDES, alreadySeen);
@@ -372,7 +426,7 @@
// [2] Pretend mobile connects.
final TestNetworkAgent cellAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
- final LinkProperties cellLp = new LinkProperties();
+ final LinkProperties cellLp = cellAgent.linkProperties;
cellLp.setInterfaceName("rmnet_data0");
final String[] CELL_ADDRS = {
"10.102.211.48", "2001:db8:0:1:b50e:70d9:10c9:433d",
@@ -382,7 +436,7 @@
cellLp.addLinkAddress(new LinkAddress(addrStr + cidr));
}
cellAgent.fakeConnect();
- cellAgent.sendLinkProperties(cellLp);
+ cellAgent.sendLinkProperties();
local = mUNM.getLocalPrefixes();
assertPrefixSet(local, INCLUDES, alreadySeen);
@@ -394,17 +448,18 @@
// [3] Pretend DUN connects.
final TestNetworkAgent dunAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
dunAgent.networkCapabilities.addCapability(NET_CAPABILITY_DUN);
- final LinkProperties dunLp = new LinkProperties();
+ dunAgent.networkCapabilities.removeCapability(NET_CAPABILITY_INTERNET);
+ final LinkProperties dunLp = dunAgent.linkProperties;
dunLp.setInterfaceName("rmnet_data1");
final String[] DUN_ADDRS = {
"192.0.2.48", "2001:db8:1:2:b50e:70d9:10c9:433d",
};
for (String addrStr : DUN_ADDRS) {
final String cidr = addrStr.contains(":") ? "/64" : "/27";
- cellLp.addLinkAddress(new LinkAddress(addrStr + cidr));
+ dunLp.addLinkAddress(new LinkAddress(addrStr + cidr));
}
dunAgent.fakeConnect();
- dunAgent.sendLinkProperties(dunLp);
+ dunAgent.sendLinkProperties();
local = mUNM.getLocalPrefixes();
assertPrefixSet(local, INCLUDES, alreadySeen);
@@ -442,6 +497,7 @@
public static class TestConnectivityManager extends ConnectivityManager {
public Map<NetworkCallback, Handler> allCallbacks = new HashMap<>();
public Set<NetworkCallback> trackingDefault = new HashSet<>();
+ public TestNetworkAgent defaultNetwork = null;
public Map<NetworkCallback, NetworkRequest> listening = new HashMap<>();
public Map<NetworkCallback, NetworkRequest> requested = new HashMap<>();
public Map<NetworkCallback, Integer> legacyTypeMap = new HashMap<>();
@@ -483,12 +539,34 @@
int getNetworkId() { return ++mNetworkId; }
+ void makeDefaultNetwork(TestNetworkAgent agent) {
+ if (Objects.equals(defaultNetwork, agent)) return;
+
+ final TestNetworkAgent formerDefault = defaultNetwork;
+ defaultNetwork = agent;
+
+ for (NetworkCallback cb : trackingDefault) {
+ if (defaultNetwork != null) {
+ cb.onAvailable(defaultNetwork.networkId);
+ cb.onCapabilitiesChanged(
+ defaultNetwork.networkId, defaultNetwork.networkCapabilities);
+ cb.onLinkPropertiesChanged(
+ defaultNetwork.networkId, defaultNetwork.linkProperties);
+ }
+ }
+ }
+
@Override
public void requestNetwork(NetworkRequest req, NetworkCallback cb, Handler h) {
assertFalse(allCallbacks.containsKey(cb));
allCallbacks.put(cb, h);
- assertFalse(requested.containsKey(cb));
- requested.put(cb, req);
+ if (mDefaultRequest.equals(req)) {
+ assertFalse(trackingDefault.contains(cb));
+ trackingDefault.add(cb);
+ } else {
+ assertFalse(requested.containsKey(cb));
+ requested.put(cb, req);
+ }
}
@Override
@@ -524,10 +602,7 @@
@Override
public void registerDefaultNetworkCallback(NetworkCallback cb, Handler h) {
- assertFalse(allCallbacks.containsKey(cb));
- allCallbacks.put(cb, h);
- assertFalse(trackingDefault.contains(cb));
- trackingDefault.add(cb);
+ fail("Should never be called.");
}
@Override
@@ -561,6 +636,7 @@
public final Network networkId;
public final int transportType;
public final NetworkCapabilities networkCapabilities;
+ public final LinkProperties linkProperties;
public TestNetworkAgent(TestConnectivityManager cm, int transportType) {
this.cm = cm;
@@ -569,12 +645,14 @@
networkCapabilities = new NetworkCapabilities();
networkCapabilities.addTransportType(transportType);
networkCapabilities.addCapability(NET_CAPABILITY_INTERNET);
+ linkProperties = new LinkProperties();
}
public void fakeConnect() {
for (NetworkCallback cb : cm.listening.keySet()) {
cb.onAvailable(networkId);
cb.onCapabilitiesChanged(networkId, copy(networkCapabilities));
+ cb.onLinkPropertiesChanged(networkId, copy(linkProperties));
}
}
@@ -584,11 +662,16 @@
}
}
- public void sendLinkProperties(LinkProperties lp) {
+ public void sendLinkProperties() {
for (NetworkCallback cb : cm.listening.keySet()) {
- cb.onLinkPropertiesChanged(networkId, lp);
+ cb.onLinkPropertiesChanged(networkId, copy(linkProperties));
}
}
+
+ @Override
+ public String toString() {
+ return String.format("TestNetworkAgent: %s %s", networkId, networkCapabilities);
+ }
}
public static class TestStateMachine extends StateMachine {
@@ -618,6 +701,10 @@
return new NetworkCapabilities(nc);
}
+ static LinkProperties copy(LinkProperties lp) {
+ return new LinkProperties(lp);
+ }
+
static void assertPrefixSet(Set<IpPrefix> prefixes, boolean expectation, String... expected) {
final Set<String> expectedSet = new HashSet<>();
Collections.addAll(expectedSet, expected);
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index ef5912b..8719a23 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -208,6 +208,15 @@
}
};
+// A chunk of text in the XML string within a CDATA tags.
+class CdataSegmentNode : public SegmentNode {
+ public:
+
+ void Build(StringBuilder* builder) const override {
+ builder->AppendText(data, /* preserve_spaces */ true);
+ }
+};
+
// A tag that will be encoded into the final flattened string. Tags like <b> or <i>.
class SpanNode : public Node {
public:
@@ -244,6 +253,7 @@
std::vector<Node*> node_stack;
node_stack.push_back(&root);
+ bool cdata_block = false;
bool saw_span_node = false;
SegmentNode* first_segment = nullptr;
SegmentNode* last_segment = nullptr;
@@ -253,11 +263,15 @@
const xml::XmlPullParser::Event event = parser->event();
// First take care of any SegmentNodes that should be created.
- if (event == xml::XmlPullParser::Event::kStartElement ||
- event == xml::XmlPullParser::Event::kEndElement) {
+ if (event == xml::XmlPullParser::Event::kStartElement
+ || event == xml::XmlPullParser::Event::kEndElement
+ || event == xml::XmlPullParser::Event::kCdataStart
+ || event == xml::XmlPullParser::Event::kCdataEnd) {
if (!current_text.empty()) {
- std::unique_ptr<SegmentNode> segment_node = util::make_unique<SegmentNode>();
+ std::unique_ptr<SegmentNode> segment_node = (cdata_block)
+ ? util::make_unique<CdataSegmentNode>() : util::make_unique<SegmentNode>();
segment_node->data = std::move(current_text);
+
last_segment = node_stack.back()->AddChild(std::move(segment_node));
if (first_segment == nullptr) {
first_segment = last_segment;
@@ -333,6 +347,16 @@
}
} break;
+ case xml::XmlPullParser::Event::kCdataStart: {
+ cdata_block = true;
+ break;
+ }
+
+ case xml::XmlPullParser::Event::kCdataEnd: {
+ cdata_block = false;
+ break;
+ }
+
default:
// ignore.
break;
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 5711dc3..ee496d5 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -989,4 +989,40 @@
ASSERT_FALSE(TestParse(input));
}
+TEST_F(ResourceParserTest, ParseCData) {
+ std::string input = R"(
+ <string name="foo"><![CDATA[some text and ' apostrophe]]></string>)";
+
+ ASSERT_TRUE(TestParse(input));
+ String* output = test::GetValue<String>(&table_, "string/foo");
+ ASSERT_THAT(output, NotNull());
+ EXPECT_THAT(*output, StrValueEq("some text and ' apostrophe"));
+
+ // Double quotes should not change the state of whitespace processing
+ input = R"(<string name="foo2">Hello<![CDATA[ "</string>' ]]> World</string>)";
+ ASSERT_TRUE(TestParse(input));
+ output = test::GetValue<String>(&table_, "string/foo2");
+ ASSERT_THAT(output, NotNull());
+ EXPECT_THAT(*output, StrValueEq(std::string("Hello \"</string>' World").data()));
+
+ // Cdata blocks should not have their whitespace trimmed
+ input = R"(<string name="foo3"> <![CDATA[ text ]]> </string>)";
+ ASSERT_TRUE(TestParse(input));
+ output = test::GetValue<String>(&table_, "string/foo3");
+ ASSERT_THAT(output, NotNull());
+ EXPECT_THAT(*output, StrValueEq(std::string(" text ").data()));
+
+ input = R"(<string name="foo4"> <![CDATA[]]> </string>)";
+ ASSERT_TRUE(TestParse(input));
+ output = test::GetValue<String>(&table_, "string/foo4");
+ ASSERT_THAT(output, NotNull());
+ EXPECT_THAT(*output, StrValueEq(std::string("").data()));
+
+ input = R"(<string name="foo5"> <![CDATA[ ]]> </string>)";
+ ASSERT_TRUE(TestParse(input));
+ output = test::GetValue<String>(&table_, "string/foo5");
+ ASSERT_THAT(output, NotNull());
+ EXPECT_THAT(*output, StrValueEq(std::string(" ").data()));
+}
+
} // namespace aapt
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 560077c..c48765b 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -797,16 +797,20 @@
: preserve_spaces_(preserve_spaces), quote_(preserve_spaces) {
}
-StringBuilder& StringBuilder::AppendText(const std::string& text) {
+StringBuilder& StringBuilder::AppendText(const std::string& text, bool preserve_spaces) {
if (!error_.empty()) {
return *this;
}
+ // Enable preserving spaces if it is enabled for this append or the StringBuilder was constructed
+ // to preserve spaces
+ preserve_spaces = (preserve_spaces) ? preserve_spaces : preserve_spaces_;
+
const size_t previous_len = xml_string_.text.size();
Utf8Iterator iter(text);
while (iter.HasNext()) {
char32_t codepoint = iter.Next();
- if (!quote_ && iswspace(codepoint)) {
+ if (!preserve_spaces && !quote_ && iswspace(codepoint)) {
if (!last_codepoint_was_space_) {
// Emit a space if it's the first.
xml_string_.text += ' ';
@@ -827,7 +831,6 @@
case U't':
xml_string_.text += '\t';
break;
-
case U'n':
xml_string_.text += '\n';
break;
@@ -855,12 +858,12 @@
break;
}
}
- } else if (!preserve_spaces_ && codepoint == U'"') {
+ } else if (!preserve_spaces && codepoint == U'"') {
// Only toggle the quote state when we are not preserving spaces.
quote_ = !quote_;
- } else if (!quote_ && codepoint == U'\'') {
- // This should be escaped.
+ } else if (!preserve_spaces && !quote_ && codepoint == U'\'') {
+ // This should be escaped when we are not preserving spaces
error_ = StringPrintf("unescaped apostrophe in string\n\"%s\"", text.c_str());
return *this;
diff --git a/tools/aapt2/ResourceUtils.h b/tools/aapt2/ResourceUtils.h
index 7af2fe0..410ef28 100644
--- a/tools/aapt2/ResourceUtils.h
+++ b/tools/aapt2/ResourceUtils.h
@@ -267,8 +267,10 @@
// single quotations can be used without escaping them.
explicit StringBuilder(bool preserve_spaces = false);
- // Appends a chunk of text.
- StringBuilder& AppendText(const std::string& text);
+ // Appends a chunk of text. If preserve_spaces is true, whitespace removal is not performed, and
+ // single quotations can be used without escaping them for this append. Otherwise, the
+ // StringBuilder will behave as it was constructed.
+ StringBuilder& AppendText(const std::string& text, bool preserve_spaces = false);
// Starts a Span (tag) with the given name. The name is expected to be of the form:
// "tag_name;attr1=value;attr2=value;"
diff --git a/tools/aapt2/ResourceUtils_test.cpp b/tools/aapt2/ResourceUtils_test.cpp
index 11f3fa3..5ce4640 100644
--- a/tools/aapt2/ResourceUtils_test.cpp
+++ b/tools/aapt2/ResourceUtils_test.cpp
@@ -254,6 +254,29 @@
TEST(ResourceUtilsTest, StringBuilderPreserveSpaces) {
EXPECT_THAT(ResourceUtils::StringBuilder(true /*preserve_spaces*/).AppendText("\"").to_string(),
Eq("\""));
+
+ // Single quotes should be able to be used without escaping them when preserving spaces and the
+ // spaces should not be trimmed
+ EXPECT_THAT(ResourceUtils::StringBuilder()
+ .AppendText(" hey guys ")
+ .AppendText(" 'this is so cool' ", /* preserve_spaces */ true)
+ .AppendText(" wow ")
+ .to_string(),
+ Eq(" hey guys 'this is so cool' wow "));
+
+ // Reading a double quote while preserving spaces should not change the quote state
+ EXPECT_THAT(ResourceUtils::StringBuilder()
+ .AppendText(" hey guys ")
+ .AppendText(" \"this is so cool' ", /* preserve_spaces */ true)
+ .AppendText(" wow ")
+ .to_string(),
+ Eq(" hey guys \"this is so cool' wow "));
+ EXPECT_THAT(ResourceUtils::StringBuilder()
+ .AppendText(" hey guys\" ")
+ .AppendText(" \"this is so cool' ", /* preserve_spaces */ true)
+ .AppendText(" wow \" ")
+ .to_string(),
+ Eq(" hey guys \"this is so cool' wow "));
}
} // namespace aapt
diff --git a/tools/aapt2/xml/XmlPullParser.cpp b/tools/aapt2/xml/XmlPullParser.cpp
index 402e5a4..a023494 100644
--- a/tools/aapt2/xml/XmlPullParser.cpp
+++ b/tools/aapt2/xml/XmlPullParser.cpp
@@ -38,6 +38,7 @@
EndNamespaceHandler);
XML_SetCharacterDataHandler(parser_, CharacterDataHandler);
XML_SetCommentHandler(parser_, CommentDataHandler);
+ XML_SetCdataSectionHandler(parser_, StartCdataSectionHandler, EndCdataSectionHandler);
event_queue_.push(EventData{Event::kStartDocument, 0, depth_++});
}
@@ -287,6 +288,22 @@
parser->depth_, comment});
}
+void XMLCALL XmlPullParser::StartCdataSectionHandler(void* user_data) {
+ XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(user_data);
+
+ parser->event_queue_.push(EventData{Event::kCdataStart,
+ XML_GetCurrentLineNumber(parser->parser_),
+ parser->depth_ });
+}
+
+void XMLCALL XmlPullParser::EndCdataSectionHandler(void* user_data) {
+ XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(user_data);
+
+ parser->event_queue_.push(EventData{Event::kCdataEnd,
+ XML_GetCurrentLineNumber(parser->parser_),
+ parser->depth_ });
+}
+
Maybe<StringPiece> FindAttribute(const XmlPullParser* parser,
const StringPiece& name) {
auto iter = parser->FindAttribute("", name);
diff --git a/tools/aapt2/xml/XmlPullParser.h b/tools/aapt2/xml/XmlPullParser.h
index 63db66f..6ebaa28 100644
--- a/tools/aapt2/xml/XmlPullParser.h
+++ b/tools/aapt2/xml/XmlPullParser.h
@@ -52,6 +52,8 @@
kEndElement,
kText,
kComment,
+ kCdataStart,
+ kCdataEnd,
};
/**
@@ -159,6 +161,8 @@
static void XMLCALL EndElementHandler(void* user_data, const char* name);
static void XMLCALL EndNamespaceHandler(void* user_data, const char* prefix);
static void XMLCALL CommentDataHandler(void* user_data, const char* comment);
+ static void XMLCALL StartCdataSectionHandler(void* user_data);
+ static void XMLCALL EndCdataSectionHandler(void* user_data);
struct EventData {
Event event;
@@ -223,6 +227,10 @@
return out << "Text";
case XmlPullParser::Event::kComment:
return out << "Comment";
+ case XmlPullParser::Event::kCdataStart:
+ return out << "CdataStart";
+ case XmlPullParser::Event::kCdataEnd:
+ return out << "CdataEnd";
}
return out;
}
@@ -240,6 +248,8 @@
case Event::kText:
case Event::kComment:
case Event::kStartElement:
+ case Event::kCdataStart:
+ case Event::kCdataEnd:
return true;
default:
break;
diff --git a/tools/incident_section_gen/main.cpp b/tools/incident_section_gen/main.cpp
index 1f77719..639f980 100644
--- a/tools/incident_section_gen/main.cpp
+++ b/tools/incident_section_gen/main.cpp
@@ -110,9 +110,7 @@
N = descriptor->field_count();
for (int i=0; i<N; i++) {
const FieldDescriptor* field = descriptor->field(i);
- if (field->type() == FieldDescriptor::TYPE_MESSAGE) {
- sections[field->name()] = field;
- }
+ sections[field->name()] = field;
}
printf("IncidentSection const INCIDENT_SECTIONS[] = {\n");
@@ -404,7 +402,7 @@
for (int i=0; i<descriptor->field_count(); i++) {
const FieldDescriptor* field = descriptor->field(i);
- if (field->type() != FieldDescriptor::TYPE_MESSAGE) {
+ if (field->type() != FieldDescriptor::TYPE_MESSAGE && field->type() != FieldDescriptor::TYPE_STRING) {
continue;
}
const SectionFlags s = getSectionFlags(field);
@@ -456,13 +454,13 @@
const FieldDescriptor* field = fieldsInOrder[i];
const string fieldName = getFieldName(field);
const Destination fieldDest = getFieldDest(field);
- const string fieldMessageName = getMessageName(field->message_type(), fieldDest);
-
- skip[i] = true;
-
if (field->type() != FieldDescriptor::TYPE_MESSAGE) {
+ printPrivacy(fieldName, field, "NULL", fieldDest, "NULL");
continue;
}
+
+ skip[i] = true;
+ const string fieldMessageName = getMessageName(field->message_type(), fieldDest);
// generate privacy flags for each section.
if (generatePrivacyFlags(field->message_type(), fieldDest, variableNames, &parents)) {
printPrivacy(fieldName, field, fieldMessageName, fieldDest, "NULL");
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 66ccc6c..af44b7e 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -147,6 +147,8 @@
boolean setWifiApConfiguration(in WifiConfiguration wifiConfig, String packageName);
+ void notifyUserOfApBandConversion(String packageName);
+
Messenger getWifiServiceMessenger(String packageName);
void enableTdls(String remoteIPAddress, boolean enable);
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 25f35d0..6963ed0 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -2170,6 +2170,21 @@
}
/**
+ * Method that triggers a notification to the user about a conversion to their saved AP config.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void notifyUserOfApBandConversion() {
+ Log.d(TAG, "apBand was converted, notify the user");
+ try {
+ mService.notifyUserOfApBandConversion(mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Enable/Disable TDLS on a specific local route.
*
* <p>