Merge "Add helper method to override flag"
diff --git a/Android.bp b/Android.bp
index 43fb48a..80f1c37 100644
--- a/Android.bp
+++ b/Android.bp
@@ -65,3 +65,25 @@
optional_subdirs = [
"core/tests/utiltests/jni",
]
+
+java_library {
+ name: "hwbinder",
+ no_framework_libs: true,
+
+ srcs: [
+ "core/java/android/os/HidlSupport.java",
+ "core/java/android/annotation/NonNull.java",
+ "core/java/android/os/HwBinder.java",
+ "core/java/android/os/HwBlob.java",
+ "core/java/android/os/HwParcel.java",
+ "core/java/android/os/IHwBinder.java",
+ "core/java/android/os/IHwInterface.java",
+ "core/java/android/os/DeadObjectException.java",
+ "core/java/android/os/DeadSystemException.java",
+ "core/java/android/os/RemoteException.java",
+ "core/java/android/util/AndroidException.java",
+ ],
+
+ dxflags: ["--core-library"],
+ installable: false,
+}
diff --git a/Android.mk b/Android.mk
index aa7caa5..98e4299 100644
--- a/Android.mk
+++ b/Android.mk
@@ -552,6 +552,8 @@
wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl \
wifi/java/android/net/wifi/aware/IWifiAwareDiscoverySessionCallback.aidl \
wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \
+ wifi/java/android/net/wifi/rtt/IRttCallback.aidl \
+ wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl \
wifi/java/android/net/wifi/IWifiScanner.aidl \
wifi/java/android/net/wifi/IRttManager.aidl \
packages/services/PacProcessor/com/android/net/IProxyService.aidl \
@@ -650,32 +652,6 @@
framework_built := $(call java-lib-deps,framework)
-# HwBinder
-# =======================================================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
- core/java/android/os/HidlSupport.java \
- core/java/android/annotation/NonNull.java \
- core/java/android/os/HwBinder.java \
- core/java/android/os/HwBlob.java \
- core/java/android/os/HwParcel.java \
- core/java/android/os/IHwBinder.java \
- core/java/android/os/IHwInterface.java \
- core/java/android/os/DeadObjectException.java \
- core/java/android/os/DeadSystemException.java \
- core/java/android/os/RemoteException.java \
- core/java/android/util/AndroidException.java \
-
-LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core-oj core-libart
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE := hwbinder
-
-LOCAL_DX_FLAGS := --core-library
-LOCAL_UNINSTALLABLE_MODULE := true
-include $(BUILD_JAVA_LIBRARY)
-
# Copy AIDL files to be preprocessed and included in the SDK,
# specified relative to the root of the build tree.
# ============================================================
@@ -721,6 +697,8 @@
frameworks/base/wifi/java/android/net/wifi/p2p/WifiP2pGroup.aidl \
frameworks/base/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.aidl \
frameworks/base/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.aidl \
+ frameworks/base/wifi/java/android/net/wifi/rtt/RangingRequest.aidl \
+ frameworks/base/wifi/java/android/net/wifi/rtt/RangingResult.aidl \
frameworks/base/wifi/java/android/net/wifi/WpsInfo.aidl \
frameworks/base/wifi/java/android/net/wifi/ScanResult.aidl \
frameworks/base/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.aidl \
diff --git a/api/current.txt b/api/current.txt
index 25cac5c..f0aa1d3 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6449,6 +6449,7 @@
method public void uninstallAllUserCaCerts(android.content.ComponentName);
method public void uninstallCaCert(android.content.ComponentName, byte[]);
method public void wipeData(int);
+ method public void wipeDataWithReason(int, java.lang.CharSequence);
field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
field public static final java.lang.String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED = "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED";
field public static final java.lang.String ACTION_DEVICE_ADMIN_SERVICE = "android.app.action.DEVICE_ADMIN_SERVICE";
@@ -6683,6 +6684,7 @@
method public android.graphics.Matrix getTransformation();
method public int getVisibility();
method public java.lang.String getWebDomain();
+ method public java.lang.String getWebScheme();
method public int getWidth();
method public boolean isAccessibilityFocused();
method public boolean isActivated();
@@ -40690,8 +40692,13 @@
public class DownloadStateCallback {
ctor public DownloadStateCallback();
+ ctor public DownloadStateCallback(int);
+ method public final boolean isFilterFlagSet(int);
method public void onProgressUpdated(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo, int, int, int, int);
method public void onStateUpdated(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo, int);
+ field public static final int ALL_UPDATES = 0; // 0x0
+ field public static final int PROGRESS_UPDATES = 1; // 0x1
+ field public static final int STATE_UPDATES = 2; // 0x2
}
public final class FileInfo implements android.os.Parcelable {
@@ -40765,6 +40772,7 @@
public class ServiceInfo {
method public java.util.List<java.util.Locale> getLocales();
method public java.lang.CharSequence getNameForLocale(java.util.Locale);
+ method public java.util.Set<java.util.Locale> getNamedContentLocales();
method public java.lang.String getServiceClassName();
method public java.lang.String getServiceId();
method public java.util.Date getSessionEndTime();
@@ -52394,6 +52402,8 @@
field public static final int OP_CONST_CLASS = 28; // 0x1c
field public static final int OP_CONST_CLASS_JUMBO = 255; // 0xff
field public static final int OP_CONST_HIGH16 = 21; // 0x15
+ field public static final int OP_CONST_METHOD_HANDLE = 254; // 0xfe
+ field public static final int OP_CONST_METHOD_TYPE = 255; // 0xff
field public static final int OP_CONST_STRING = 26; // 0x1a
field public static final int OP_CONST_STRING_JUMBO = 27; // 0x1b
field public static final int OP_CONST_WIDE = 24; // 0x18
diff --git a/api/system-current.txt b/api/system-current.txt
index 82cdbaf..4e68265 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6683,6 +6683,7 @@
method public void uninstallAllUserCaCerts(android.content.ComponentName);
method public void uninstallCaCert(android.content.ComponentName, byte[]);
method public void wipeData(int);
+ method public void wipeDataWithReason(int, java.lang.CharSequence);
field public static final java.lang.String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_ALLOWED";
field public static final java.lang.String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
@@ -6933,6 +6934,7 @@
method public android.graphics.Matrix getTransformation();
method public int getVisibility();
method public java.lang.String getWebDomain();
+ method public java.lang.String getWebScheme();
method public int getWidth();
method public boolean isAccessibilityFocused();
method public boolean isActivated();
@@ -40890,17 +40892,22 @@
public final class Suggestion implements android.os.Parcelable {
method public int describeContents();
+ method public int getFlags();
+ method public android.graphics.drawable.Icon getIcon();
method public java.lang.String getId();
method public android.app.PendingIntent getPendingIntent();
method public java.lang.CharSequence getSummary();
method public java.lang.CharSequence getTitle();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.service.settings.suggestions.Suggestion> CREATOR;
+ field public static final int FLAG_HAS_BUTTON = 1; // 0x1
}
public static class Suggestion.Builder {
ctor public Suggestion.Builder(java.lang.String);
method public android.service.settings.suggestions.Suggestion build();
+ method public android.service.settings.suggestions.Suggestion.Builder setFlags(int);
+ method public android.service.settings.suggestions.Suggestion.Builder setIcon(android.graphics.drawable.Icon);
method public android.service.settings.suggestions.Suggestion.Builder setPendingIntent(android.app.PendingIntent);
method public android.service.settings.suggestions.Suggestion.Builder setSummary(java.lang.CharSequence);
method public android.service.settings.suggestions.Suggestion.Builder setTitle(java.lang.CharSequence);
@@ -44287,8 +44294,13 @@
public class DownloadStateCallback {
ctor public DownloadStateCallback();
+ ctor public DownloadStateCallback(int);
+ method public final boolean isFilterFlagSet(int);
method public void onProgressUpdated(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo, int, int, int, int);
method public void onStateUpdated(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo, int);
+ field public static final int ALL_UPDATES = 0; // 0x0
+ field public static final int PROGRESS_UPDATES = 1; // 0x1
+ field public static final int STATE_UPDATES = 2; // 0x2
}
public final class FileInfo implements android.os.Parcelable {
@@ -44371,6 +44383,7 @@
public class ServiceInfo {
method public java.util.List<java.util.Locale> getLocales();
method public java.lang.CharSequence getNameForLocale(java.util.Locale);
+ method public java.util.Set<java.util.Locale> getNamedContentLocales();
method public java.lang.String getServiceClassName();
method public java.lang.String getServiceId();
method public java.util.Date getSessionEndTime();
@@ -56457,6 +56470,8 @@
field public static final int OP_CONST_CLASS = 28; // 0x1c
field public static final int OP_CONST_CLASS_JUMBO = 255; // 0xff
field public static final int OP_CONST_HIGH16 = 21; // 0x15
+ field public static final int OP_CONST_METHOD_HANDLE = 254; // 0xfe
+ field public static final int OP_CONST_METHOD_TYPE = 255; // 0xff
field public static final int OP_CONST_STRING = 26; // 0x1a
field public static final int OP_CONST_STRING_JUMBO = 27; // 0x1b
field public static final int OP_CONST_WIDE = 24; // 0x18
diff --git a/api/test-current.txt b/api/test-current.txt
index 34b663b..435f3b4 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -6517,6 +6517,7 @@
method public void uninstallAllUserCaCerts(android.content.ComponentName);
method public void uninstallCaCert(android.content.ComponentName, byte[]);
method public void wipeData(int);
+ method public void wipeDataWithReason(int, java.lang.CharSequence);
field public static final java.lang.String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_ALLOWED";
field public static final java.lang.String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
@@ -6754,6 +6755,7 @@
method public android.graphics.Matrix getTransformation();
method public int getVisibility();
method public java.lang.String getWebDomain();
+ method public java.lang.String getWebScheme();
method public int getWidth();
method public boolean isAccessibilityFocused();
method public boolean isActivated();
@@ -41040,8 +41042,13 @@
public class DownloadStateCallback {
ctor public DownloadStateCallback();
+ ctor public DownloadStateCallback(int);
+ method public final boolean isFilterFlagSet(int);
method public void onProgressUpdated(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo, int, int, int, int);
method public void onStateUpdated(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo, int);
+ field public static final int ALL_UPDATES = 0; // 0x0
+ field public static final int PROGRESS_UPDATES = 1; // 0x1
+ field public static final int STATE_UPDATES = 2; // 0x2
}
public final class FileInfo implements android.os.Parcelable {
@@ -41115,6 +41122,7 @@
public class ServiceInfo {
method public java.util.List<java.util.Locale> getLocales();
method public java.lang.CharSequence getNameForLocale(java.util.Locale);
+ method public java.util.Set<java.util.Locale> getNamedContentLocales();
method public java.lang.String getServiceClassName();
method public java.lang.String getServiceId();
method public java.util.Date getSessionEndTime();
@@ -52965,6 +52973,8 @@
field public static final int OP_CONST_CLASS = 28; // 0x1c
field public static final int OP_CONST_CLASS_JUMBO = 255; // 0xff
field public static final int OP_CONST_HIGH16 = 21; // 0x15
+ field public static final int OP_CONST_METHOD_HANDLE = 254; // 0xfe
+ field public static final int OP_CONST_METHOD_TYPE = 255; // 0xff
field public static final int OP_CONST_STRING = 26; // 0x1a
field public static final int OP_CONST_STRING_JUMBO = 27; // 0x1b
field public static final int OP_CONST_WIDE = 24; // 0x18
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk
index 7e78d6c..b16188e 100644
--- a/cmds/bootanimation/Android.mk
+++ b/cmds/bootanimation/Android.mk
@@ -31,12 +31,13 @@
LOCAL_SRC_FILES += \
iot/iotbootanimation_main.cpp \
- iot/BootAction.cpp
+ iot/BootAction.cpp \
+ iot/BootParameters.cpp \
LOCAL_SHARED_LIBRARIES += \
libandroidthings \
libbase \
- libbinder
+ libbinder \
LOCAL_STATIC_LIBRARIES += cpufeatures
diff --git a/cmds/bootanimation/iot/BootAction.cpp b/cmds/bootanimation/iot/BootAction.cpp
index 665b4d9..fa79744 100644
--- a/cmds/bootanimation/iot/BootAction.cpp
+++ b/cmds/bootanimation/iot/BootAction.cpp
@@ -19,96 +19,20 @@
#define LOG_TAG "BootAction"
#include <dlfcn.h>
-#include <fcntl.h>
-#include <map>
-
-#include <android-base/file.h>
-#include <android-base/strings.h>
-#include <base/json/json_parser.h>
-#include <base/json/json_value_converter.h>
-#include <cpu-features.h>
#include <pio/peripheral_manager_client.h>
#include <utils/Log.h>
-using android::base::ReadFileToString;
-using android::base::RemoveFileIfExists;
-using android::base::Split;
-using android::base::Join;
-using android::base::StartsWith;
-using android::base::EndsWith;
-using base::JSONReader;
-using base::Value;
-
namespace android {
-// Brightness and volume are stored as integer strings in next_boot.json.
-// They are divided by this constant to produce the actual float values in
-// range [0.0, 1.0]. This constant must match its counterpart in
-// DeviceManager.
-constexpr const float kFloatScaleFactor = 1000.0f;
-
-constexpr const char* kNextBootFile = "/data/misc/bootanimation/next_boot.json";
-constexpr const char* kLastBootFile = "/data/misc/bootanimation/last_boot.json";
-
-bool loadParameters(BootAction::SavedBootParameters* parameters)
-{
- std::string contents;
- if (!ReadFileToString(kLastBootFile, &contents)) {
- if (errno != ENOENT)
- ALOGE("Unable to read from %s: %s", kLastBootFile, strerror(errno));
-
- return false;
- }
-
- std::unique_ptr<Value> json = JSONReader::Read(contents);
- if (json.get() == nullptr) return false;
-
- JSONValueConverter<BootAction::SavedBootParameters> converter;
- if (!converter.Convert(*(json.get()), parameters)) return false;
-
- return true;
-}
-
-void BootAction::SavedBootParameters::RegisterJSONConverter(
- JSONValueConverter<SavedBootParameters> *converter) {
- converter->RegisterIntField("brightness", &SavedBootParameters::brightness);
- converter->RegisterIntField("volume", &SavedBootParameters::volume);
- converter->RegisterRepeatedString("param_names",
- &SavedBootParameters::param_names);
- converter->RegisterRepeatedString("param_values",
- &SavedBootParameters::param_values);
-}
-
BootAction::~BootAction() {
if (mLibHandle != nullptr) {
dlclose(mLibHandle);
}
}
-void BootAction::swapBootConfigs() {
- // rename() will fail if next_boot.json doesn't exist, so delete
- // last_boot.json manually first.
- std::string err;
- if (!RemoveFileIfExists(kLastBootFile, &err))
- ALOGE("Unable to delete last boot file: %s", err.c_str());
-
- if (rename(kNextBootFile, kLastBootFile) && errno != ENOENT)
- ALOGE("Unable to swap boot files: %s", strerror(errno));
-
- int fd = open(kNextBootFile, O_CREAT, DEFFILEMODE);
- if (fd == -1) {
- ALOGE("Unable to create next boot file: %s", strerror(errno));
- } else {
- // Make next_boot.json writible to everyone so DeviceManagementService
- // can save parameters there.
- if (fchmod(fd, DEFFILEMODE))
- ALOGE("Unable to set next boot file permissions: %s", strerror(errno));
- close(fd);
- }
-}
-
-bool BootAction::init(const std::string& libraryPath) {
+bool BootAction::init(const std::string& libraryPath,
+ const std::vector<ABootActionParameter>& parameters) {
APeripheralManagerClient* client = nullptr;
ALOGD("Connecting to peripheralmanager");
// Wait for peripheral manager to come up.
@@ -122,27 +46,6 @@
ALOGD("Peripheralmanager is up.");
APeripheralManagerClient_delete(client);
- float brightness = -1.0f;
- float volume = -1.0f;
- std::vector<ABootActionParameter> parameters;
- SavedBootParameters saved_parameters;
-
- if (loadParameters(&saved_parameters)) {
- // TODO(b/65462981): Do something with brightness and volume?
- brightness = saved_parameters.brightness / kFloatScaleFactor;
- volume = saved_parameters.volume / kFloatScaleFactor;
-
- if (saved_parameters.param_names.size() == saved_parameters.param_values.size()) {
- for (size_t i = 0; i < saved_parameters.param_names.size(); i++) {
- parameters.push_back({
- .key = saved_parameters.param_names[i]->c_str(),
- .value = saved_parameters.param_values[i]->c_str()
- });
- }
- } else {
- ALOGW("Parameter names and values size mismatch");
- }
- }
ALOGI("Loading boot action %s", libraryPath.c_str());
mLibHandle = dlopen(libraryPath.c_str(), RTLD_NOW);
diff --git a/cmds/bootanimation/iot/BootAction.h b/cmds/bootanimation/iot/BootAction.h
index 3cd43be..5e2495f 100644
--- a/cmds/bootanimation/iot/BootAction.h
+++ b/cmds/bootanimation/iot/BootAction.h
@@ -17,38 +17,21 @@
#ifndef _BOOTANIMATION_BOOTACTION_H
#define _BOOTANIMATION_BOOTACTION_H
-#include <map>
#include <string>
+#include <vector>
-#include <base/json/json_value_converter.h>
#include <boot_action/boot_action.h> // libandroidthings native API.
#include <utils/RefBase.h>
-using base::JSONValueConverter;
-
namespace android {
class BootAction : public RefBase {
public:
- struct SavedBootParameters {
- int brightness;
- int volume;
- ScopedVector<std::string> param_names;
- ScopedVector<std::string> param_values;
- static void RegisterJSONConverter(
- JSONValueConverter<SavedBootParameters>* converter);
- };
-
~BootAction();
- // Rename next_boot.json to last_boot.json so that we don't repeat
- // parameters if there is a crash before the framework comes up.
- // TODO(b/65462981): Is this what we want to do? Should we swap in the
- // framework instead?
- static void swapBootConfigs();
-
// libraryPath is a fully qualified path to the target .so library.
- bool init(const std::string& libraryPath);
+ bool init(const std::string& libraryPath,
+ const std::vector<ABootActionParameter>& parameters);
// The animation is going to start playing partNumber for the playCount'th
// time, update the action as needed.
diff --git a/cmds/bootanimation/iot/BootParameters.cpp b/cmds/bootanimation/iot/BootParameters.cpp
new file mode 100644
index 0000000..da6ad0d
--- /dev/null
+++ b/cmds/bootanimation/iot/BootParameters.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BootParameters.h"
+
+#define LOG_TAG "BootParameters"
+
+#include <fcntl.h>
+
+#include <string>
+
+#include <android-base/file.h>
+#include <base/json/json_parser.h>
+#include <base/json/json_reader.h>
+#include <base/json/json_value_converter.h>
+#include <utils/Log.h>
+
+using android::base::RemoveFileIfExists;
+using android::base::ReadFileToString;
+using base::JSONReader;
+using base::JSONValueConverter;
+using base::Value;
+
+namespace android {
+
+namespace {
+
+// Brightness and volume are stored as integer strings in next_boot.json.
+// They are divided by this constant to produce the actual float values in
+// range [0.0, 1.0]. This constant must match its counterpart in
+// DeviceManager.
+constexpr const float kFloatScaleFactor = 1000.0f;
+
+constexpr const char* kNextBootFile = "/data/misc/bootanimation/next_boot.json";
+constexpr const char* kLastBootFile = "/data/misc/bootanimation/last_boot.json";
+
+void swapBootConfigs() {
+ // rename() will fail if next_boot.json doesn't exist, so delete
+ // last_boot.json manually first.
+ std::string err;
+ if (!RemoveFileIfExists(kLastBootFile, &err))
+ ALOGE("Unable to delete last boot file: %s", err.c_str());
+
+ if (rename(kNextBootFile, kLastBootFile) && errno != ENOENT)
+ ALOGE("Unable to swap boot files: %s", strerror(errno));
+
+ int fd = open(kNextBootFile, O_CREAT, DEFFILEMODE);
+ if (fd == -1) {
+ ALOGE("Unable to create next boot file: %s", strerror(errno));
+ } else {
+ // Make next_boot.json writable to everyone so DeviceManagementService
+ // can save saved_parameters there.
+ if (fchmod(fd, DEFFILEMODE))
+ ALOGE("Unable to set next boot file permissions: %s", strerror(errno));
+ close(fd);
+ }
+}
+
+} // namespace
+
+BootParameters::SavedBootParameters::SavedBootParameters()
+ : brightness(-kFloatScaleFactor), volume(-kFloatScaleFactor) {}
+
+void BootParameters::SavedBootParameters::RegisterJSONConverter(
+ JSONValueConverter<SavedBootParameters>* converter) {
+ converter->RegisterIntField("brightness", &SavedBootParameters::brightness);
+ converter->RegisterIntField("volume", &SavedBootParameters::volume);
+ converter->RegisterRepeatedString("param_names",
+ &SavedBootParameters::param_names);
+ converter->RegisterRepeatedString("param_values",
+ &SavedBootParameters::param_values);
+}
+
+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));
+
+ return;
+ }
+
+ std::unique_ptr<Value> json = JSONReader::Read(contents);
+ if (json.get() == nullptr) {
+ return;
+ }
+
+ JSONValueConverter<SavedBootParameters> converter;
+ if (converter.Convert(*(json.get()), &mRawParameters)) {
+ mBrightness = mRawParameters.brightness / kFloatScaleFactor;
+ mVolume = mRawParameters.volume / kFloatScaleFactor;
+
+ if (mRawParameters.param_names.size() == mRawParameters.param_values.size()) {
+ for (size_t i = 0; i < mRawParameters.param_names.size(); i++) {
+ mParameters.push_back({
+ .key = mRawParameters.param_names[i]->c_str(),
+ .value = mRawParameters.param_values[i]->c_str()
+ });
+ }
+ } else {
+ ALOGW("Parameter names and values size mismatch");
+ }
+ }
+}
+
+} // namespace android
diff --git a/cmds/bootanimation/iot/BootParameters.h b/cmds/bootanimation/iot/BootParameters.h
new file mode 100644
index 0000000..ff3b018
--- /dev/null
+++ b/cmds/bootanimation/iot/BootParameters.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _BOOTANIMATION_BOOT_PARAMETERS_H_
+#define _BOOTANIMATION_BOOT_PARAMETERS_H_
+
+#include <list>
+#include <vector>
+
+#include <base/json/json_value_converter.h>
+#include <boot_action/boot_action.h> // libandroidthings native API.
+
+namespace android {
+
+// Provides access to the parameters set by DeviceManager.reboot().
+class BootParameters {
+public:
+ // Constructor loads the parameters for this boot and swaps the param files
+ // to clear the parameters for next boot.
+ BootParameters();
+
+ // Returns true if volume/brightness were explicitly set on reboot.
+ bool hasVolume() const { return mVolume >= 0; }
+ bool hasBrightness() const { return mBrightness >= 0; }
+
+ // Returns volume/brightness in [0,1], or -1 if unset.
+ float getVolume() const { return mVolume; }
+ float getBrightness() const { return mBrightness; }
+
+ // Returns the additional boot parameters that were set on reboot.
+ const std::vector<ABootActionParameter>& getParameters() const { return mParameters; }
+
+private:
+ // Raw boot saved_parameters loaded from .json.
+ struct SavedBootParameters {
+ int brightness;
+ int volume;
+ ScopedVector<std::string> param_names;
+ ScopedVector<std::string> param_values;
+
+ SavedBootParameters();
+ static void RegisterJSONConverter(
+ ::base::JSONValueConverter<SavedBootParameters>* converter);
+ };
+
+ void loadParameters();
+
+ float mVolume = -1.f;
+ float mBrightness = -1.f;
+ std::vector<ABootActionParameter> mParameters;
+
+ // ABootActionParameter is just a raw pointer so we need to keep the
+ // original strings around to avoid losing them.
+ SavedBootParameters mRawParameters;
+};
+
+} // namespace android
+
+
+#endif // _BOOTANIMATION_BOOT_PARAMETERS_H_
diff --git a/cmds/bootanimation/iot/iotbootanimation_main.cpp b/cmds/bootanimation/iot/iotbootanimation_main.cpp
index 441a140..742f9c24 100644
--- a/cmds/bootanimation/iot/iotbootanimation_main.cpp
+++ b/cmds/bootanimation/iot/iotbootanimation_main.cpp
@@ -28,6 +28,7 @@
#include "BootAction.h"
#include "BootAnimationUtil.h"
+#include "BootParameters.h"
using namespace android;
using android::base::ReadFileToString;
@@ -37,7 +38,11 @@
namespace {
-class BootActionAnimationCallbacks : public android::BootAnimation::Callbacks {public:
+class BootActionAnimationCallbacks : public android::BootAnimation::Callbacks {
+public:
+ BootActionAnimationCallbacks(std::unique_ptr<BootParameters> bootParameters)
+ : mBootParameters(std::move(bootParameters)) {}
+
void init(const Vector<Animation::Part>&) override {
std::string library_path("/oem/lib/");
@@ -51,7 +56,7 @@
library_path += property;
mBootAction = new BootAction();
- if (!mBootAction->init(library_path)) {
+ if (!mBootAction->init(library_path, mBootParameters->getParameters())) {
mBootAction = NULL;
}
};
@@ -86,6 +91,7 @@
};
private:
+ std::unique_ptr<BootParameters> mBootParameters;
sp<BootAction> mBootAction = nullptr;
};
@@ -94,9 +100,8 @@
int main() {
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
- // TODO(b/65462981): Should we set brightness/volume here in case the boot
- // animation is disabled?
- BootAction::swapBootConfigs();
+ // Clear our params for next boot no matter what.
+ std::unique_ptr<BootParameters> bootParameters(new BootParameters());
if (bootAnimationDisabled()) {
ALOGI("boot animation disabled");
@@ -108,7 +113,8 @@
sp<ProcessState> proc(ProcessState::self());
ProcessState::self()->startThreadPool();
- sp<BootAnimation> boot = new BootAnimation(new BootActionAnimationCallbacks());
+ sp<BootAnimation> boot = new BootAnimation(
+ new BootActionAnimationCallbacks(std::move(bootParameters)));
IPCThreadState::self()->joinThreadPool();
return 0;
diff --git a/cmds/incidentd/Android.mk b/cmds/incidentd/Android.mk
index 830bf9e..cb5fd02 100644
--- a/cmds/incidentd/Android.mk
+++ b/cmds/incidentd/Android.mk
@@ -23,7 +23,7 @@
LOCAL_MODULE := incidentd
LOCAL_SRC_FILES := \
- src/EncodedBuffer.cpp \
+ src/PrivacyBuffer.cpp \
src/FdBuffer.cpp \
src/IncidentService.cpp \
src/Privacy.cpp \
@@ -31,7 +31,6 @@
src/Section.cpp \
src/io_util.cpp \
src/main.cpp \
- src/protobuf.cpp \
src/report_directory.cpp
LOCAL_CFLAGS += \
@@ -54,6 +53,7 @@
libcutils \
libincident \
liblog \
+ libprotoutil \
libselinux \
libservices \
libutils
@@ -93,16 +93,15 @@
LOCAL_C_INCLUDES += $(LOCAL_PATH)/src
LOCAL_SRC_FILES := \
- src/EncodedBuffer.cpp \
+ src/PrivacyBuffer.cpp \
src/FdBuffer.cpp \
src/Privacy.cpp \
src/Reporter.cpp \
src/Section.cpp \
src/io_util.cpp \
- src/protobuf.cpp \
src/report_directory.cpp \
tests/section_list.cpp \
- tests/EncodedBuffer_test.cpp \
+ tests/PrivacyBuffer_test.cpp \
tests/FdBuffer_test.cpp \
tests/Reporter_test.cpp \
tests/Section_test.cpp \
@@ -116,6 +115,7 @@
libcutils \
libincident \
liblog \
+ libprotoutil \
libselinux \
libservices \
libutils \
diff --git a/cmds/incidentd/src/EncodedBuffer.cpp b/cmds/incidentd/src/EncodedBuffer.cpp
deleted file mode 100644
index e8f2c11..0000000
--- a/cmds/incidentd/src/EncodedBuffer.cpp
+++ /dev/null
@@ -1,195 +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.
- */
-
-#include "EncodedBuffer.h"
-#include "io_util.h"
-#include "protobuf.h"
-
-#include <deque>
-
-const size_t BUFFER_SIZE = 4 * 1024; // 4 KB
-
-/**
- * Read varint from iterator, the iterator will point to next available byte.
- * Return the number of bytes of the varint.
- */
-static uint32_t
-read_raw_varint(FdBuffer::iterator* it)
-{
- uint32_t val = 0;
- int i = 0;
- bool hasNext = true;
- while (hasNext) {
- hasNext = ((**it & 0x80) != 0);
- val += (**it & 0x7F) << (7*i);
- (*it)++;
- i++;
- }
- return val;
-}
-
-/**
- * Write the field to buf based on the wire type, iterator will point to next field.
- * If skip is set to true, no data will be written to buf. Return number of bytes written.
- */
-static size_t
-write_field_or_skip(FdBuffer::iterator* iter, vector<uint8_t>* buf, uint8_t wireType, bool skip)
-{
- FdBuffer::iterator snapshot = iter->snapshot();
- size_t bytesToWrite = 0;
- uint32_t varint = 0;
- switch (wireType) {
- case WIRE_TYPE_VARINT:
- varint = read_raw_varint(iter);
- if(!skip) return write_raw_varint(buf, varint);
- break;
- case WIRE_TYPE_FIXED64:
- bytesToWrite = 8;
- break;
- case WIRE_TYPE_LENGTH_DELIMITED:
- bytesToWrite = read_raw_varint(iter);
- if(!skip) write_raw_varint(buf, bytesToWrite);
- break;
- case WIRE_TYPE_FIXED32:
- bytesToWrite = 4;
- break;
- }
- if (skip) {
- *iter += bytesToWrite;
- } else {
- for (size_t i=0; i<bytesToWrite; i++) {
- buf->push_back(**iter);
- (*iter)++;
- }
- }
- return skip ? 0 : *iter - snapshot;
-}
-
-/**
- * Strip next field based on its private policy and request spec, then stores data in buf.
- * Return NO_ERROR if succeeds, otherwise BAD_VALUE is returned to indicate bad data in FdBuffer.
- *
- * The iterator must point to the head of a protobuf formatted field for successful operation.
- * After exit with NO_ERROR, iterator points to the next protobuf field's head.
- */
-static status_t
-stripField(FdBuffer::iterator* iter, vector<uint8_t>* buf, const Privacy* parentPolicy, const PrivacySpec& spec)
-{
- if (iter->outOfBound() || parentPolicy == NULL) return BAD_VALUE;
-
- uint32_t varint = read_raw_varint(iter);
- uint8_t wireType = read_wire_type(varint);
- uint32_t fieldId = read_field_id(varint);
- const Privacy* policy = parentPolicy->lookup(fieldId);
-
- if (policy == NULL || !policy->IsMessageType() || !policy->HasChildren()) {
- bool skip = !spec.CheckPremission(policy);
- size_t amt = buf->size();
- if (!skip) amt += write_header(buf, fieldId, wireType);
- amt += write_field_or_skip(iter, buf, wireType, skip); // point to head of next field
- return buf->size() != amt ? BAD_VALUE : NO_ERROR;
- }
- // current field is message type and its sub-fields have extra privacy policies
- deque<vector<uint8_t>> q;
- uint32_t msgSize = read_raw_varint(iter);
- size_t finalSize = 0;
- FdBuffer::iterator start = iter->snapshot();
- while ((*iter - start) != (int)msgSize) {
- vector<uint8_t> v;
- status_t err = stripField(iter, &v, policy, spec);
- if (err != NO_ERROR) return err;
- if (v.empty()) continue;
- q.push_back(v);
- finalSize += v.size();
- }
-
- write_header(buf, fieldId, wireType);
- write_raw_varint(buf, finalSize);
- buf->reserve(finalSize); // reserve the size of the field
- while (!q.empty()) {
- vector<uint8_t> subField = q.front();
- for (vector<uint8_t>::iterator it = subField.begin(); it != subField.end(); it++) {
- buf->push_back(*it);
- }
- q.pop_front();
- }
- return NO_ERROR;
-}
-
-// ================================================================================
-EncodedBuffer::EncodedBuffer(const FdBuffer& buffer, const Privacy* policy)
- : mFdBuffer(buffer),
- mPolicy(policy),
- mBuffers(),
- mSize(0)
-{
-}
-
-EncodedBuffer::~EncodedBuffer()
-{
-}
-
-status_t
-EncodedBuffer::strip(const PrivacySpec& spec)
-{
- // optimization when no strip happens
- if (mPolicy == NULL || !mPolicy->HasChildren() || spec.RequireAll()) {
- if (spec.CheckPremission(mPolicy)) mSize = mFdBuffer.size();
- return NO_ERROR;
- }
-
- FdBuffer::iterator it = mFdBuffer.begin();
- vector<uint8_t> field;
- field.reserve(BUFFER_SIZE);
-
- while (it != mFdBuffer.end()) {
- status_t err = stripField(&it, &field, mPolicy, spec);
- if (err != NO_ERROR) return err;
- if (field.size() > BUFFER_SIZE) { // rotate to another chunk if buffer size exceeds
- mBuffers.push_back(field);
- mSize += field.size();
- field.clear();
- }
- }
- if (!field.empty()) {
- mBuffers.push_back(field);
- mSize += field.size();
- }
- return NO_ERROR;
-}
-
-void
-EncodedBuffer::clear()
-{
- mSize = 0;
- mBuffers.clear();
-}
-
-size_t
-EncodedBuffer::size() const { return mSize; }
-
-status_t
-EncodedBuffer::flush(int fd)
-{
- if (size() == mFdBuffer.size()) return mFdBuffer.flush(fd);
-
- for (vector<vector<uint8_t>>::iterator it = mBuffers.begin(); it != mBuffers.end(); it++) {
- status_t err = write_all(fd, it->data(), it->size());
- if (err != NO_ERROR) return err;
- }
- return NO_ERROR;
-}
-
diff --git a/cmds/incidentd/src/FdBuffer.cpp b/cmds/incidentd/src/FdBuffer.cpp
index bb399b5..b7633a4 100644
--- a/cmds/incidentd/src/FdBuffer.cpp
+++ b/cmds/incidentd/src/FdBuffer.cpp
@@ -17,7 +17,6 @@
#define LOG_TAG "incidentd"
#include "FdBuffer.h"
-#include "io_util.h"
#include <cutils/log.h>
#include <utils/SystemClock.h>
@@ -31,10 +30,9 @@
const ssize_t MAX_BUFFER_COUNT = 256; // 4 MB max
FdBuffer::FdBuffer()
- :mBuffers(),
+ :mBuffer(BUFFER_SIZE),
mStartTime(-1),
mFinishTime(-1),
- mCurrentWritten(-1),
mTimedOut(false),
mTruncated(false)
{
@@ -42,11 +40,6 @@
FdBuffer::~FdBuffer()
{
- const int N = mBuffers.size();
- for (int i=0; i<N; i++) {
- uint8_t* buf = mBuffers[i];
- free(buf);
- }
}
status_t
@@ -60,20 +53,12 @@
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
- uint8_t* buf = NULL;
while (true) {
- if (mCurrentWritten >= BUFFER_SIZE || mCurrentWritten < 0) {
- if (mBuffers.size() == MAX_BUFFER_COUNT) {
- mTruncated = true;
- break;
- }
- buf = (uint8_t*)malloc(BUFFER_SIZE);
- if (buf == NULL) {
- return NO_MEMORY;
- }
- mBuffers.push_back(buf);
- mCurrentWritten = 0;
+ if (mBuffer.size() >= MAX_BUFFER_COUNT * BUFFER_SIZE) {
+ mTruncated = true;
+ break;
}
+ if (mBuffer.writeBuffer() == NULL) return NO_MEMORY;
int64_t remainingTime = (mStartTime + timeout) - uptimeMillis();
if (remainingTime <= 0) {
@@ -91,7 +76,7 @@
if ((pfds.revents & POLLERR) != 0) {
return errno != 0 ? -errno : UNKNOWN_ERROR;
} else {
- ssize_t amt = ::read(fd, buf + mCurrentWritten, BUFFER_SIZE - mCurrentWritten);
+ ssize_t amt = ::read(fd, mBuffer.writeBuffer(), mBuffer.currentToWrite());
if (amt < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
continue;
@@ -101,11 +86,10 @@
} else if (amt == 0) {
break;
}
- mCurrentWritten += amt;
+ mBuffer.wp()->move(amt);
}
}
}
-
mFinishTime = uptimeMillis();
return NO_ERROR;
}
@@ -132,20 +116,12 @@
int rpos = 0, wpos = 0;
// This is the buffer used to store processed data
- uint8_t* buf = NULL;
while (true) {
- if (mCurrentWritten >= BUFFER_SIZE || mCurrentWritten < 0) {
- if (mBuffers.size() == MAX_BUFFER_COUNT) {
- mTruncated = true;
- break;
- }
- buf = (uint8_t*)malloc(BUFFER_SIZE);
- if (buf == NULL) {
- return NO_MEMORY;
- }
- mBuffers.push_back(buf);
- mCurrentWritten = 0;
+ if (mBuffer.size() >= MAX_BUFFER_COUNT * BUFFER_SIZE) {
+ mTruncated = true;
+ break;
}
+ if (mBuffer.writeBuffer() == NULL) return NO_MEMORY;
int64_t remainingTime = (mStartTime + timeoutMs) - uptimeMillis();
if (remainingTime <= 0) {
@@ -223,7 +199,7 @@
}
// read from parsing process
- ssize_t amt = ::read(fromFd, buf + mCurrentWritten, BUFFER_SIZE - mCurrentWritten);
+ ssize_t amt = ::read(fromFd, mBuffer.writeBuffer(), mBuffer.currentToWrite());
if (amt < 0) {
if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
return -errno;
@@ -231,7 +207,7 @@
} else if (amt == 0) {
break;
} else {
- mCurrentWritten += amt;
+ mBuffer.wp()->move(amt);
}
}
@@ -242,105 +218,11 @@
size_t
FdBuffer::size() const
{
- if (mBuffers.empty()) return 0;
- return ((mBuffers.size() - 1) * BUFFER_SIZE) + mCurrentWritten;
+ return mBuffer.size();
}
-status_t
-FdBuffer::flush(int fd) const
+EncodedBuffer::iterator
+FdBuffer::data() const
{
- size_t i=0;
- status_t err = NO_ERROR;
- for (i=0; i<mBuffers.size()-1; i++) {
- err = write_all(fd, mBuffers[i], BUFFER_SIZE);
- if (err != NO_ERROR) return err;
- }
- return write_all(fd, mBuffers[i], mCurrentWritten);
-}
-
-FdBuffer::iterator
-FdBuffer::begin() const
-{
- return iterator(*this, 0, 0);
-}
-
-FdBuffer::iterator
-FdBuffer::end() const
-{
- if (mBuffers.empty() || mCurrentWritten < 0) return begin();
- if (mCurrentWritten == BUFFER_SIZE)
- // FdBuffer doesn't allocate another buf since no more bytes to read.
- return FdBuffer::iterator(*this, mBuffers.size(), 0);
- return FdBuffer::iterator(*this, mBuffers.size() - 1, mCurrentWritten);
-}
-
-// ===============================================================================
-FdBuffer::iterator::iterator(const FdBuffer& buffer, ssize_t index, ssize_t offset)
- : mFdBuffer(buffer),
- mIndex(index),
- mOffset(offset)
-{
-}
-
-FdBuffer::iterator&
-FdBuffer::iterator::operator=(iterator& other) const { return other; }
-
-FdBuffer::iterator&
-FdBuffer::iterator::operator+(size_t offset)
-{
- size_t newOffset = mOffset + offset;
- while (newOffset >= BUFFER_SIZE) {
- mIndex++;
- newOffset -= BUFFER_SIZE;
- }
- mOffset = newOffset;
- return *this;
-}
-
-FdBuffer::iterator&
-FdBuffer::iterator::operator+=(size_t offset) { return *this + offset; }
-
-FdBuffer::iterator&
-FdBuffer::iterator::operator++() { return *this + 1; }
-
-FdBuffer::iterator
-FdBuffer::iterator::operator++(int) { return *this + 1; }
-
-bool
-FdBuffer::iterator::operator==(iterator other) const
-{
- return mIndex == other.mIndex && mOffset == other.mOffset;
-}
-
-bool
-FdBuffer::iterator::operator!=(iterator other) const { return !(*this == other); }
-
-int
-FdBuffer::iterator::operator-(iterator other) const
-{
- return (int)bytesRead() - (int)other.bytesRead();
-}
-
-FdBuffer::iterator::reference
-FdBuffer::iterator::operator*() const
-{
- return mFdBuffer.mBuffers[mIndex][mOffset];
-}
-
-FdBuffer::iterator
-FdBuffer::iterator::snapshot() const
-{
- return FdBuffer::iterator(mFdBuffer, mIndex, mOffset);
-}
-
-size_t
-FdBuffer::iterator::bytesRead() const
-{
- return mIndex * BUFFER_SIZE + mOffset;
-}
-
-bool
-FdBuffer::iterator::outOfBound() const
-{
- return bytesRead() > mFdBuffer.size();
+ return mBuffer.begin();
}
diff --git a/cmds/incidentd/src/FdBuffer.h b/cmds/incidentd/src/FdBuffer.h
index dfe39c6..8857ae7 100644
--- a/cmds/incidentd/src/FdBuffer.h
+++ b/cmds/incidentd/src/FdBuffer.h
@@ -17,11 +17,11 @@
#ifndef FD_BUFFER_H
#define FD_BUFFER_H
+#include <android/util/EncodedBuffer.h>
#include <utils/Errors.h>
-#include <vector>
-
using namespace android;
+using namespace android::util;
using namespace std;
/**
@@ -71,52 +71,19 @@
size_t size() const;
/**
- * Flush all the data to given file descriptor;
- */
- status_t flush(int fd) const;
-
- /**
* How long the read took in milliseconds.
*/
int64_t durationMs() const { return mFinishTime - mStartTime; }
/**
- * Read data stored in FdBuffer
+ * Reader API for data stored in FdBuffer
*/
- class iterator;
- friend class iterator;
- class iterator : public std::iterator<std::random_access_iterator_tag, uint8_t> {
- public:
- iterator(const FdBuffer& buffer, ssize_t index, ssize_t offset);
- iterator& operator=(iterator& other) const;
- iterator& operator+(size_t offset);
- iterator& operator+=(size_t offset);
- iterator& operator++();
- iterator operator++(int);
- bool operator==(iterator other) const;
- bool operator!=(iterator other) const;
- int operator-(iterator other) const;
- reference operator*() const;
-
- // return the snapshot of the current iterator
- iterator snapshot() const;
- // how many bytes are read
- size_t bytesRead() const;
- // random access could make the iterator out of bound
- bool outOfBound() const;
- private:
- const FdBuffer& mFdBuffer;
- size_t mIndex;
- size_t mOffset;
- };
- iterator begin() const;
- iterator end() const;
+ EncodedBuffer::iterator data() const;
private:
- vector<uint8_t*> mBuffers;
+ EncodedBuffer mBuffer;
int64_t mStartTime;
int64_t mFinishTime;
- ssize_t mCurrentWritten;
bool mTimedOut;
bool mTruncated;
};
diff --git a/cmds/incidentd/src/PrivacyBuffer.cpp b/cmds/incidentd/src/PrivacyBuffer.cpp
new file mode 100644
index 0000000..07a064cf
--- /dev/null
+++ b/cmds/incidentd/src/PrivacyBuffer.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+#include "PrivacyBuffer.h"
+#include "io_util.h"
+
+#include <android/util/protobuf.h>
+#include <deque>
+
+using namespace android::util;
+
+/**
+ * Write the field to buf based on the wire type, iterator will point to next field.
+ * If skip is set to true, no data will be written to buf. Return number of bytes written.
+ */
+static size_t
+write_field_or_skip(EncodedBuffer::iterator* iter, EncodedBuffer* buf, uint8_t wireType, bool skip)
+{
+ EncodedBuffer::Pointer snapshot = iter->rp()->copy();
+ size_t bytesToWrite = 0;
+ uint32_t varint = 0;
+ switch (wireType) {
+ case WIRE_TYPE_VARINT:
+ varint = iter->readRawVarint();
+ if(!skip) return buf->writeRawVarint(varint);
+ break;
+ case WIRE_TYPE_FIXED64:
+ bytesToWrite = 8;
+ break;
+ case WIRE_TYPE_LENGTH_DELIMITED:
+ bytesToWrite = iter->readRawVarint();
+ if(!skip) buf->writeRawVarint(bytesToWrite);
+ break;
+ case WIRE_TYPE_FIXED32:
+ bytesToWrite = 4;
+ break;
+ }
+ if (skip) {
+ iter->rp()->move(bytesToWrite);
+ } else {
+ for (size_t i=0; i<bytesToWrite; i++) {
+ *buf->writeBuffer() = iter->next();
+ buf->wp()->move();
+ }
+ }
+ return skip ? 0 : iter->rp()->pos() - snapshot.pos();
+}
+
+/**
+ * Strip next field based on its private policy and request spec, then stores data in buf.
+ * Return NO_ERROR if succeeds, otherwise BAD_VALUE is returned to indicate bad data in FdBuffer.
+ *
+ * The iterator must point to the head of a protobuf formatted field for successful operation.
+ * After exit with NO_ERROR, iterator points to the next protobuf field's head.
+ */
+static status_t
+stripField(EncodedBuffer::iterator* iter, EncodedBuffer* buf, const Privacy* parentPolicy, const PrivacySpec& spec)
+{
+ if (!iter->hasNext() || parentPolicy == NULL) return BAD_VALUE;
+ uint32_t varint = iter->readRawVarint();
+ uint8_t wireType = read_wire_type(varint);
+ uint32_t fieldId = read_field_id(varint);
+ const Privacy* policy = parentPolicy->lookup(fieldId);
+
+ if (policy == NULL || !policy->IsMessageType() || !policy->HasChildren()) {
+ bool skip = !spec.CheckPremission(policy);
+ size_t amt = buf->size();
+ if (!skip) amt += buf->writeHeader(fieldId, wireType);
+ amt += write_field_or_skip(iter, buf, wireType, skip); // point to head of next field
+ return buf->size() != amt ? BAD_VALUE : NO_ERROR;
+ }
+ // current field is message type and its sub-fields have extra privacy policies
+ deque<EncodedBuffer*> q;
+ uint32_t msgSize = iter->readRawVarint();
+ size_t finalSize = 0;
+ EncodedBuffer::Pointer start = iter->rp()->copy();
+ while (iter->rp()->pos() - start.pos() != msgSize) {
+ EncodedBuffer* v = new EncodedBuffer();
+ status_t err = stripField(iter, v, policy, spec);
+ if (err != NO_ERROR) return err;
+ if (v->size() == 0) continue;
+ q.push_back(v);
+ finalSize += v->size();
+ }
+
+ buf->writeHeader(fieldId, wireType);
+ buf->writeRawVarint(finalSize);
+ while (!q.empty()) {
+ EncodedBuffer* subField = q.front();
+ EncodedBuffer::iterator it = subField->begin();
+ while (it.hasNext()) {
+ *buf->writeBuffer() = it.next();
+ buf->wp()->move();
+ }
+ q.pop_front();
+ delete subField;
+ }
+ return NO_ERROR;
+}
+
+// ================================================================================
+PrivacyBuffer::PrivacyBuffer(const Privacy* policy, EncodedBuffer::iterator& data)
+ :mPolicy(policy),
+ mData(data),
+ mBuffer(0),
+ mSize(0)
+{
+}
+
+PrivacyBuffer::~PrivacyBuffer()
+{
+}
+
+status_t
+PrivacyBuffer::strip(const PrivacySpec& spec)
+{
+ // optimization when no strip happens
+ if (mPolicy == NULL || !mPolicy->HasChildren() || spec.RequireAll()) {
+ if (spec.CheckPremission(mPolicy)) mSize = mData.size();
+ return NO_ERROR;
+ }
+ while (mData.hasNext()) {
+ status_t err = stripField(&mData, &mBuffer, mPolicy, spec);
+ if (err != NO_ERROR) return err;
+ }
+ if (mData.bytesRead() != mData.size()) return BAD_VALUE;
+ mSize = mBuffer.size();
+ mData.rp()->rewind(); // rewind the read pointer back to beginning after the strip.
+ return NO_ERROR;
+}
+
+void
+PrivacyBuffer::clear()
+{
+ mSize = 0;
+ mBuffer.wp()->rewind();
+}
+
+size_t
+PrivacyBuffer::size() const { return mSize; }
+
+status_t
+PrivacyBuffer::flush(int fd)
+{
+ status_t err = NO_ERROR;
+ EncodedBuffer::iterator iter = size() == mData.size() ? mData : mBuffer.begin();
+ while (iter.readBuffer() != NULL) {
+ err = write_all(fd, iter.readBuffer(), iter.currentToRead());
+ iter.rp()->move(iter.currentToRead());
+ if (err != NO_ERROR) return err;
+ }
+ return NO_ERROR;
+}
diff --git a/cmds/incidentd/src/EncodedBuffer.h b/cmds/incidentd/src/PrivacyBuffer.h
similarity index 69%
rename from cmds/incidentd/src/EncodedBuffer.h
rename to cmds/incidentd/src/PrivacyBuffer.h
index ea8603a..720b38e 100644
--- a/cmds/incidentd/src/EncodedBuffer.h
+++ b/cmds/incidentd/src/PrivacyBuffer.h
@@ -14,25 +14,27 @@
* limitations under the License.
*/
-#ifndef ENCODED_BUFFER_H
-#define ENCODED_BUFFER_H
+#ifndef PRIVACY_BUFFER_H
+#define PRIVACY_BUFFER_H
-#include "FdBuffer.h"
#include "Privacy.h"
+#include <android/util/EncodedBuffer.h>
#include <stdint.h>
-#include <vector>
+#include <utils/Errors.h>
+
+using namespace android;
+using namespace android::util;
/**
- * EncodedBuffer is constructed from FdBuffer which holds original protobuf formatted data and
- * its privacy policy in its tagged proto message. The class strips PII-sensitive fields
- * based on the request and holds stripped data in its buffer for output.
+ * PrivacyBuffer holds the original protobuf data and strips PII-sensitive fields
+ * based on the request and holds stripped data in its own buffer for output.
*/
-class EncodedBuffer
+class PrivacyBuffer
{
public:
- EncodedBuffer(const FdBuffer& buffer, const Privacy* policy);
- ~EncodedBuffer();
+ PrivacyBuffer(const Privacy* policy, EncodedBuffer::iterator& data);
+ ~PrivacyBuffer();
/**
* Strip based on the request and hold data in its own buffer. Return NO_ERROR if strip succeeds.
@@ -55,10 +57,11 @@
status_t flush(int fd);
private:
- const FdBuffer& mFdBuffer;
const Privacy* mPolicy;
- vector<vector<uint8_t>> mBuffers;
+ EncodedBuffer::iterator& mData;
+
+ EncodedBuffer mBuffer;
size_t mSize;
};
-#endif // ENCODED_BUFFER_H
\ No newline at end of file
+#endif // PRIVACY_BUFFER_H
\ No newline at end of file
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 166fef0..892bcca 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -16,15 +16,15 @@
#define LOG_TAG "incidentd"
-#include "EncodedBuffer.h"
#include "FdBuffer.h"
#include "Privacy.h"
+#include "PrivacyBuffer.h"
#include "Section.h"
#include "io_util.h"
-#include "protobuf.h"
#include "section_list.h"
+#include <android/util/protobuf.h>
#include <private/android_filesystem_config.h>
#include <binder/IServiceManager.h>
#include <map>
@@ -32,8 +32,13 @@
#include <wait.h>
#include <unistd.h>
+using namespace android::util;
using namespace std;
+// special section ids
+const int FIELD_ID_INCIDENT_HEADER = 1;
+
+// incident section parameters
const int WAIT_MAX = 5;
const struct timespec WAIT_INTERVAL_NS = {0, 200 * 1000 * 1000};
const char* INCIDENT_HELPER = "/system/bin/incident_helper";
@@ -127,7 +132,8 @@
write_report_requests(const int id, const FdBuffer& buffer, ReportRequestSet* requests)
{
status_t err = -EBADF;
- EncodedBuffer encodedBuffer(buffer, get_privacy_of_section(id));
+ EncodedBuffer::iterator data = buffer.data();
+ PrivacyBuffer privacyBuffer(get_privacy_of_section(id), data);
int writeable = 0;
// The streaming ones, group requests by spec in order to save unnecessary strip operations
@@ -143,34 +149,34 @@
for (map<PrivacySpec, vector<sp<ReportRequest>>>::iterator mit = requestsBySpec.begin(); mit != requestsBySpec.end(); mit++) {
PrivacySpec spec = mit->first;
- err = encodedBuffer.strip(spec);
- if (err != NO_ERROR) return err; // it means the encodedBuffer data is corrupted.
- if (encodedBuffer.size() == 0) continue;
+ err = privacyBuffer.strip(spec);
+ if (err != NO_ERROR) return err; // it means the privacyBuffer data is corrupted.
+ if (privacyBuffer.size() == 0) continue;
for (vector<sp<ReportRequest>>::iterator it = mit->second.begin(); it != mit->second.end(); it++) {
sp<ReportRequest> request = *it;
- err = write_section_header(request->fd, id, encodedBuffer.size());
+ err = write_section_header(request->fd, id, privacyBuffer.size());
if (err != NO_ERROR) { request->err = err; continue; }
- err = encodedBuffer.flush(request->fd);
+ err = privacyBuffer.flush(request->fd);
if (err != NO_ERROR) { request->err = err; continue; }
writeable++;
- ALOGD("Section %d flushed %zu bytes to fd %d with spec %d", id, encodedBuffer.size(), request->fd, spec.dest);
+ ALOGD("Section %d flushed %zu bytes to fd %d with spec %d", id, privacyBuffer.size(), request->fd, spec.dest);
}
- encodedBuffer.clear();
+ privacyBuffer.clear();
}
// The dropbox file
if (requests->mainFd() >= 0) {
- err = encodedBuffer.strip(get_default_dropbox_spec());
+ err = privacyBuffer.strip(get_default_dropbox_spec());
if (err != NO_ERROR) return err; // the buffer data is corrupted.
- if (encodedBuffer.size() == 0) goto DONE;
+ if (privacyBuffer.size() == 0) goto DONE;
- err = write_section_header(requests->mainFd(), id, encodedBuffer.size());
+ err = write_section_header(requests->mainFd(), id, privacyBuffer.size());
if (err != NO_ERROR) { requests->setMainFd(-1); goto DONE; }
- err = encodedBuffer.flush(requests->mainFd());
+ err = privacyBuffer.flush(requests->mainFd());
if (err != NO_ERROR) { requests->setMainFd(-1); goto DONE; }
writeable++;
- ALOGD("Section %d flushed %zu bytes to dropbox %d", id, encodedBuffer.size(), requests->mainFd());
+ ALOGD("Section %d flushed %zu bytes to dropbox %d", id, privacyBuffer.size(), requests->mainFd());
}
DONE:
diff --git a/cmds/incidentd/tests/FdBuffer_test.cpp b/cmds/incidentd/tests/FdBuffer_test.cpp
index d1436b2..2afa778 100644
--- a/cmds/incidentd/tests/FdBuffer_test.cpp
+++ b/cmds/incidentd/tests/FdBuffer_test.cpp
@@ -49,12 +49,11 @@
void AssertBufferContent(const char* expected) {
int i=0;
- FdBuffer::iterator it = buffer.begin();
- while (expected[i] != '\0') {
- ASSERT_EQ(*it, expected[i++]);
- it++;
+ EncodedBuffer::iterator it = buffer.data();
+ while (it.hasNext()) {
+ ASSERT_EQ(it.next(), expected[i++]);
}
- ASSERT_EQ(it, buffer.end());
+ EXPECT_EQ(expected[i], '\0');
}
bool DoDataStream(int rFd, int wFd) {
@@ -92,20 +91,8 @@
}
TEST_F(FdBufferTest, IterateEmpty) {
- FdBuffer::iterator it = buffer.begin();
- EXPECT_EQ(it, buffer.end());
- it += 1;
- EXPECT_TRUE(it.outOfBound());
-}
-
-TEST_F(FdBufferTest, IteratorSnapshot) {
- FdBuffer::iterator it = buffer.begin();
- it += 4;
- FdBuffer::iterator snapshot = it.snapshot();
- it += 5;
- EXPECT_TRUE(snapshot != it);
- EXPECT_EQ(it - snapshot, 5);
- EXPECT_EQ(snapshot - it, -5);
+ EncodedBuffer::iterator it = buffer.data();
+ EXPECT_FALSE(it.hasNext());
}
TEST_F(FdBufferTest, ReadAndIterate) {
@@ -114,15 +101,15 @@
ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, READ_TIMEOUT));
int i=0;
- for (FdBuffer::iterator it = buffer.begin(); it != buffer.end(); ++it) {
- EXPECT_EQ(*it, (uint8_t)testdata[i++]);
+ EncodedBuffer::iterator it = buffer.data();
+ while (it.hasNext()) {
+ EXPECT_EQ(it.next(), (uint8_t)testdata[i++]);
}
- FdBuffer::iterator it = buffer.begin();
- it += buffer.size();
- EXPECT_EQ(it, buffer.end());
+ it.rp()->rewind();
+ it.rp()->move(buffer.size());
EXPECT_EQ(it.bytesRead(), testdata.size());
- EXPECT_FALSE(it.outOfBound());
+ EXPECT_FALSE(it.hasNext());
}
TEST_F(FdBufferTest, ReadTimeout) {
@@ -258,13 +245,15 @@
EXPECT_FALSE(buffer.timedOut());
EXPECT_TRUE(buffer.truncated());
wait(&pid);
- FdBuffer::iterator it = buffer.begin();
- it += fourMB;
+ EncodedBuffer::iterator it = buffer.data();
+ it.rp()->move(fourMB);
EXPECT_EQ(it.bytesRead(), fourMB);
- EXPECT_EQ(it, buffer.end());
- for (FdBuffer::iterator it = buffer.begin(); it != buffer.end(); it++) {
+ EXPECT_FALSE(it.hasNext());
+
+ it.rp()->rewind();
+ while (it.hasNext()) {
char c = 'A' + (it.bytesRead() % 64 / 8);
- ASSERT_TRUE(*it == c);
+ ASSERT_TRUE(it.next() == c);
}
}
}
diff --git a/cmds/incidentd/tests/EncodedBuffer_test.cpp b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
similarity index 77%
rename from cmds/incidentd/tests/EncodedBuffer_test.cpp
rename to cmds/incidentd/tests/PrivacyBuffer_test.cpp
index 37a938a..8f6e355 100644
--- a/cmds/incidentd/tests/EncodedBuffer_test.cpp
+++ b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
@@ -12,7 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "EncodedBuffer.h"
+#include "FdBuffer.h"
+#include "PrivacyBuffer.h"
#include <android-base/file.h>
#include <android-base/test_utils.h>
@@ -42,9 +43,10 @@
const string FIX32_FIELD_4 = "\x25\xff\xff\xff\xff"; // -1
const string MESSAGE_FIELD_5 = "\x2a\x10" + VARINT_FIELD_1 + STRING_FIELD_2;
-class EncodedBufferTest : public Test {
+
+class PrivacyBufferTest : public Test {
public:
- virtual ~EncodedBufferTest() {
+ virtual ~PrivacyBufferTest() {
// Delete in reverse order of construction, to be consistent with
// regular allocation/deallocation.
while (!privacies.empty()) {
@@ -60,9 +62,10 @@
void writeToFdBuffer(string str) {
ASSERT_TRUE(WriteStringToFile(str, tf.path, false));
ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, 10000));
+ ASSERT_EQ(str.size(), buffer.size());
}
- void assertBuffer(EncodedBuffer& buf, string expected) {
+ void assertBuffer(PrivacyBuffer& buf, string expected) {
ASSERT_EQ(buf.size(), expected.size());
CaptureStdout();
ASSERT_EQ(buf.flush(STDOUT_FILENO), NO_ERROR);
@@ -71,9 +74,10 @@
void assertStrip(uint8_t dest, string expected, Privacy* policy) {
PrivacySpec spec(dest);
- EncodedBuffer encodedBuf(buffer, policy);
- ASSERT_EQ(encodedBuf.strip(spec), NO_ERROR);
- assertBuffer(encodedBuf, expected);
+ EncodedBuffer::iterator bufData = buffer.data();
+ PrivacyBuffer privacyBuf(policy, bufData);
+ ASSERT_EQ(privacyBuf.strip(spec), NO_ERROR);
+ assertBuffer(privacyBuf, expected);
}
void assertStripByFields(uint8_t dest, string expected, int size, Privacy* privacy, ...) {
@@ -134,67 +138,67 @@
}
};
-TEST_F(EncodedBufferTest, NullFieldPolicy) {
+TEST_F(PrivacyBufferTest, NullFieldPolicy) {
writeToFdBuffer(STRING_FIELD_0);
assertStrip(EXPLICIT, STRING_FIELD_0, create_string_privacy(300, AUTOMATIC, NULL));
}
-TEST_F(EncodedBufferTest, StripSpecNotAllowed) {
+TEST_F(PrivacyBufferTest, StripSpecNotAllowed) {
writeToFdBuffer(STRING_FIELD_0);
assertStripByFields(AUTOMATIC, "", 1, create_privacy(0, STRING_TYPE, EXPLICIT));
}
-TEST_F(EncodedBufferTest, StripVarintField) {
+TEST_F(PrivacyBufferTest, StripVarintField) {
writeToFdBuffer(VARINT_FIELD_1);
assertStripByFields(EXPLICIT, "", 1, create_privacy(1, OTHER_TYPE, LOCAL));
}
-TEST_F(EncodedBufferTest, StripLengthDelimitedField_String) {
+TEST_F(PrivacyBufferTest, StripLengthDelimitedField_String) {
writeToFdBuffer(STRING_FIELD_2);
assertStripByFields(EXPLICIT, "", 1, create_privacy(2, STRING_TYPE, LOCAL));
}
-TEST_F(EncodedBufferTest, StripFixed64Field) {
+TEST_F(PrivacyBufferTest, StripFixed64Field) {
writeToFdBuffer(FIX64_FIELD_3);
assertStripByFields(EXPLICIT, "", 1, create_privacy(3, OTHER_TYPE, LOCAL));
}
-TEST_F(EncodedBufferTest, StripFixed32Field) {
+TEST_F(PrivacyBufferTest, StripFixed32Field) {
writeToFdBuffer(FIX32_FIELD_4);
assertStripByFields(EXPLICIT, "", 1, create_privacy(4, OTHER_TYPE, LOCAL));
}
-TEST_F(EncodedBufferTest, StripLengthDelimitedField_Message) {
+TEST_F(PrivacyBufferTest, StripLengthDelimitedField_Message) {
writeToFdBuffer(MESSAGE_FIELD_5);
assertStripByFields(EXPLICIT, "", 1, create_privacy(5, MESSAGE_TYPE, LOCAL));
}
-TEST_F(EncodedBufferTest, NoStripVarintField) {
+TEST_F(PrivacyBufferTest, NoStripVarintField) {
writeToFdBuffer(VARINT_FIELD_1);
assertStripByFields(EXPLICIT, VARINT_FIELD_1, 1, create_privacy(1, OTHER_TYPE, AUTOMATIC));
}
-TEST_F(EncodedBufferTest, NoStripLengthDelimitedField_String) {
+TEST_F(PrivacyBufferTest, NoStripLengthDelimitedField_String) {
writeToFdBuffer(STRING_FIELD_2);
assertStripByFields(EXPLICIT, STRING_FIELD_2, 1, create_privacy(2, STRING_TYPE, AUTOMATIC));
}
-TEST_F(EncodedBufferTest, NoStripFixed64Field) {
+TEST_F(PrivacyBufferTest, NoStripFixed64Field) {
writeToFdBuffer(FIX64_FIELD_3);
assertStripByFields(EXPLICIT, FIX64_FIELD_3, 1, create_privacy(3, OTHER_TYPE, AUTOMATIC));
}
-TEST_F(EncodedBufferTest, NoStripFixed32Field) {
+TEST_F(PrivacyBufferTest, NoStripFixed32Field) {
writeToFdBuffer(FIX32_FIELD_4);
assertStripByFields(EXPLICIT, FIX32_FIELD_4, 1, create_privacy(4, OTHER_TYPE, AUTOMATIC));
}
-TEST_F(EncodedBufferTest, NoStripLengthDelimitedField_Message) {
+TEST_F(PrivacyBufferTest, NoStripLengthDelimitedField_Message) {
writeToFdBuffer(MESSAGE_FIELD_5);
assertStripByFields(EXPLICIT, MESSAGE_FIELD_5, 1, create_privacy(5, MESSAGE_TYPE, AUTOMATIC));
}
-TEST_F(EncodedBufferTest, StripVarintAndString) {
+TEST_F(PrivacyBufferTest, StripVarintAndString) {
writeToFdBuffer(STRING_FIELD_0 + VARINT_FIELD_1 + STRING_FIELD_2
+ FIX64_FIELD_3 + FIX32_FIELD_4);
string expected = STRING_FIELD_0 + FIX64_FIELD_3 + FIX32_FIELD_4;
@@ -202,7 +206,7 @@
create_privacy(1, OTHER_TYPE, LOCAL), create_privacy(2, STRING_TYPE, LOCAL));
}
-TEST_F(EncodedBufferTest, StripVarintAndFixed64) {
+TEST_F(PrivacyBufferTest, StripVarintAndFixed64) {
writeToFdBuffer(STRING_FIELD_0 + VARINT_FIELD_1 + STRING_FIELD_2
+ FIX64_FIELD_3 + FIX32_FIELD_4);
string expected = STRING_FIELD_0 + STRING_FIELD_2 + FIX32_FIELD_4;
@@ -210,46 +214,49 @@
create_privacy(1, OTHER_TYPE, LOCAL), create_privacy(3, OTHER_TYPE, LOCAL));
}
-TEST_F(EncodedBufferTest, StripVarintInNestedMessage) {
+TEST_F(PrivacyBufferTest, StripVarintInNestedMessage) {
writeToFdBuffer(STRING_FIELD_0 + MESSAGE_FIELD_5);
Privacy* list[] = { create_privacy(1, OTHER_TYPE, LOCAL), NULL };
string expected = STRING_FIELD_0 + "\x2a\xd" + STRING_FIELD_2;
assertStripByFields(EXPLICIT, expected, 1, create_message_privacy(5, list));
}
-TEST_F(EncodedBufferTest, StripFix64AndVarintInNestedMessage) {
+TEST_F(PrivacyBufferTest, StripFix64AndVarintInNestedMessage) {
writeToFdBuffer(STRING_FIELD_0 + FIX64_FIELD_3 + MESSAGE_FIELD_5);
Privacy* list[] = { create_privacy(1, OTHER_TYPE, LOCAL), NULL };
string expected = STRING_FIELD_0 + "\x2a\xd" + STRING_FIELD_2;
assertStripByFields(EXPLICIT, expected, 2, create_privacy(3, OTHER_TYPE, LOCAL), create_message_privacy(5, list));
}
-TEST_F(EncodedBufferTest, ClearAndStrip) {
+TEST_F(PrivacyBufferTest, ClearAndStrip) {
string data = STRING_FIELD_0 + VARINT_FIELD_1;
writeToFdBuffer(data);
Privacy* list[] = { create_privacy(1, OTHER_TYPE, LOCAL), NULL };
- EncodedBuffer encodedBuf(buffer, create_message_privacy(300, list));
+ EncodedBuffer::iterator bufData = buffer.data();
+ PrivacyBuffer privacyBuf(create_message_privacy(300, list), bufData);
PrivacySpec spec1(EXPLICIT), spec2(LOCAL);
- ASSERT_EQ(encodedBuf.strip(spec1), NO_ERROR);
- assertBuffer(encodedBuf, STRING_FIELD_0);
- ASSERT_EQ(encodedBuf.strip(spec2), NO_ERROR);
- assertBuffer(encodedBuf, data);
+ ASSERT_EQ(privacyBuf.strip(spec1), NO_ERROR);
+ assertBuffer(privacyBuf, STRING_FIELD_0);
+ ASSERT_EQ(privacyBuf.strip(spec2), NO_ERROR);
+ assertBuffer(privacyBuf, data);
}
-TEST_F(EncodedBufferTest, BadDataInFdBuffer) {
+TEST_F(PrivacyBufferTest, BadDataInFdBuffer) {
writeToFdBuffer("iambaddata");
Privacy* list[] = { create_privacy(4, OTHER_TYPE, AUTOMATIC), NULL };
- EncodedBuffer encodedBuf(buffer, create_message_privacy(300, list));
+ EncodedBuffer::iterator bufData = buffer.data();
+ PrivacyBuffer privacyBuf(create_message_privacy(300, list), bufData);
PrivacySpec spec;
- ASSERT_EQ(encodedBuf.strip(spec), BAD_VALUE);
+ ASSERT_EQ(privacyBuf.strip(spec), BAD_VALUE);
}
-TEST_F(EncodedBufferTest, BadDataInNestedMessage) {
+TEST_F(PrivacyBufferTest, BadDataInNestedMessage) {
writeToFdBuffer(STRING_FIELD_0 + MESSAGE_FIELD_5 + "aoeoe");
Privacy* list[] = { create_privacy(1, OTHER_TYPE, LOCAL), NULL };
Privacy* field5[] = { create_message_privacy(5, list), NULL };
- EncodedBuffer encodedBuf(buffer, create_message_privacy(300, field5));
+ EncodedBuffer::iterator bufData = buffer.data();
+ PrivacyBuffer privacyBuf(create_message_privacy(300, field5), bufData);
PrivacySpec spec;
- ASSERT_EQ(encodedBuf.strip(spec), BAD_VALUE);
+ ASSERT_EQ(privacyBuf.strip(spec), BAD_VALUE);
}
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 7cf5246..56f9512 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -44,6 +44,7 @@
../../core/java/android/os/IStatsManager.aidl \
src/StatsService.cpp \
src/AnomalyMonitor.cpp \
+ src/StatsPuller.cpp \
src/LogEntryPrinter.cpp \
src/LogReader.cpp \
src/main.cpp \
@@ -54,6 +55,9 @@
src/statsd_config.proto \
src/DropboxReader.cpp \
src/matchers/LogEntryMatcherManager.cpp \
+ src/metrics/CountMetricProducer.cpp \
+ src/metrics/ConditionTracker.cpp \
+ src/metrics/MetricsManager.cpp \
LOCAL_CFLAGS += \
diff --git a/cmds/statsd/src/DropboxWriter.h b/cmds/statsd/src/DropboxWriter.h
index 6107685..d72f103 100644
--- a/cmds/statsd/src/DropboxWriter.h
+++ b/cmds/statsd/src/DropboxWriter.h
@@ -17,7 +17,8 @@
#ifndef DROPBOX_WRITER_H
#define DROPBOX_WRITER_H
-#include <frameworks/base/cmds/statsd/src/stats_log.pb.h>
+#include <utils/RefBase.h>
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
using std::string;
@@ -25,7 +26,7 @@
namespace os {
namespace statsd {
-class DropboxWriter {
+class DropboxWriter : public virtual RefBase {
public:
/* tag will be part of the file name, and used as the key to build the file index inside
DropBoxManagerService.
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 280f9af..117fb5e 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -16,52 +16,74 @@
#include <StatsLogProcessor.h>
+#include <cutils/log.h>
+#include <frameworks/base/cmds/statsd/src/stats_log.pb.h>
#include <log/log_event_list.h>
+#include <metrics/CountMetricProducer.h>
#include <parse_util.h>
#include <utils/Errors.h>
using namespace android;
+using std::make_unique;
+using std::unique_ptr;
+using std::vector;
namespace android {
namespace os {
namespace statsd {
StatsLogProcessor::StatsLogProcessor() : m_dropbox_writer("all-logs") {
- // Initialize the EventTagMap, which is how we know the names of the numeric event tags.
- // If this fails, we can't print well, but something will print.
- m_tags = android_openEventTagMap(NULL);
-
- // Printing format
- m_format = android_log_format_new();
- android_log_setPrintFormat(m_format, FORMAT_THREADTIME);
+ // hardcoded config
+ // this should be called from StatsService when it receives a statsd_config
+ UpdateConfig(0, buildFakeConfig());
}
StatsLogProcessor::~StatsLogProcessor() {
- if (m_tags != NULL) {
- android_closeEventTagMap(m_tags);
- }
- android_log_format_free(m_format);
}
+StatsdConfig StatsLogProcessor::buildFakeConfig() {
+ // HACK: Hard code a test metric for counting screen on events...
+ StatsdConfig config;
+ config.set_config_id(12345L);
+
+ CountMetric* metric = config.add_count_metric();
+ metric->set_metric_id(20150717L);
+ metric->set_what("SCREEN_IS_ON");
+ metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
+
+ LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
+ eventMatcher->set_name("SCREEN_IS_ON");
+
+ SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
+ simpleLogEntryMatcher->add_tag(2 /*SCREEN_STATE_CHANGE*/);
+ simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()
+ ->set_key(1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
+ simpleLogEntryMatcher->mutable_key_value_matcher(0)
+ ->set_eq_int(2/*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
+ return config;
+}
+
+// TODO: what if statsd service restarts? How do we know what logs are already processed before?
void StatsLogProcessor::OnLogEvent(const log_msg& msg) {
- status_t err;
- AndroidLogEntry entry;
- char buf[1024];
+ // TODO: Use EventMetric to filter the events we want to log.
+ EventMetricData eventMetricData = parse(msg);
+ m_dropbox_writer.addEventMetricData(eventMetricData);
- err = android_log_processBinaryLogBuffer(&(const_cast<log_msg*>(&msg)->entry_v1), &entry,
- m_tags, buf, sizeof(buf));
-
- // dump all statsd logs to dropbox for now.
- // TODO: Add filtering, aggregation, etc.
- if (err == NO_ERROR) {
- EventMetricData eventMetricData = parse(msg);
- m_dropbox_writer.addEventMetricData(eventMetricData);
+ // pass the event to metrics managers.
+ for (auto& pair : mMetricsManagers) {
+ pair.second->onLogEvent(msg);
}
}
-void StatsLogProcessor::UpdateConfig(const int config_source, StatsdConfig config) {
- m_configs[config_source] = config;
+void StatsLogProcessor::UpdateConfig(const int config_source, const StatsdConfig& config) {
+ auto it = mMetricsManagers.find(config_source);
+ if (it != mMetricsManagers.end()) {
+ it->second->finish();
+ }
+
ALOGD("Updated configuration for source %i", config_source);
+
+ mMetricsManagers.insert({config_source, std::make_unique<MetricsManager>(config)});
}
} // namespace statsd
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 4546d33..88c63fa 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -17,8 +17,13 @@
#define STATS_LOG_PROCESSOR_H
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "DropboxWriter.h"
+#include "LogReader.h"
+#include "metrics/MetricsManager.h"
#include "parse_util.h"
+#include <log/logprint.h>
+#include <stdio.h>
#include <unordered_map>
namespace android {
@@ -32,26 +37,15 @@
virtual void OnLogEvent(const log_msg& msg);
- virtual void UpdateConfig(const int config_source, StatsdConfig config);
+ void UpdateConfig(const int config_source, const StatsdConfig& config);
private:
- /**
- * Numeric to string tag name mapping.
- */
- EventTagMap* m_tags;
-
- /**
- * Pretty printing format.
- */
- AndroidLogFormat* m_format;
-
+ // TODO: use EventMetrics to log the events.
DropboxWriter m_dropbox_writer;
- /**
- * Configs that have been specified, keyed by the source. This allows us to override the config
- * from a source later.
- */
- std::unordered_map<int, StatsdConfig> m_configs;
+ std::unordered_map<int, std::unique_ptr<MetricsManager>> mMetricsManagers;
+
+ static StatsdConfig buildFakeConfig();
};
} // namespace statsd
diff --git a/cmds/statsd/src/StatsPuller.cpp b/cmds/statsd/src/StatsPuller.cpp
new file mode 100644
index 0000000..94e8361
--- /dev/null
+++ b/cmds/statsd/src/StatsPuller.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "StatsPuller"
+#define DEBUG true
+
+#include "StatsPuller.h"
+#include "StatsService.h"
+#include <android/os/IStatsCompanionService.h>
+#include <cutils/log.h>
+
+using namespace android;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+String16 StatsPuller::pull(int pullCode) {
+ if (DEBUG) ALOGD("Initiating pulling %d", pullCode);
+
+ switch (pullCode) {
+ // All stats_companion_service cases go here with fallthroughs
+ case PULL_CODE_KERNEL_WAKELOCKS: {
+ // TODO: Consider caching the statsCompanion service
+ sp <IStatsCompanionService>
+ statsCompanion = StatsService::getStatsCompanionService();
+ String16 returned_value("");
+ Status status = statsCompanion->pullData(pullCode, &returned_value);
+ if (DEBUG) ALOGD("Finished pulling the data");
+ if (!status.isOk()) {
+ ALOGW("error pulling data of type %d", pullCode);
+ }
+ return returned_value;
+ }
+
+ // case OTHER_TYPES: etc.
+
+ default: {
+ ALOGE("invalid pull code %d", pullCode);
+ return String16("");
+ }
+ }
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/StatsPuller.h b/cmds/statsd/src/StatsPuller.h
new file mode 100644
index 0000000..05343b5
--- /dev/null
+++ b/cmds/statsd/src/StatsPuller.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STATSD_STATSPULLER_H
+#define STATSD_STATSPULLER_H
+
+#include <utils/String16.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class StatsPuller {
+public:
+ // Enums of pulled data types (pullCodes)
+ // These values must be kept in sync with com/android/server/stats/StatsCompanionService.java.
+ // TODO: pull the constant from stats_events.proto instead
+ const static int PULL_CODE_KERNEL_WAKELOCKS = 20;
+
+ StatsPuller();
+ ~StatsPuller();
+
+ static String16 pull(int pullCode);
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+
+#endif //STATSD_STATSPULLER_H
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index a28f085..ae7d66b 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -177,6 +177,9 @@
if (DEBUG) ALOGD("StatsService::informPollAlarmFired succeeded");
// TODO: determine what services to poll and poll (or ask StatsCompanionService to poll) them.
+ String16 output = StatsPuller::pull(StatsPuller::PULL_CODE_KERNEL_WAKELOCKS);
+ // TODO: do something useful with the output instead of writing a string to screen.
+ ALOGD("%s", String8(output).string());
return Status::ok();
}
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index a956cbf..a16b115 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -19,12 +19,12 @@
#include "AnomalyMonitor.h"
#include "StatsLogProcessor.h"
+#include "StatsPuller.h"
#include <android/os/BnStatsManager.h>
#include <android/os/IStatsCompanionService.h>
#include <binder/IResultReceiver.h>
#include <binder/IShellCallback.h>
-#include <frameworks/base/cmds/statsd/src/statsd_config.pb.h>
#include <utils/Looper.h>
#include <deque>
@@ -67,19 +67,21 @@
/** Inform statsCompanion that statsd is ready. */
virtual void sayHiToStatsCompanion();
-private:
- sp<StatsLogProcessor> m_processor; // Reference to the processor for updating configs.
+ // TODO: Move this to a more logical file/class
+ // TODO: Should be private. Temporarily public for testing purposes only.
+ const sp<AnomalyMonitor> mAnomalyMonitor;
- const sp<AnomalyMonitor> mAnomalyMonitor; // TODO: Move this to a more logical file/class
+ /** Fetches and returns the StatsCompanionService. */
+ static sp<IStatsCompanionService> getStatsCompanionService();
+
+ private:
+ sp<StatsLogProcessor> m_processor; // Reference to the processor for updating configs.
status_t doPrintStatsLog(FILE* out, const Vector<String8>& args);
void printCmdHelp(FILE* out);
status_t doLoadConfig(FILE* in);
-
- /** Fetches the StatsCompanionService. */
- sp<IStatsCompanionService> getStatsCompanionService();
};
// --- StatsdDeathRecipient ---
diff --git a/cmds/statsd/src/matchers/LogEntryMatcherManager.cpp b/cmds/statsd/src/matchers/LogEntryMatcherManager.cpp
index bb0951c..ab7b2b1d 100644
--- a/cmds/statsd/src/matchers/LogEntryMatcherManager.cpp
+++ b/cmds/statsd/src/matchers/LogEntryMatcherManager.cpp
@@ -15,75 +15,147 @@
*/
#include "LogEntryMatcherManager.h"
+#include <cutils/log.h>
#include <log/event_tag_map.h>
+#include <log/log_event_list.h>
#include <log/logprint.h>
#include <utils/Errors.h>
-#include <cutils/log.h>
#include <unordered_map>
-#include <frameworks/base/cmds/statsd/src/statsd_config.pb.h>
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "parse_util.h"
-using std::unordered_map;
+using std::set;
using std::string;
+using std::unordered_map;
namespace android {
namespace os {
namespace statsd {
-bool LogEntryMatcherManager::matches(const LogEntryMatcher &matcher, const int tagId,
- const unordered_map<int, long> &intMap,
- const unordered_map<int, string> &strMap,
- const unordered_map<int, float> &floatMap,
- const unordered_map<int, bool> &boolMap) {
- if (matcher.has_combination()) { // Need to evaluate composite matching
+LogEventWrapper LogEntryMatcherManager::parseLogEvent(log_msg msg) {
+ LogEventWrapper wrapper;
+ wrapper.timestamp_ns = msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec;
+ wrapper.tagId = getTagId(msg);
+
+ // start iterating k,v pairs.
+ android_log_context context =
+ create_android_log_parser(const_cast<log_msg*>(&msg)->msg() + sizeof(uint32_t),
+ const_cast<log_msg*>(&msg)->len() - sizeof(uint32_t));
+ android_log_list_element elem;
+
+ if (context) {
+ memset(&elem, 0, sizeof(elem));
+ size_t index = 0;
+ int32_t key = -1;
+ do {
+ elem = android_log_read_next(context);
+ switch ((int)elem.type) {
+ case EVENT_TYPE_INT:
+ if (index % 2 == 0) {
+ key = elem.data.int32;
+ } else {
+ wrapper.intMap[key] = elem.data.int32;
+ }
+ index++;
+ break;
+ case EVENT_TYPE_FLOAT:
+ if (index % 2 == 1) {
+ wrapper.floatMap[key] = elem.data.float32;
+ }
+ index++;
+ break;
+ case EVENT_TYPE_STRING:
+ if (index % 2 == 1) {
+ wrapper.strMap[key] = elem.data.string;
+ }
+ index++;
+ break;
+ case EVENT_TYPE_LONG:
+ if (index % 2 == 1) {
+ wrapper.intMap[key] = elem.data.int64;
+ }
+ index++;
+ break;
+ case EVENT_TYPE_LIST:
+ break;
+ case EVENT_TYPE_LIST_STOP:
+ break;
+ case EVENT_TYPE_UNKNOWN:
+ break;
+ default:
+ elem.complete = true;
+ break;
+ }
+
+ if (elem.complete) {
+ break;
+ }
+ } while ((elem.type != EVENT_TYPE_UNKNOWN) && !elem.complete);
+
+ android_log_destroy(&context);
+ }
+
+ return wrapper;
+}
+
+bool LogEntryMatcherManager::matches(const LogEntryMatcher& matcher, const LogEventWrapper& event) {
+ const int tagId = event.tagId;
+ const unordered_map<int, long>& intMap = event.intMap;
+ const unordered_map<int, string>& strMap = event.strMap;
+ const unordered_map<int, float>& floatMap = event.floatMap;
+ const unordered_map<int, bool>& boolMap = event.boolMap;
+
+ if (matcher.has_combination()) { // Need to evaluate composite matching
switch (matcher.combination().operation()) {
case LogicalOperation::AND:
for (auto nestedMatcher : matcher.combination().matcher()) {
- if (!matches(nestedMatcher, tagId, intMap, strMap, floatMap, boolMap)) {
- return false; // return false if any nested matcher is false;
+ if (!matches(nestedMatcher, event)) {
+ return false; // return false if any nested matcher is false;
}
}
- return true; // Otherwise, return true.
+ return true; // Otherwise, return true.
case LogicalOperation::OR:
for (auto nestedMatcher : matcher.combination().matcher()) {
- if (matches(nestedMatcher, tagId, intMap, strMap, floatMap, boolMap)) {
- return true; // return true if any nested matcher is true;
+ if (matches(nestedMatcher, event)) {
+ return true; // return true if any nested matcher is true;
}
}
return false;
case LogicalOperation::NOT:
- return !matches(matcher.combination().matcher(0), tagId, intMap, strMap, floatMap,
- boolMap);
+ return !matches(matcher.combination().matcher(0), event);
// Case NAND is just inverting the return statement of AND
case LogicalOperation::NAND:
for (auto nestedMatcher : matcher.combination().matcher()) {
auto simple = nestedMatcher.simple_log_entry_matcher();
- if (!matches(nestedMatcher, tagId, intMap, strMap, floatMap, boolMap)) {
- return true; // return false if any nested matcher is false;
+ if (!matches(nestedMatcher, event)) {
+ return true; // return false if any nested matcher is false;
}
}
- return false; // Otherwise, return true.
+ return false; // Otherwise, return true.
case LogicalOperation::NOR:
for (auto nestedMatcher : matcher.combination().matcher()) {
- if (matches(nestedMatcher, tagId, intMap, strMap, floatMap, boolMap)) {
- return false; // return true if any nested matcher is true;
+ if (matches(nestedMatcher, event)) {
+ return false; // return true if any nested matcher is true;
}
}
return true;
}
return false;
} else {
- return matchesSimple(matcher.simple_log_entry_matcher(), tagId, intMap, strMap, floatMap,
- boolMap);
+ return matchesSimple(matcher.simple_log_entry_matcher(), event);
}
}
-bool LogEntryMatcherManager::matchesSimple(const SimpleLogEntryMatcher &simpleMatcher,
- const int tagId,
- const unordered_map<int, long> &intMap,
- const unordered_map<int, string> &strMap,
- const unordered_map<int, float> &floatMap,
- const unordered_map<int, bool> &boolMap) {
+bool LogEntryMatcherManager::matchesSimple(const SimpleLogEntryMatcher& simpleMatcher,
+ const LogEventWrapper& event) {
+ const int tagId = event.tagId;
+ const unordered_map<int, long>& intMap = event.intMap;
+ const unordered_map<int, string>& strMap = event.strMap;
+ const unordered_map<int, float>& floatMap = event.floatMap;
+ const unordered_map<int, bool>& boolMap = event.boolMap;
+
for (int i = 0; i < simpleMatcher.tag_size(); i++) {
if (simpleMatcher.tag(i) != tagId) {
continue;
@@ -177,6 +249,26 @@
return false;
}
-} // namespace statsd
-} // namespace os
-} // namespace android
+set<int> LogEntryMatcherManager::getTagIdsFromMatcher(const LogEntryMatcher& matcher) {
+ set<int> result;
+ switch (matcher.contents_case()) {
+ case LogEntryMatcher::kCombination:
+ for (auto sub_matcher : matcher.combination().matcher()) {
+ set<int> tagSet = getTagIdsFromMatcher(sub_matcher);
+ result.insert(tagSet.begin(), tagSet.end());
+ }
+ break;
+ case LogEntryMatcher::kSimpleLogEntryMatcher:
+ for (int i = 0; i < matcher.simple_log_entry_matcher().tag_size(); i++) {
+ result.insert(matcher.simple_log_entry_matcher().tag(i));
+ }
+ break;
+ case LogEntryMatcher::CONTENTS_NOT_SET:
+ break;
+ }
+ return result;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/matchers/LogEntryMatcherManager.h b/cmds/statsd/src/matchers/LogEntryMatcherManager.h
index 10ac0e2..fc8e6a1 100644
--- a/cmds/statsd/src/matchers/LogEntryMatcherManager.h
+++ b/cmds/statsd/src/matchers/LogEntryMatcherManager.h
@@ -17,20 +17,30 @@
#ifndef LOG_ENTRY_MATCHER_MANAGER_H
#define LOG_ENTRY_MATCHER_MANAGER_H
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include <log/logprint.h>
#include <log/log_read.h>
+#include <log/logprint.h>
#include <set>
-#include <vector>
#include <unordered_map>
+#include <vector>
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-using std::unordered_map;
using std::string;
+using std::unordered_map;
namespace android {
namespace os {
namespace statsd {
+typedef struct {
+ int tagId;
+ long timestamp_ns;
+ std::unordered_map<int, long> intMap;
+ std::unordered_map<int, std::string> strMap;
+ std::unordered_map<int, bool> boolMap;
+ std::unordered_map<int, float> floatMap;
+} LogEventWrapper;
+
/**
* Keeps track per log entry which simple log entry matchers match.
*/
@@ -38,23 +48,19 @@
public:
LogEntryMatcherManager();
- ~LogEntryMatcherManager() {};
+ ~LogEntryMatcherManager(){};
- static bool matches(const LogEntryMatcher &matcher, const int tagId,
- const unordered_map<int, long> &intMap,
- const unordered_map<int, string> &strMap,
- const unordered_map<int, float> &floatMap,
- const unordered_map<int, bool> &boolMap);
+ static LogEventWrapper parseLogEvent(log_msg msg);
- static bool matchesSimple(const SimpleLogEntryMatcher &simpleMatcher,
- const int tagId,
- const unordered_map<int, long> &intMap,
- const unordered_map<int, string> &strMap,
- const unordered_map<int, float> &floatMap,
- const unordered_map<int, bool> &boolMap);
+ static std::set<int> getTagIdsFromMatcher(const LogEntryMatcher& matcher);
+
+ static bool matches(const LogEntryMatcher& matcher, const LogEventWrapper& wrapper);
+
+ static bool matchesSimple(const SimpleLogEntryMatcher& simpleMatcher,
+ const LogEventWrapper& wrapper);
};
-} // namespace statsd
-} // namespace os
-} // namespace android
-#endif //LOG_ENTRY_MATCHER_MANAGER_H
+} // namespace statsd
+} // namespace os
+} // namespace android
+#endif // LOG_ENTRY_MATCHER_MANAGER_H
diff --git a/cmds/statsd/src/metrics/ConditionTracker.cpp b/cmds/statsd/src/metrics/ConditionTracker.cpp
new file mode 100644
index 0000000..684ffdb
--- /dev/null
+++ b/cmds/statsd/src/metrics/ConditionTracker.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ConditionTracker"
+#define DEBUG true // STOPSHIP if true
+#define VLOG(...) \
+ if (DEBUG) ALOGD(__VA_ARGS__);
+
+#include "ConditionTracker.h"
+#include <cutils/log.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+ConditionTracker::ConditionTracker() : mIsConditionMet(true) {
+ VLOG("ConditionTracker()");
+}
+
+ConditionTracker::ConditionTracker(const Condition& condition)
+ : mCondition(condition), mIsConditionMet(true) {
+ VLOG("ConditionTracker()");
+}
+
+ConditionTracker::~ConditionTracker() {
+ VLOG("~ConditionTracker()");
+}
+
+void ConditionTracker::evaluateCondition(const LogEventWrapper& event) {
+ // modify condition.
+ VLOG("evaluateCondition");
+}
+
+bool ConditionTracker::isConditionMet() const {
+ VLOG("isConditionMet() %d", mIsConditionMet);
+ return mIsConditionMet;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/metrics/ConditionTracker.h b/cmds/statsd/src/metrics/ConditionTracker.h
new file mode 100644
index 0000000..b94d5ab
--- /dev/null
+++ b/cmds/statsd/src/metrics/ConditionTracker.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CONDITION_TRACKER_H
+#define CONDITION_TRACKER_H
+
+#include <utils/RefBase.h>
+#include "../matchers/LogEntryMatcherManager.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class ConditionTracker : public RefBase {
+public:
+ ConditionTracker();
+
+ ConditionTracker(const Condition& condition);
+
+ ~ConditionTracker();
+
+ void evaluateCondition(const LogEventWrapper& event);
+
+ bool isConditionMet() const;
+
+private:
+ // this is the definition of the Condition.
+ Condition mCondition;
+
+ bool mIsConditionMet;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+
+#endif // CONDITION_TRACKER_H
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
new file mode 100644
index 0000000..fbd013e
--- /dev/null
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CountMetric"
+#define DEBUG true // STOPSHIP if true
+#define VLOG(...) \
+ if (DEBUG) ALOGD(__VA_ARGS__);
+
+#include "CountMetricProducer.h"
+#include "parse_util.h"
+
+#include <cutils/log.h>
+#include <limits.h>
+#include <stdlib.h>
+
+using std::unordered_map;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+CountMetricProducer::CountMetricProducer(const CountMetric& metric,
+ const sp<ConditionTracker> condition)
+ : mMetric(metric),
+ mConditionTracker(condition),
+ mStartTime(std::time(nullptr)),
+ mCounter(0),
+ mCurrentBucketStartTime(mStartTime) {
+ // TODO: evaluate initial conditions. and set mConditionMet.
+ if (metric.has_bucket() && metric.bucket().has_bucket_size_millis()) {
+ mBucketSize_sec = metric.bucket().bucket_size_millis() / 1000;
+ } else {
+ mBucketSize_sec = LONG_MAX;
+ }
+
+ VLOG("created. bucket size %lu start_time: %lu", mBucketSize_sec, mStartTime);
+}
+
+CountMetricProducer::CountMetricProducer(const CountMetric& metric)
+ : CountMetricProducer(metric, new ConditionTracker()) {
+}
+
+CountMetricProducer::~CountMetricProducer() {
+ VLOG("~CountMetricProducer() called");
+}
+
+void CountMetricProducer::finish() {
+ // TODO: write the StatsLogReport to dropbox using
+ // DropboxWriter.
+ onDumpReport();
+}
+
+void CountMetricProducer::onDumpReport() {
+ VLOG("dump report now...");
+}
+
+void CountMetricProducer::onMatchedLogEvent(const LogEventWrapper& event) {
+ time_t eventTime = event.timestamp_ns / 1000000000;
+
+ // this is old event, maybe statsd restarted?
+ if (eventTime < mStartTime) {
+ return;
+ }
+
+ if (mConditionTracker->isConditionMet()) {
+ flushCounterIfNeeded(eventTime);
+ mCounter++;
+ }
+}
+
+// When a new matched event comes in, we check if it falls into the current bucket. And flush the
+// counter to the StatsLogReport and adjust the bucket if needed.
+void CountMetricProducer::flushCounterIfNeeded(const time_t& eventTime) {
+ if (mCurrentBucketStartTime + mBucketSize_sec > eventTime) {
+ return;
+ }
+
+ // TODO: add a KeyValuePair to StatsLogReport.
+ ALOGD("CountMetric: dump counter %d", mCounter);
+
+ // reset counter
+ mCounter = 0;
+
+ // adjust the bucket start time
+ mCurrentBucketStartTime =
+ mCurrentBucketStartTime +
+ ((eventTime - mCurrentBucketStartTime) / mBucketSize_sec) * mBucketSize_sec;
+
+ VLOG("new bucket start time: %lu", mCurrentBucketStartTime);
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
new file mode 100644
index 0000000..7665791
--- /dev/null
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef COUNT_METRIC_PRODUCER_H
+#define COUNT_METRIC_PRODUCER_H
+
+#include <mutex>
+#include <thread>
+#include <unordered_map>
+#include "../matchers/LogEntryMatcherManager.h"
+#include "ConditionTracker.h"
+#include "DropboxWriter.h"
+#include "MetricProducer.h"
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class CountMetricProducer : public MetricProducer {
+public:
+ CountMetricProducer(const CountMetric& countMetric, const sp<ConditionTracker> condition);
+
+ CountMetricProducer(const CountMetric& countMetric);
+
+ virtual ~CountMetricProducer();
+
+ void onMatchedLogEvent(const LogEventWrapper& event) override;
+
+ void finish() override;
+
+ void onDumpReport() override;
+
+private:
+ const CountMetric mMetric;
+
+ const sp<ConditionTracker> mConditionTracker;
+
+ const time_t mStartTime;
+ // TODO: Add dimensions.
+ int mCounter;
+
+ time_t mCurrentBucketStartTime;
+
+ long mBucketSize_sec;
+
+ void flushCounterIfNeeded(const time_t& newEventTime);
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#endif // COUNT_METRIC_PRODUCER_H
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
new file mode 100644
index 0000000..44a778b
--- /dev/null
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef METRIC_PRODUCER_H
+#define METRIC_PRODUCER_H
+
+#include <log/logprint.h>
+#include "../matchers/LogEntryMatcherManager.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+// A MetricProducer is responsible for compute one single metrics, creating stats log report, and
+// writing the report to dropbox.
+class MetricProducer {
+public:
+ virtual ~MetricProducer(){};
+
+ // Consume the stats log if it's interesting to this metric.
+ virtual void onMatchedLogEvent(const LogEventWrapper& event) = 0;
+
+ // This is called when the metric collecting is done, e.g., when there is a new configuration
+ // coming. MetricProducer should do the clean up, and dump existing data to dropbox.
+ virtual void finish() = 0;
+
+ virtual void onDumpReport() = 0;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#endif // METRIC_PRODUCER_H
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
new file mode 100644
index 0000000..cb74206
--- /dev/null
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "MetricManager"
+#define DEBUG true // STOPSHIP if true
+#define VLOG(...) \
+ if (DEBUG) ALOGD(__VA_ARGS__);
+
+#include "MetricsManager.h"
+#include <cutils/log.h>
+#include <log/logprint.h>
+#include "CountMetricProducer.h"
+#include "parse_util.h"
+
+using std::make_unique;
+using std::set;
+using std::string;
+using std::unique_ptr;
+using std::unordered_map;
+using std::vector;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+MetricsManager::MetricsManager(const StatsdConfig& config) : mConfig(config), mLogMatchers() {
+ std::unordered_map<string, LogEntryMatcher> matcherMap;
+ std::unordered_map<string, sp<ConditionTracker>> conditionMap;
+
+ for (int i = 0; i < config.log_entry_matcher_size(); i++) {
+ const LogEntryMatcher& logMatcher = config.log_entry_matcher(i);
+ mMatchers.push_back(logMatcher);
+
+ matcherMap[config.log_entry_matcher(i).name()] = logMatcher;
+
+ mLogMatchers[logMatcher.name()] = vector<unique_ptr<MetricProducer>>();
+ // Collect all the tag ids that are interesting
+ set<int> tagIds = LogEntryMatcherManager::getTagIdsFromMatcher(logMatcher);
+
+ mTagIds.insert(tagIds.begin(), tagIds.end());
+ }
+
+ for (int i = 0; i < config.condition_size(); i++) {
+ const Condition& condition = config.condition(i);
+ conditionMap[condition.name()] = new ConditionTracker(condition);
+ }
+
+ // Build MetricProducers for each metric defined in config.
+ // (1) build CountMetricProducer
+ for (int i = 0; i < config.count_metric_size(); i++) {
+ const CountMetric& metric = config.count_metric(i);
+ auto it = mLogMatchers.find(metric.what());
+ if (it == mLogMatchers.end()) {
+ ALOGW("cannot find the LogEntryMatcher %s in config", metric.what().c_str());
+ continue;
+ }
+
+ if (metric.has_condition()) {
+ auto condition_it = conditionMap.find(metric.condition());
+ if (condition_it == conditionMap.end()) {
+ ALOGW("cannot find the Condition %s in the config", metric.condition().c_str());
+ continue;
+ }
+ it->second.push_back(make_unique<CountMetricProducer>(metric, condition_it->second));
+ } else {
+ it->second.push_back(make_unique<CountMetricProducer>(metric));
+ }
+ }
+
+ // TODO: build other types of metrics too.
+}
+
+MetricsManager::~MetricsManager() {
+ VLOG("~MetricManager()");
+}
+
+void MetricsManager::finish() {
+ for (auto const& entryPair : mLogMatchers) {
+ for (auto const& metric : entryPair.second) {
+ metric->finish();
+ }
+ }
+}
+
+// Consume the stats log if it's interesting to this metric.
+void MetricsManager::onLogEvent(const log_msg& logMsg) {
+ int tagId = getTagId(logMsg);
+ if (mTagIds.find(tagId) == mTagIds.end()) {
+ // not interesting...
+ return;
+ }
+ // Since at least one of the metrics is interested in this event, we parse it now.
+ LogEventWrapper event = LogEntryMatcherManager::parseLogEvent(logMsg);
+
+ // Evaluate the conditions. Order matters, this should happen
+ // before sending the event to metrics
+ for (auto& condition : mConditionTracker) {
+ condition->evaluateCondition(event);
+ }
+
+ // Now find out which LogMatcher matches this event, and let relevant metrics know.
+ for (auto matcher : mMatchers) {
+ if (LogEntryMatcherManager::matches(matcher, event)) {
+ auto it = mLogMatchers.find(matcher.name());
+ if (it != mLogMatchers.end()) {
+ for (auto const& it2 : it->second) {
+ // Only metrics that matches this event get notified.
+ it2->onMatchedLogEvent(event);
+ }
+ } else {
+ // TODO: we should remove any redundant matchers that the config provides.
+ ALOGW("Matcher not used by any metrics.");
+ }
+ }
+ }
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
new file mode 100644
index 0000000..77d7535
--- /dev/null
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef METRICS_MANAGER_H
+#define METRICS_MANAGER_H
+
+#include <cutils/log.h>
+#include <log/logprint.h>
+#include <unordered_map>
+#include "../matchers/LogEntryMatcherManager.h"
+#include "ConditionTracker.h"
+#include "MetricProducer.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+// A MetricsManager is responsible for managing metrics from one single config source.
+class MetricsManager {
+public:
+ MetricsManager(const StatsdConfig& config);
+
+ ~MetricsManager();
+
+ // Consume the stats log if it's interesting to this metric.
+ void onLogEvent(const log_msg& logMsg);
+
+ void finish();
+
+private:
+ const StatsdConfig mConfig;
+
+ // All event tags that are interesting to my metrics.
+ std::set<int> mTagIds;
+
+ // The matchers that my metrics share.
+ std::vector<LogEntryMatcher> mMatchers;
+
+ // The conditions that my metrics share.
+ std::vector<sp<ConditionTracker>> mConditionTracker;
+
+ // the map from LogEntryMatcher names to the metrics that use this matcher.
+ std::unordered_map<std::string, std::vector<std::unique_ptr<MetricProducer>>> mLogMatchers;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+
+#endif // METRICS_MANAGER_H
diff --git a/cmds/statsd/src/parse_util.cpp b/cmds/statsd/src/parse_util.cpp
index 408a65c..61421880 100644
--- a/cmds/statsd/src/parse_util.cpp
+++ b/cmds/statsd/src/parse_util.cpp
@@ -17,22 +17,25 @@
#include <log/log_event_list.h>
#include <parse_util.h>
-using android::os::statsd::EventMetricData;
-using android::os::statsd::KeyValuePair;
+namespace android {
+namespace os {
+namespace statsd {
static inline uint32_t get4LE(const char* src) {
return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
}
-EventMetricData parse(log_msg msg)
-{
+int getTagId(log_msg msg) {
+ return get4LE(msg.msg());
+}
+
+EventMetricData parse(log_msg msg) {
// dump all statsd logs to dropbox for now.
// TODO: Add filtering, aggregation, etc.
EventMetricData eventMetricData;
// set tag.
- char* eventData = msg.msg();
- uint32_t tag = get4LE(eventData);
+ int tag = getTagId(msg);
// TODO: Replace the following line when we can serialize on the fly.
//eventMetricData.set_tag(tag);
@@ -124,3 +127,6 @@
return eventMetricData;
}
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/parse_util.h b/cmds/statsd/src/parse_util.h
index e9f4c27..8b82e7b 100644
--- a/cmds/statsd/src/parse_util.h
+++ b/cmds/statsd/src/parse_util.h
@@ -21,8 +21,16 @@
#include <log/logprint.h>
-using android::os::statsd::EventMetricData;
+namespace android {
+namespace os {
+namespace statsd {
-EventMetricData parse(const log_msg msg);
+EventMetricData parse(log_msg msg);
+
+int getTagId(log_msg msg);
+
+} // namespace statsd
+} // namespace os
+} // namespace android
#endif // PARSE_UTIL_H
diff --git a/cmds/statsd/src/stats_events.proto b/cmds/statsd/src/stats_events.proto
index dffc68e..1e17895 100644
--- a/cmds/statsd/src/stats_events.proto
+++ b/cmds/statsd/src/stats_events.proto
@@ -23,13 +23,19 @@
option java_outer_classname = "StatsEventProto";
message StatsEvent {
- oneof log_entry_event {
+ oneof event {
+ // Screen state change.
ScreenStateChange screen_state_change = 2;
+ // Process state change.
ProcessStateChange process_state_change = 1112;
}
}
+// Logs changes in screen state. This event is logged in
+// frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
message ScreenStateChange {
+ // Screen state enums follow the values defined in below file.
+ // frameworks/base/core/java/android/view/Display.java
enum State {
STATE_UNKNOWN = 0;
STATE_OFF = 1;
@@ -38,20 +44,20 @@
STATE_DOZE_SUSPEND = 4;
STATE_VR = 5;
}
+ // New screen state.
optional State display_state = 1;
}
+// Logs changes in process state. This event is logged in
+// frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
message ProcessStateChange {
+ // Type of process event.
enum State {
START = 1;
CRASH = 2;
}
optional State state = 1;
+ // UID associated with the package.
optional int32 uid = 2;
-
- optional string package_name = 1002;
-
- optional int32 package_version = 3;
- optional string package_version_string = 4;
}
diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp
index 81d93b6..473704a 100644
--- a/cmds/statsd/tests/LogEntryMatcher_test.cpp
+++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp
@@ -14,13 +14,13 @@
#define LOG_TAG "statsd_test"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include <gtest/gtest.h>
+#include <log/log_event_list.h>
+#include <log/log_read.h>
+#include <log/logprint.h>
#include "../src/matchers/LogEntryMatcherManager.h"
#include "../src/parse_util.h"
-#include <log/logprint.h>
-#include <log/log_read.h>
-#include <log/log_event_list.h>
-#include <gtest/gtest.h>
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include <stdio.h>
@@ -38,12 +38,10 @@
auto simpleMatcher = matcher.mutable_simple_log_entry_matcher();
simpleMatcher->add_tag(kTagIdWakelock);
- unordered_map<int, long> intMap;
- unordered_map<int, string> strMap;
- unordered_map<int, float> floatMap;
- unordered_map<int, bool> boolMap;
+ LogEventWrapper wrapper;
+ wrapper.tagId = kTagIdWakelock;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap, floatMap, boolMap));
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
}
TEST(LogEntryMatcherTest, TestBoolMatcher) {
@@ -54,24 +52,18 @@
auto keyValue = simpleMatcher->add_key_value_matcher();
keyValue->mutable_key_matcher()->set_key(kKeyIdState);
-
- unordered_map<int, long> intMap;
- unordered_map<int, string> strMap;
- unordered_map<int, float> floatMap;
- unordered_map<int, bool> boolMap;
+ LogEventWrapper wrapper;
+ wrapper.tagId = kTagIdWakelock;
keyValue->set_eq_bool(true);
- boolMap[kKeyIdState] = true;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap, floatMap,
- boolMap));
+ wrapper.boolMap[kKeyIdState] = true;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
keyValue->set_eq_bool(false);
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap,
- floatMap, boolMap));
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
- boolMap[kKeyIdState] = false;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap, floatMap,
- boolMap));
+ wrapper.boolMap[kTagIdWakelock] = false;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
}
TEST(LogEntryMatcherTest, TestStringMatcher) {
@@ -83,14 +75,12 @@
keyValue->mutable_key_matcher()->set_key(kKeyIdState);
keyValue->set_eq_string("wakelock_name");
- unordered_map<int, long> intMap;
- unordered_map<int, string> strMap;
- unordered_map<int, float> floatMap;
- unordered_map<int, bool> boolMap;
+ LogEventWrapper wrapper;
+ wrapper.tagId = kTagIdWakelock;
- strMap[kKeyIdState] = "wakelock_name";
+ wrapper.strMap[kKeyIdState] = "wakelock_name";
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap, floatMap, boolMap));
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
}
TEST(LogEntryMatcherTest, TestIntComparisonMatcher) {
@@ -101,32 +91,24 @@
auto keyValue = simpleMatcher->add_key_value_matcher();
keyValue->mutable_key_matcher()->set_key(kKeyIdState);
- unordered_map<int, long> intMap;
- unordered_map<int, string> strMap;
- unordered_map<int, float> floatMap;
- unordered_map<int, bool> boolMap;
+ LogEventWrapper wrapper;
+ wrapper.tagId = kTagIdWakelock;
keyValue->set_lt_int(10);
- intMap[kKeyIdState] = 11;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap,
- floatMap, boolMap));
- intMap[kKeyIdState] = 10;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap,
- floatMap, boolMap));
- intMap[kKeyIdState] = 9;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap,
- floatMap, boolMap));
+ wrapper.intMap[kKeyIdState] = 11;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[kKeyIdState] = 10;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[kKeyIdState] = 9;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
keyValue->set_gt_int(10);
- intMap[kKeyIdState] = 11;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap,
- floatMap, boolMap));
- intMap[kKeyIdState] = 10;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap,
- floatMap, boolMap));
- intMap[kKeyIdState] = 9;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap,
- floatMap, boolMap));
+ wrapper.intMap[kKeyIdState] = 11;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[kKeyIdState] = 10;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[kKeyIdState] = 9;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
}
TEST(LogEntryMatcherTest, TestIntWithEqualityComparisonMatcher) {
@@ -137,32 +119,24 @@
auto keyValue = simpleMatcher->add_key_value_matcher();
keyValue->mutable_key_matcher()->set_key(kKeyIdState);
- unordered_map<int, long> intMap;
- unordered_map<int, string> strMap;
- unordered_map<int, float> floatMap;
- unordered_map<int, bool> boolMap;
+ LogEventWrapper wrapper;
+ wrapper.tagId = kTagIdWakelock;
keyValue->set_lte_int(10);
- intMap[kKeyIdState] = 11;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap,
- floatMap, boolMap));
- intMap[kKeyIdState] = 10;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap,
- floatMap, boolMap));
- intMap[kKeyIdState] = 9;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap,
- floatMap, boolMap));
+ wrapper.intMap[kKeyIdState] = 11;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[kKeyIdState] = 10;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[kKeyIdState] = 9;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
keyValue->set_gte_int(10);
- intMap[kKeyIdState] = 11;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap,
- floatMap, boolMap));
- intMap[kKeyIdState] = 10;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap,
- floatMap, boolMap));
- intMap[kKeyIdState] = 9;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap,
- floatMap, boolMap));
+ wrapper.intMap[kKeyIdState] = 11;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[kKeyIdState] = 10;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[kKeyIdState] = 9;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
}
TEST(LogEntryMatcherTest, TestFloatComparisonMatcher) {
@@ -173,26 +147,20 @@
auto keyValue = simpleMatcher->add_key_value_matcher();
keyValue->mutable_key_matcher()->set_key(kKeyIdState);
- unordered_map<int, long> intMap;
- unordered_map<int, string> strMap;
- unordered_map<int, float> floatMap;
- unordered_map<int, bool> boolMap;
+ LogEventWrapper wrapper;
+ wrapper.tagId = kTagIdWakelock;
keyValue->set_lt_float(10.0);
- floatMap[kKeyIdState] = 10.1;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap,
- floatMap, boolMap));
- floatMap[kKeyIdState] = 9.9;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap,
- floatMap, boolMap));
+ wrapper.floatMap[kKeyIdState] = 10.1;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.floatMap[kKeyIdState] = 9.9;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
keyValue->set_gt_float(10.0);
- floatMap[kKeyIdState] = 10.1;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap,
- floatMap, boolMap));
- floatMap[kKeyIdState] = 9.9;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap,
- floatMap, boolMap));
+ wrapper.floatMap[kKeyIdState] = 10.1;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.floatMap[kKeyIdState] = 9.9;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
}
// Helper for the composite matchers.
@@ -209,23 +177,23 @@
auto combination = matcher.mutable_combination();
combination->set_operation(LogicalOperation::AND);
- addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(), kTagIdWakelock, kKeyIdState, 3);
- addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(), kTagIdWakelock, kKeyIdPackageVersion, 4);
+ addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
+ kTagIdWakelock, kKeyIdState, 3);
+ addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
+ kTagIdWakelock, kKeyIdPackageVersion, 4);
- unordered_map<int, long> intMap;
- unordered_map<int, string> strMap;
- unordered_map<int, float> floatMap;
- unordered_map<int, bool> boolMap;
+ LogEventWrapper wrapper;
+ wrapper.tagId = kTagIdWakelock;
- intMap[kKeyIdPackageVersion] = 4;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap, floatMap, boolMap));
- intMap.clear();
- intMap[kKeyIdState] = 3;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap, floatMap, boolMap));
- intMap.clear();
- intMap[kKeyIdState] = 3;
- intMap[kKeyIdPackageVersion] = 4;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap, floatMap, boolMap));
+ wrapper.intMap[1003] = 4;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap.clear();
+ wrapper.intMap[1] = 3;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap.clear();
+ wrapper.intMap[1] = 3;
+ wrapper.intMap[1003] = 4;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
}
TEST(LogEntryMatcherTest, TestOrMatcher) {
@@ -239,26 +207,20 @@
addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
kTagIdWakelock, kKeyIdPackageVersion, 4);
- unordered_map<int, long> intMap;
- unordered_map<int, string> strMap;
- unordered_map<int, float> floatMap;
- unordered_map<int, bool> boolMap;
+ LogEventWrapper wrapper;
+ wrapper.tagId = kTagIdWakelock;
// Don't set any key-value pairs.
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap, floatMap,
- boolMap));
- intMap[kKeyIdPackageVersion] = 4;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap, floatMap,
- boolMap));
- intMap.clear();
- intMap[kKeyIdState] = 3;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap, floatMap,
- boolMap));
- intMap.clear();
- intMap[kKeyIdState] = 3;
- intMap[kKeyIdPackageVersion] = 4;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap, floatMap,
- boolMap));
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[1003] = 4;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap.clear();
+ wrapper.intMap[1] = 3;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap.clear();
+ wrapper.intMap[1] = 3;
+ wrapper.intMap[1003] = 4;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
}
TEST(LogEntryMatcherTest, TestNotMatcher) {
@@ -271,15 +233,12 @@
addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
kTagIdWakelock, kKeyIdState, 3);
- unordered_map<int, long> intMap;
- unordered_map<int, string> strMap;
- unordered_map<int, float> floatMap;
- unordered_map<int, bool> boolMap;
+ LogEventWrapper wrapper;
+ wrapper.tagId = kTagIdWakelock;
// Don't set any key-value pairs.
- intMap[kKeyIdState] = 3;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap, floatMap,
- boolMap));
+ wrapper.intMap[kKeyIdState] = 3;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
}
TEST(LogEntryMatcherTest, TestNANDMatcher) {
@@ -293,20 +252,15 @@
addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
kTagIdWakelock, kKeyIdPackageVersion, 4);
- unordered_map<int, long> intMap;
- unordered_map<int, string> strMap;
- unordered_map<int, float> floatMap;
- unordered_map<int, bool> boolMap;
+ LogEventWrapper wrapper;
+ wrapper.tagId = kTagIdWakelock;
// Don't set any key-value pairs.
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap, floatMap,
- boolMap));
- intMap[kKeyIdState] = 3;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap, floatMap,
- boolMap));
- intMap[kKeyIdPackageVersion] = 4;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap, floatMap,
- boolMap));
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[kKeyIdState] = 3;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[kKeyIdPackageVersion] = 4;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
}
TEST(LogEntryMatcherTest, TestNORMatcher) {
@@ -320,20 +274,15 @@
addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
kTagIdWakelock, kKeyIdPackageVersion, 4);
- unordered_map<int, long> intMap;
- unordered_map<int, string> strMap;
- unordered_map<int, float> floatMap;
- unordered_map<int, bool> boolMap;
+ LogEventWrapper wrapper;
+ wrapper.tagId = kTagIdWakelock;
// Don't set any key-value pairs.
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap, floatMap,
- boolMap));
- intMap[kKeyIdState] = 3;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap, floatMap,
- boolMap));
- intMap[kKeyIdPackageVersion] = 4;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap, floatMap,
- boolMap));
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[kKeyIdState] = 3;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[kKeyIdPackageVersion] = 4;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
}
// Tests that a NOT on top of AND is the same as NAND
@@ -350,22 +299,17 @@
addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
kTagIdWakelock, kKeyIdPackageVersion, 4);
- unordered_map<int, long> intMap;
- unordered_map<int, string> strMap;
- unordered_map<int, float> floatMap;
- unordered_map<int, bool> boolMap;
+ LogEventWrapper wrapper;
+ wrapper.tagId = kTagIdWakelock;
// Don't set any key-value pairs.
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap, floatMap,
- boolMap));
- intMap[kKeyIdState] = 3;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap, floatMap,
- boolMap));
- intMap[kKeyIdPackageVersion] = 4;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, kTagIdWakelock, intMap, strMap, floatMap,
- boolMap));
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[kKeyIdState] = 3;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[kKeyIdPackageVersion] = 4;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
}
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index b07327f..2516a3e 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -5780,7 +5780,7 @@
final int preloadedFontsResource = info.metaData.getInt(
ApplicationInfo.METADATA_PRELOADED_FONTS, 0);
if (preloadedFontsResource != 0) {
- data.info.mResources.preloadFonts(preloadedFontsResource);
+ data.info.getResources().preloadFonts(preloadedFontsResource);
}
}
} catch (RemoteException e) {
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 163a8dc..64b9ae8 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -25,6 +25,7 @@
import android.provider.Settings;
import android.service.notification.NotificationListenerService;
import android.text.TextUtils;
+import android.util.proto.ProtoOutputStream;
import org.json.JSONException;
import org.json.JSONObject;
@@ -135,12 +136,15 @@
private boolean mLights;
private int mLightColor = DEFAULT_LIGHT_COLOR;
private long[] mVibration;
+ // Bitwise representation of fields that have been changed by the user, preventing the app from
+ // making changes to these fields.
private int mUserLockedFields;
private boolean mVibrationEnabled;
private boolean mShowBadge = DEFAULT_SHOW_BADGE;
private boolean mDeleted = DEFAULT_DELETED;
private String mGroup;
private AudioAttributes mAudioAttributes = Notification.AUDIO_ATTRIBUTES_DEFAULT;
+ // If this is a blockable system notification channel.
private boolean mBlockableSystem = false;
/**
@@ -850,4 +854,35 @@
+ ", mBlockableSystem=" + mBlockableSystem
+ '}';
}
+
+ /** @hide */
+ public void toProto(ProtoOutputStream proto) {
+ proto.write(NotificationChannelProto.ID, mId);
+ proto.write(NotificationChannelProto.NAME, mName);
+ proto.write(NotificationChannelProto.DESCRIPTION, mDesc);
+ proto.write(NotificationChannelProto.IMPORTANCE, mImportance);
+ proto.write(NotificationChannelProto.CAN_BYPASS_DND, mBypassDnd);
+ proto.write(NotificationChannelProto.LOCKSCREEN_VISIBILITY, mLockscreenVisibility);
+ if (mSound != null) {
+ proto.write(NotificationChannelProto.SOUND, mSound.toString());
+ }
+ proto.write(NotificationChannelProto.USE_LIGHTS, mLights);
+ proto.write(NotificationChannelProto.LIGHT_COLOR, mLightColor);
+ if (mVibration != null) {
+ for (long v : mVibration) {
+ proto.write(NotificationChannelProto.VIBRATION, v);
+ }
+ }
+ proto.write(NotificationChannelProto.USER_LOCKED_FIELDS, mUserLockedFields);
+ proto.write(NotificationChannelProto.IS_VIBRATION_ENABLED, mVibrationEnabled);
+ proto.write(NotificationChannelProto.SHOW_BADGE, mShowBadge);
+ proto.write(NotificationChannelProto.IS_DELETED, mDeleted);
+ proto.write(NotificationChannelProto.GROUP, mGroup);
+ if (mAudioAttributes != null) {
+ long aToken = proto.start(NotificationChannelProto.AUDIO_ATTRIBUTES);
+ mAudioAttributes.toProto(proto);
+ proto.end(aToken);
+ }
+ proto.write(NotificationChannelProto.IS_BLOCKABLE_SYSTEM, mBlockableSystem);
+ }
}
diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java
index 5173311..5cb7fb7 100644
--- a/core/java/android/app/NotificationChannelGroup.java
+++ b/core/java/android/app/NotificationChannelGroup.java
@@ -21,6 +21,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import android.util.proto.ProtoOutputStream;
import org.json.JSONException;
import org.json.JSONObject;
@@ -295,4 +296,15 @@
+ ", mChannels=" + mChannels
+ '}';
}
+
+ /** @hide */
+ public void toProto(ProtoOutputStream proto) {
+ proto.write(NotificationChannelGroupProto.ID, mId);
+ proto.write(NotificationChannelGroupProto.NAME, mName.toString());
+ proto.write(NotificationChannelGroupProto.DESCRIPTION, mDescription);
+ proto.write(NotificationChannelGroupProto.IS_BLOCKED, mBlocked);
+ for (NotificationChannel channel : mChannels) {
+ channel.toProto(proto);
+ }
+ }
}
diff --git a/core/java/android/app/SharedElementCallback.java b/core/java/android/app/SharedElementCallback.java
index 0d14a8d..80fb805 100644
--- a/core/java/android/app/SharedElementCallback.java
+++ b/core/java/android/app/SharedElementCallback.java
@@ -27,6 +27,7 @@
import android.os.Parcelable;
import android.transition.TransitionUtils;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
@@ -202,7 +203,8 @@
} else {
mTempMatrix.set(viewToGlobalMatrix);
}
- return TransitionUtils.createViewBitmap(sharedElement, mTempMatrix, screenBounds);
+ ViewGroup parent = (ViewGroup) sharedElement.getParent();
+ return TransitionUtils.createViewBitmap(sharedElement, mTempMatrix, screenBounds, parent);
}
/**
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index ab70f0e..50f1f36 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -81,10 +81,10 @@
import android.net.IpSecManager;
import android.net.NetworkPolicyManager;
import android.net.NetworkScoreManager;
-import android.net.nsd.INsdManager;
-import android.net.nsd.NsdManager;
import android.net.lowpan.ILowpanManager;
import android.net.lowpan.LowpanManager;
+import android.net.nsd.INsdManager;
+import android.net.nsd.NsdManager;
import android.net.wifi.IRttManager;
import android.net.wifi.IWifiManager;
import android.net.wifi.IWifiScanner;
@@ -95,6 +95,8 @@
import android.net.wifi.aware.WifiAwareManager;
import android.net.wifi.p2p.IWifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager;
+import android.net.wifi.rtt.IWifiRttManager;
+import android.net.wifi.rtt.WifiRttManager;
import android.nfc.NfcManager;
import android.os.BatteryManager;
import android.os.BatteryStats;
@@ -603,6 +605,16 @@
ConnectivityThread.getInstanceLooper());
}});
+ registerService(Context.WIFI_RTT2_SERVICE, WifiRttManager.class,
+ new CachedServiceFetcher<WifiRttManager>() {
+ @Override
+ public WifiRttManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ IBinder b = ServiceManager.getServiceOrThrow(Context.WIFI_RTT2_SERVICE);
+ IWifiRttManager service = IWifiRttManager.Stub.asInterface(b);
+ return new WifiRttManager(ctx.getOuterContext(), service);
+ }});
+
registerService(Context.ETHERNET_SERVICE, EthernetManager.class,
new CachedServiceFetcher<EthernetManager>() {
@Override
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 6bccad9..3c53063 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -63,7 +63,9 @@
import android.util.ArraySet;
import android.util.Log;
+import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
import com.android.org.conscrypt.TrustedCertificateStore;
import java.io.ByteArrayInputStream;
@@ -3142,6 +3144,7 @@
*/
public static final int WIPE_EUICC = 0x0004;
+
/**
* Ask that all user data be wiped. If called as a secondary user, the user will be removed and
* other users will remain unaffected. Calling from the primary user will cause the device to
@@ -3157,10 +3160,47 @@
* that uses {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA}
*/
public void wipeData(int flags) {
- throwIfParentInstance("wipeData");
+ final String wipeReasonForUser = mContext.getString(
+ R.string.work_profile_deleted_description_dpm_wipe);
+ wipeDataInternal(flags, wipeReasonForUser);
+ }
+
+ /**
+ * Ask that all user data be wiped. If called as a secondary user, the user will be removed and
+ * other users will remain unaffected, the provided reason for wiping data can be shown to
+ * user. Calling from the primary user will cause the device to reboot, erasing all device data
+ * - including all the secondary users and their data - while booting up. In this case, we don't
+ * show the reason to the user since the device would be factory reset.
+ * <p>
+ * The calling device admin must have requested {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA} to
+ * be able to call this method; if it has not, a security exception will be thrown.
+ *
+ * @param flags Bit mask of additional options: currently supported flags are
+ * {@link #WIPE_EXTERNAL_STORAGE} and {@link #WIPE_RESET_PROTECTION_DATA}.
+ * @param reason a string that contains the reason for wiping data, which can be
+ * presented to the user.
+ * @throws SecurityException if the calling application does not own an active administrator
+ * that uses {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA}
+ * @throws IllegalArgumentException if the input reason string is null or empty.
+ */
+ public void wipeDataWithReason(int flags, @NonNull CharSequence reason) {
+ Preconditions.checkNotNull(reason, "CharSequence is null");
+ wipeDataInternal(flags, reason.toString());
+ }
+
+ /**
+ * Internal function for both {@link #wipeData(int)} and
+ * {@link #wipeDataWithReason(int, CharSequence)} to call.
+ *
+ * @see #wipeData(int)
+ * @see #wipeDataWithReason(int, CharSequence)
+ * @hide
+ */
+ private void wipeDataInternal(int flags, @NonNull String wipeReasonForUser) {
+ throwIfParentInstance("wipeDataWithReason");
if (mService != null) {
try {
- mService.wipeData(flags);
+ mService.wipeDataWithReason(flags, wipeReasonForUser);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -7534,12 +7574,12 @@
}
/**
- * Called by the device owner or profile owner to set the name of the organization under
- * management.
- * <p>
- * If the organization name needs to be localized, it is the responsibility of the
- * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
- * and set a new version of this string accordingly.
+ * Called by the device owner (since API 26) or profile owner (since API 24) to set the name of
+ * the organization under management.
+ *
+ * <p>If the organization name needs to be localized, it is the responsibility of the {@link
+ * DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast and set
+ * a new version of this string accordingly.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param title The organization name or {@code null} to clear a previously set name.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index acfb602..8865a05 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -95,7 +95,7 @@
void lockNow(int flags, boolean parent);
- void wipeData(int flags);
+ void wipeDataWithReason(int flags, String wipeReasonForUser);
ComponentName setGlobalProxy(in ComponentName admin, String proxySpec, String exclusionList);
ComponentName getGlobalProxyAdmin(int userHandle);
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index c208f1d..d9b7cd7 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -674,6 +674,7 @@
ViewNodeText mText;
int mInputType;
+ String mWebScheme;
String mWebDomain;
Bundle mExtras;
LocaleList mLocaleList;
@@ -751,6 +752,7 @@
mInputType = in.readInt();
}
if ((flags&FLAGS_HAS_URL) != 0) {
+ mWebScheme = in.readString();
mWebDomain = in.readString();
}
if ((flags&FLAGS_HAS_LOCALE_LIST) != 0) {
@@ -813,7 +815,7 @@
if (mInputType != 0) {
flags |= FLAGS_HAS_INPUT_TYPE;
}
- if (mWebDomain != null) {
+ if (mWebScheme != null || mWebDomain != null) {
flags |= FLAGS_HAS_URL;
}
if (mLocaleList != null) {
@@ -908,6 +910,7 @@
out.writeInt(mInputType);
}
if ((flags&FLAGS_HAS_URL) != 0) {
+ out.writeString(mWebScheme);
out.writeString(mWebDomain);
}
if ((flags&FLAGS_HAS_LOCALE_LIST) != 0) {
@@ -1265,13 +1268,26 @@
* {@link android.service.autofill.AutofillService} for more details.
*
* @return domain-only part of the document. For example, if the full URL is
- * {@code https://my.site/login?user=my_user}, it returns {@code my.site}.
+ * {@code https://example.com/login?user=my_user}, it returns {@code example.com}.
*/
@Nullable public String getWebDomain() {
return mWebDomain;
}
/**
+ * Returns the scheme of the HTML document represented by this view.
+ *
+ * <p>Typically used when the view associated with the view is a container for an HTML
+ * document.
+ *
+ * @return scheme-only part of the document. For example, if the full URL is
+ * {@code https://example.com/login?user=my_user}, it returns {@code https}.
+ */
+ @Nullable public String getWebScheme() {
+ return mWebScheme;
+ }
+
+ /**
* Returns the HTML properties associated with this view.
*
* <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
@@ -1767,10 +1783,13 @@
@Override
public void setWebDomain(@Nullable String domain) {
if (domain == null) {
+ mNode.mWebScheme = null;
mNode.mWebDomain = null;
return;
}
- mNode.mWebDomain = Uri.parse(domain).getHost();
+ Uri uri = Uri.parse(domain);
+ mNode.mWebScheme = uri.getScheme();
+ mNode.mWebDomain = uri.getHost();
}
@Override
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index 87e516c..1434c9b 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -317,7 +317,8 @@
}
/**
- * Whether this job needs the device to be plugged in.
+ * Whether this job requires that the device be charging (or be a non-battery-powered
+ * device connected to permanent power, such as Android TV devices).
*/
public boolean isRequireCharging() {
return (constraintFlags & CONSTRAINT_FLAG_CHARGING) != 0;
@@ -331,7 +332,10 @@
}
/**
- * Whether this job needs the device to be in an Idle maintenance window.
+ * Whether this job requires that the user <em>not</em> be interacting with the device.
+ *
+ * <p class="note">This is <em>not</em> the same as "doze" or "device idle";
+ * it is purely about the user's direct interactions.</p>
*/
public boolean isRequireDeviceIdle() {
return (constraintFlags & CONSTRAINT_FLAG_DEVICE_IDLE) != 0;
@@ -918,9 +922,19 @@
}
/**
- * Specify that to run this job, the device needs to be plugged in. This defaults to
- * false.
- * @param requiresCharging Whether or not the device is plugged in.
+ * Specify that to run this job, the device must be charging (or be a
+ * non-battery-powered device connected to permanent power, such as Android TV
+ * devices). This defaults to {@code false}.
+ *
+ * <p class="note">For purposes of running jobs, a battery-powered device
+ * "charging" is not quite the same as simply being connected to power. If the
+ * device is so busy that the battery is draining despite a power connection, jobs
+ * with this constraint will <em>not</em> run. This can happen during some
+ * common use cases such as video chat, particularly if the device is plugged in
+ * to USB rather than to wall power.
+ *
+ * @param requiresCharging Pass {@code true} to require that the device be
+ * charging in order to run the job.
*/
public Builder setRequiresCharging(boolean requiresCharging) {
mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_CHARGING)
@@ -942,14 +956,22 @@
}
/**
- * Specify that to run, the job needs the device to be in idle mode. This defaults to
- * false.
- * <p>Idle mode is a loose definition provided by the system, which means that the device
- * is not in use, and has not been in use for some time. As such, it is a good time to
- * perform resource heavy jobs. Bear in mind that battery usage will still be attributed
- * to your application, and surfaced to the user in battery stats.</p>
- * @param requiresDeviceIdle Whether or not the device need be within an idle maintenance
- * window.
+ * When set {@code true}, ensure that this job will not run if the device is in active use.
+ * The default state is {@code false}: that is, the for the job to be runnable even when
+ * someone is interacting with the device.
+ *
+ * <p>This state is a loose definition provided by the system. In general, it means that
+ * the device is not currently being used interactively, and has not been in use for some
+ * time. As such, it is a good time to perform resource heavy jobs. Bear in mind that
+ * battery usage will still be attributed to your application, and surfaced to the user in
+ * battery stats.</p>
+ *
+ * <p class="note">Despite the similar naming, this job constraint is <em>not</em>
+ * related to the system's "device idle" or "doze" states. This constraint only
+ * determines whether a job is allowed to run while the device is directly in use.
+ *
+ * @param requiresDeviceIdle Pass {@code true} to prevent the job from running
+ * while the device is being used interactively.
*/
public Builder setRequiresDeviceIdle(boolean requiresDeviceIdle) {
mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_DEVICE_IDLE)
diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java
index 19f5198..a1a9347 100644
--- a/core/java/android/bluetooth/BluetoothPbap.java
+++ b/core/java/android/bluetooth/BluetoothPbap.java
@@ -16,6 +16,7 @@
package android.bluetooth;
+import android.annotation.SdkConstant;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -53,35 +54,32 @@
private static final boolean DBG = true;
private static final boolean VDBG = false;
- /** int extra for PBAP_STATE_CHANGED_ACTION */
- public static final String PBAP_STATE =
- "android.bluetooth.pbap.intent.PBAP_STATE";
- /** int extra for PBAP_STATE_CHANGED_ACTION */
- public static final String PBAP_PREVIOUS_STATE =
- "android.bluetooth.pbap.intent.PBAP_PREVIOUS_STATE";
-
/**
- * Indicates the state of a pbap connection state has changed.
- * This intent will always contain PBAP_STATE, PBAP_PREVIOUS_STATE and
- * BluetoothIntent.ADDRESS extras.
+ * Intent used to broadcast the change in connection state of the PBAP
+ * profile.
+ *
+ * <p>This intent will have 3 extras:
+ * <ul>
+ * <li> {@link BluetoothProfile#EXTRA_STATE} - The current state of the profile. </li>
+ * <li> {@link BluetoothProfile#EXTRA_PREVIOUS_STATE}- The previous state of the profile. </li>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * </ul>
+ * <p>{@link BluetoothProfile#EXTRA_STATE} or {@link BluetoothProfile#EXTRA_PREVIOUS_STATE}
+ * can be any of {@link BluetoothProfile#STATE_DISCONNECTED},
+ * {@link BluetoothProfile#STATE_CONNECTING}, {@link BluetoothProfile#STATE_CONNECTED},
+ * {@link BluetoothProfile#STATE_DISCONNECTING}.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
*/
- public static final String PBAP_STATE_CHANGED_ACTION =
- "android.bluetooth.pbap.intent.action.PBAP_STATE_CHANGED";
+ @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_CONNECTION_STATE_CHANGED =
+ "android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED";
private volatile IBluetoothPbap mService;
private final Context mContext;
private ServiceListener mServiceListener;
private BluetoothAdapter mAdapter;
- /** There was an error trying to obtain the state */
- public static final int STATE_ERROR = -1;
- /** No client currently connected */
- public static final int STATE_DISCONNECTED = 0;
- /** Connection attempt in progress */
- public static final int STATE_CONNECTING = 1;
- /** Client is currently connected */
- public static final int STATE_CONNECTED = 2;
-
public static final int RESULT_FAILURE = 0;
public static final int RESULT_SUCCESS = 1;
/** Connection canceled before completion. */
@@ -209,8 +207,8 @@
/**
* Get the current state of the BluetoothPbap service.
*
- * @return One of the STATE_ return codes, or STATE_ERROR if this proxy object is currently not
- * connected to the Pbap service.
+ * @return One of the STATE_ return codes, or {@link BluetoothProfile#STATE_DISCONNECTED}
+ * if this proxy object is currently not connected to the Pbap service.
*/
public int getState() {
if (VDBG) log("getState()");
@@ -225,7 +223,7 @@
Log.w(TAG, "Proxy not attached to service");
if (DBG) log(Log.getStackTraceString(new Throwable()));
}
- return BluetoothPbap.STATE_ERROR;
+ return BluetoothProfile.STATE_DISCONNECTED;
}
/**
diff --git a/core/java/android/bluetooth/BluetoothPbapClient.java b/core/java/android/bluetooth/BluetoothPbapClient.java
index 00a15f3..01b3f6e 100644
--- a/core/java/android/bluetooth/BluetoothPbapClient.java
+++ b/core/java/android/bluetooth/BluetoothPbapClient.java
@@ -40,7 +40,7 @@
private static final boolean VDBG = false;
public static final String ACTION_CONNECTION_STATE_CHANGED =
- "android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED";
+ "android.bluetooth.pbapclient.profile.action.CONNECTION_STATE_CHANGED";
private volatile IBluetoothPbapClient mService;
private final Context mContext;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 693921d..cd9c6a3 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3467,6 +3467,19 @@
/**
* Use with {@link #getSystemService} to retrieve a {@link
+ * android.net.wifi.rtt.WifiRttManager} for ranging devices with wifi
+ *
+ * Note: this is a replacement for WIFI_RTT_SERVICE above. It will
+ * be renamed once final implementation in place.
+ *
+ * @see #getSystemService
+ * @see android.net.wifi.rtt.WifiRttManager
+ * @hide
+ */
+ public static final String WIFI_RTT2_SERVICE = "rttmanager2";
+
+ /**
+ * Use with {@link #getSystemService} to retrieve a {@link
* android.net.lowpan.LowpanManager} for handling management of
* LoWPAN access.
*
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index ef8f84b..31ca198 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2330,6 +2330,16 @@
/**
* Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device supports Wi-Fi RTT (IEEE 802.11mc).
+ *
+ * @hide RTT_API
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_WIFI_RTT = "android.hardware.wifi.rtt";
+
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device supports LoWPAN networking.
* @hide
*/
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index d3a3560..6b9c753 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -1763,21 +1763,43 @@
return 0;
}
+
/**
* Return a string representation, intended for logging. Some fields will be retracted.
*/
@Override
public String toString() {
- return toStringInner(/* secure =*/ true, /* includeInternalData =*/ false);
+ return toStringInner(/* secure =*/ true, /* includeInternalData =*/ false,
+ /*indent=*/ null);
}
/** @hide */
public String toInsecureString() {
- return toStringInner(/* secure =*/ false, /* includeInternalData =*/ true);
+ return toStringInner(/* secure =*/ false, /* includeInternalData =*/ true,
+ /*indent=*/ null);
}
- private String toStringInner(boolean secure, boolean includeInternalData) {
+ /** @hide */
+ public String toDumpString(String indent) {
+ return toStringInner(/* secure =*/ false, /* includeInternalData =*/ true, indent);
+ }
+
+ private void addIndentOrComma(StringBuilder sb, String indent) {
+ if (indent != null) {
+ sb.append("\n ");
+ sb.append(indent);
+ } else {
+ sb.append(", ");
+ }
+ }
+
+ private String toStringInner(boolean secure, boolean includeInternalData, String indent) {
final StringBuilder sb = new StringBuilder();
+
+ if (indent != null) {
+ sb.append(indent);
+ }
+
sb.append("ShortcutInfo {");
sb.append("id=");
@@ -1787,47 +1809,51 @@
sb.append(Integer.toHexString(mFlags));
sb.append(" [");
if (!isEnabled()) {
- sb.append("X");
+ sb.append("Dis");
}
if (isImmutable()) {
sb.append("Im");
}
if (isManifestShortcut()) {
- sb.append("M");
+ sb.append("Man");
}
if (isDynamic()) {
- sb.append("D");
+ sb.append("Dyn");
}
if (isPinned()) {
- sb.append("P");
+ sb.append("Pin");
}
if (hasIconFile()) {
- sb.append("If");
+ sb.append("Ic-f");
}
if (isIconPendingSave()) {
- sb.append("^");
+ sb.append("Pens");
}
if (hasIconResource()) {
- sb.append("Ir");
+ sb.append("Ic-r");
}
if (hasKeyFieldsOnly()) {
- sb.append("K");
+ sb.append("Key");
}
if (hasStringResourcesResolved()) {
- sb.append("Sr");
+ sb.append("Str");
}
if (isReturnedByServer()) {
- sb.append("V");
+ sb.append("Rets");
}
sb.append("]");
- sb.append(", packageName=");
+ addIndentOrComma(sb, indent);
+
+ sb.append("packageName=");
sb.append(mPackageName);
sb.append(", activity=");
sb.append(mActivity);
- sb.append(", shortLabel=");
+ addIndentOrComma(sb, indent);
+
+ sb.append("shortLabel=");
sb.append(secure ? "***" : mTitle);
sb.append(", resId=");
sb.append(mTitleResId);
@@ -1835,7 +1861,9 @@
sb.append(mTitleResName);
sb.append("]");
- sb.append(", longLabel=");
+ addIndentOrComma(sb, indent);
+
+ sb.append("longLabel=");
sb.append(secure ? "***" : mText);
sb.append(", resId=");
sb.append(mTextResId);
@@ -1843,7 +1871,9 @@
sb.append(mTextResName);
sb.append("]");
- sb.append(", disabledMessage=");
+ addIndentOrComma(sb, indent);
+
+ sb.append("disabledMessage=");
sb.append(secure ? "***" : mDisabledMessage);
sb.append(", resId=");
sb.append(mDisabledMessageResId);
@@ -1851,19 +1881,27 @@
sb.append(mDisabledMessageResName);
sb.append("]");
- sb.append(", categories=");
+ addIndentOrComma(sb, indent);
+
+ sb.append("categories=");
sb.append(mCategories);
- sb.append(", icon=");
+ addIndentOrComma(sb, indent);
+
+ sb.append("icon=");
sb.append(mIcon);
- sb.append(", rank=");
+ addIndentOrComma(sb, indent);
+
+ sb.append("rank=");
sb.append(mRank);
sb.append(", timestamp=");
sb.append(mLastChangedTimestamp);
- sb.append(", intents=");
+ addIndentOrComma(sb, indent);
+
+ sb.append("intents=");
if (mIntents == null) {
sb.append("null");
} else {
@@ -1885,12 +1923,15 @@
}
}
- sb.append(", extras=");
+ addIndentOrComma(sb, indent);
+
+ sb.append("extras=");
sb.append(mExtras);
if (includeInternalData) {
+ addIndentOrComma(sb, indent);
- sb.append(", iconRes=");
+ sb.append("iconRes=");
sb.append(mIconResId);
sb.append("[");
sb.append(mIconResName);
diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl
index a83d313..d8f9567 100644
--- a/core/java/android/os/IStatsCompanionService.aidl
+++ b/core/java/android/os/IStatsCompanionService.aidl
@@ -20,11 +20,11 @@
* Binder interface to communicate with the Java-based statistics service helper.
* {@hide}
*/
-oneway interface IStatsCompanionService {
+interface IStatsCompanionService {
/**
* Tell statscompanion that stastd is up and running.
*/
- void statsdReady();
+ oneway void statsdReady();
/**
* Register an alarm for anomaly detection to fire at the given timestamp (ms since epoch).
@@ -32,10 +32,10 @@
* Uses AlarmManager.set API, so if the timestamp is in the past, alarm fires immediately, and
* alarm is inexact.
*/
- void setAnomalyAlarm(long timestampMs);
+ oneway void setAnomalyAlarm(long timestampMs);
/** Cancel any anomaly detection alarm. */
- void cancelAnomalyAlarm();
+ oneway void cancelAnomalyAlarm();
/**
* Register a repeating alarm for polling to fire at the given timestamp and every
@@ -44,8 +44,11 @@
* Uses AlarmManager.setRepeating API, so if the timestamp is in past, alarm fires immediately,
* and alarm is inexact.
*/
- void setPollingAlarms(long timestampMs, long intervalMs);
+ oneway void setPollingAlarms(long timestampMs, long intervalMs);
/** Cancel any repeating polling alarm. */
- void cancelPollingAlarms();
+ oneway void cancelPollingAlarms();
+
+ /** Pull the specified data. Results will be sent to statsd when complete. */
+ String pullData(int pullCode);
}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 3726f47..7f4dee6 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -1412,7 +1412,11 @@
*/
public void release(int flags) {
synchronized (mToken) {
- mInternalCount--;
+ if (mInternalCount > 0) {
+ // internal count must only be decreased if it is > 0 or state of
+ // the WakeLock object is broken.
+ mInternalCount--;
+ }
if ((flags & RELEASE_FLAG_TIMEOUT) == 0) {
mExternalCount--;
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 3c3e466..eca2fcd 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10894,6 +10894,26 @@
*/
public static final String ENABLE_DELETION_HELPER_NO_THRESHOLD_TOGGLE =
"enable_deletion_helper_no_threshold_toggle";
+
+ /**
+ * The list of snooze options for notifications
+ * This is encoded as a key=value list, separated by commas. Ex:
+ *
+ * "default=60,options_array=15:30:60:120"
+ *
+ * The following keys are supported:
+ *
+ * <pre>
+ * default (int)
+ * options_array (string)
+ * </pre>
+ *
+ * All delays in integer minutes. Array order is respected.
+ * Options will be used in order up to the maximum allowed by the UI.
+ * @hide
+ */
+ public static final String NOTIFICATION_SNOOZE_OPTIONS =
+ "notification_snooze_options";
}
/**
diff --git a/core/java/android/service/settings/suggestions/Suggestion.java b/core/java/android/service/settings/suggestions/Suggestion.java
index f27cc2e..cfeb7fc 100644
--- a/core/java/android/service/settings/suggestions/Suggestion.java
+++ b/core/java/android/service/settings/suggestions/Suggestion.java
@@ -16,12 +16,17 @@
package android.service.settings.suggestions;
+import android.annotation.IntDef;
import android.annotation.SystemApi;
import android.app.PendingIntent;
+import android.graphics.drawable.Icon;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Data object that has information about a device suggestion.
*
@@ -30,9 +35,27 @@
@SystemApi
public final class Suggestion implements Parcelable {
+ /**
+ * @hide
+ */
+ @IntDef(flag = true, value = {
+ FLAG_HAS_BUTTON,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Flags {
+ }
+
+ /**
+ * Flag for suggestion type with a single button
+ */
+ public static final int FLAG_HAS_BUTTON = 1 << 0;
+
private final String mId;
private final CharSequence mTitle;
private final CharSequence mSummary;
+ private final Icon mIcon;
+ @Flags
+ private final int mFlags;
private final PendingIntent mPendingIntent;
/**
@@ -57,6 +80,22 @@
}
/**
+ * Optional icon for this suggestion.
+ */
+ public Icon getIcon() {
+ return mIcon;
+ }
+
+ /**
+ * Optional flags for this suggestion. This will influence UI when rendering suggestion in
+ * different style.
+ */
+ @Flags
+ public int getFlags() {
+ return mFlags;
+ }
+
+ /**
* The Intent to launch when the suggestion is activated.
*/
public PendingIntent getPendingIntent() {
@@ -67,6 +106,8 @@
mId = builder.mId;
mTitle = builder.mTitle;
mSummary = builder.mSummary;
+ mIcon = builder.mIcon;
+ mFlags = builder.mFlags;
mPendingIntent = builder.mPendingIntent;
}
@@ -74,6 +115,8 @@
mId = in.readString();
mTitle = in.readCharSequence();
mSummary = in.readCharSequence();
+ mIcon = in.readParcelable(Icon.class.getClassLoader());
+ mFlags = in.readInt();
mPendingIntent = in.readParcelable(PendingIntent.class.getClassLoader());
}
@@ -99,6 +142,8 @@
dest.writeString(mId);
dest.writeCharSequence(mTitle);
dest.writeCharSequence(mSummary);
+ dest.writeParcelable(mIcon, flags);
+ dest.writeInt(mFlags);
dest.writeParcelable(mPendingIntent, flags);
}
@@ -109,6 +154,9 @@
private final String mId;
private CharSequence mTitle;
private CharSequence mSummary;
+ private Icon mIcon;
+ @Flags
+ private int mFlags;
private PendingIntent mPendingIntent;
public Builder(String id) {
@@ -135,6 +183,23 @@
}
/**
+ * Sets icon for the suggestion.
+ */
+ public Builder setIcon(Icon icon) {
+ mIcon = icon;
+ return this;
+ }
+
+ /**
+ * Sets a UI type for this suggestion. This will influence UI when rendering suggestion in
+ * different style.
+ */
+ public Builder setFlags(@Flags int flags) {
+ mFlags = flags;
+ return this;
+ }
+
+ /**
* Sets suggestion intent
*/
public Builder setPendingIntent(PendingIntent pendingIntent) {
diff --git a/core/java/android/text/MeasuredText.java b/core/java/android/text/MeasuredText.java
index 9f54d8e..b09ccc2 100644
--- a/core/java/android/text/MeasuredText.java
+++ b/core/java/android/text/MeasuredText.java
@@ -90,10 +90,6 @@
}
}
- void setPos(int pos) {
- mPos = pos - mTextStart;
- }
-
/**
* Analyzes text for bidirectional runs. Allocates working buffers.
*/
@@ -160,47 +156,43 @@
}
}
+ /**
+ * Apply the style.
+ *
+ * If StaticLyaout.Builder is not provided in setPara() method, this method measures the styled
+ * text width.
+ * If StaticLayout.Builder is provided in setPara() method, this method just passes the style
+ * information to native code by calling StaticLayout.Builder.addstyleRun() and returns 0.
+ */
float addStyleRun(TextPaint paint, int len, Paint.FontMetricsInt fm) {
if (fm != null) {
paint.getFontMetricsInt(fm);
}
- int p = mPos;
+ final int p = mPos;
mPos = p + len;
- // try to do widths measurement in native code, but use Java if paint has been subclassed
- // FIXME: may want to eliminate special case for subclass
- float[] widths = null;
- if (mBuilder == null || paint.getClass() != TextPaint.class) {
- widths = mWidths;
- }
if (mEasy) {
- boolean isRtl = mDir != Layout.DIR_LEFT_TO_RIGHT;
- float width = 0;
- if (widths != null) {
- width = paint.getTextRunAdvances(mChars, p, len, p, len, isRtl, widths, p);
- if (mBuilder != null) {
- mBuilder.addMeasuredRun(paint, p, p + len, widths);
- }
+ final boolean isRtl = mDir != Layout.DIR_LEFT_TO_RIGHT;
+ if (mBuilder == null) {
+ return paint.getTextRunAdvances(mChars, p, len, p, len, isRtl, mWidths, p);
} else {
- width = mBuilder.addStyleRun(paint, p, p + len, isRtl);
+ mBuilder.addStyleRun(paint, p, p + len, isRtl);
+ return 0.0f; // Builder.addStyleRun doesn't return the width.
}
- return width;
}
float totalAdvance = 0;
int level = mLevels[p];
for (int q = p, i = p + 1, e = p + len;; ++i) {
if (i == e || mLevels[i] != level) {
- boolean isRtl = (level & 0x1) != 0;
- if (widths != null) {
+ final boolean isRtl = (level & 0x1) != 0;
+ if (mBuilder == null) {
totalAdvance +=
- paint.getTextRunAdvances(mChars, q, i - q, q, i - q, isRtl, widths, q);
- if (mBuilder != null) {
- mBuilder.addMeasuredRun(paint, q, i, widths);
- }
+ paint.getTextRunAdvances(mChars, q, i - q, q, i - q, isRtl, mWidths, q);
} else {
- totalAdvance += mBuilder.addStyleRun(paint, q, i, isRtl);
+ // Builder.addStyleRun doesn't return the width.
+ mBuilder.addStyleRun(paint, q, i, isRtl);
}
if (i == e) {
break;
@@ -209,7 +201,7 @@
level = mLevels[i];
}
}
- return totalAdvance;
+ return totalAdvance; // If mBuilder is null, the result is zero.
}
float addStyleRun(TextPaint paint, MetricAffectingSpan[] spans, int len,
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index e71ad5b..961cd8ee 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -431,7 +431,6 @@
* Then, for each run within the paragraph:
* - one of the following, depending on the type of run:
* + addStyleRun (a text run, to be measured in native code)
- * + addMeasuredRun (a run already measured in Java, passed into native code)
* + addReplacementRun (a replacement run, width is given)
*
* After measurement, nGetWidths() is valid if the widths are needed (eg for ellipsis).
@@ -454,15 +453,10 @@
}
}
- /* package */ float addStyleRun(TextPaint paint, int start, int end, boolean isRtl) {
+ /* package */ void addStyleRun(TextPaint paint, int start, int end, boolean isRtl) {
Pair<String, long[]> locHyph = getLocaleAndHyphenatorIfChanged(paint);
- return nAddStyleRun(mNativePtr, paint.getNativeInstance(), start, end, isRtl,
- locHyph.first, locHyph.second);
- }
-
- /* package */ void addMeasuredRun(TextPaint paint, int start, int end, float[] widths) {
- Pair<String, long[]> locHyph = getLocaleAndHyphenatorIfChanged(paint);
- nAddMeasuredRun(mNativePtr, start, end, widths, locHyph.first, locHyph.second);
+ nAddStyleRun(mNativePtr, paint.getNativeInstance(), start, end, isRtl, locHyph.first,
+ locHyph.second);
}
/* package */ void addReplacementRun(TextPaint paint, int start, int end, float width) {
@@ -1547,15 +1541,11 @@
@Nullable int[] indents, @Nullable int[] leftPaddings, @Nullable int[] rightPaddings,
@IntRange(from = 0) int indentsOffset);
- private static native float nAddStyleRun(
+ private static native void nAddStyleRun(
/* non-zero */ long nativePtr, /* non-zero */ long nativePaint,
@IntRange(from = 0) int start, @IntRange(from = 0) int end, boolean isRtl,
@Nullable String languageTags, @Nullable long[] hyphenators);
- private static native void nAddMeasuredRun(/* non-zero */ long nativePtr,
- @IntRange(from = 0) int start, @IntRange(from = 0) int end, @NonNull float[] widths,
- @Nullable String languageTags, @Nullable long[] hyphenators);
-
private static native void nAddReplacementRun(/* non-zero */ long nativePtr,
@IntRange(from = 0) int start, @IntRange(from = 0) int end,
@FloatRange(from = 0.0f) float width, @Nullable String languageTags,
diff --git a/core/java/android/transition/TransitionUtils.java b/core/java/android/transition/TransitionUtils.java
index 3306a50..084b79d 100644
--- a/core/java/android/transition/TransitionUtils.java
+++ b/core/java/android/transition/TransitionUtils.java
@@ -101,7 +101,7 @@
ImageView copy = new ImageView(view.getContext());
copy.setScaleType(ImageView.ScaleType.CENTER_CROP);
- Bitmap bitmap = createViewBitmap(view, matrix, bounds);
+ Bitmap bitmap = createViewBitmap(view, matrix, bounds, sceneRoot);
if (bitmap != null) {
copy.setImageBitmap(bitmap);
}
@@ -156,11 +156,18 @@
* returning.
* @param bounds The bounds of the bitmap in the destination coordinate system (where the
* view should be presented. Typically, this is matrix.mapRect(viewBounds);
+ * @param sceneRoot A ViewGroup that is attached to the window to temporarily contain the view
+ * if it isn't attached to the window.
* @return A bitmap of the given view or null if bounds has no width or height.
*/
- public static Bitmap createViewBitmap(View view, Matrix matrix, RectF bounds) {
- if (!view.isAttachedToWindow()) {
- return null;
+ public static Bitmap createViewBitmap(View view, Matrix matrix, RectF bounds,
+ ViewGroup sceneRoot) {
+ final boolean addToOverlay = !view.isAttachedToWindow();
+ if (addToOverlay) {
+ if (sceneRoot == null || !sceneRoot.isAttachedToWindow()) {
+ return null;
+ }
+ sceneRoot.getOverlay().add(view);
}
Bitmap bitmap = null;
int bitmapWidth = Math.round(bounds.width());
@@ -181,6 +188,9 @@
node.end(canvas);
bitmap = ThreadedRenderer.createHardwareBitmap(node, bitmapWidth, bitmapHeight);
}
+ if (addToOverlay) {
+ sceneRoot.getOverlay().remove(view);
+ }
return bitmap;
}
diff --git a/core/java/android/util/proto/ProtoOutputStream.java b/core/java/android/util/proto/ProtoOutputStream.java
index 9afa56d..49f8eea 100644
--- a/core/java/android/util/proto/ProtoOutputStream.java
+++ b/core/java/android/util/proto/ProtoOutputStream.java
@@ -2375,6 +2375,9 @@
if (countString == null) {
countString = "fieldCount=" + fieldCount;
}
+ if (countString.length() > 0) {
+ countString += " ";
+ }
final long fieldType = fieldId & FIELD_TYPE_MASK;
String typeString = getFieldTypeString(fieldType);
@@ -2382,7 +2385,7 @@
typeString = "fieldType=" + fieldType;
}
- return fieldCount + " " + typeString + " tag=" + ((int)fieldId)
+ return countString + typeString + " tag=" + ((int) fieldId)
+ " fieldId=0x" + Long.toHexString(fieldId);
}
diff --git a/core/java/android/util/proto/ProtoUtils.java b/core/java/android/util/proto/ProtoUtils.java
new file mode 100644
index 0000000..449baca
--- /dev/null
+++ b/core/java/android/util/proto/ProtoUtils.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.proto;
+
+import android.util.AggStats;
+
+/**
+ * This class contains a list of helper functions to write common proto in
+ * //frameworks/base/core/proto/android/base directory
+ */
+public class ProtoUtils {
+
+ /**
+ * Dump AggStats to ProtoOutputStream
+ * @hide
+ */
+ public static void toAggStatsProto(ProtoOutputStream proto, long fieldId,
+ long min, long average, long max) {
+ final long aggStatsToken = proto.start(fieldId);
+ proto.write(AggStats.MIN, min);
+ proto.write(AggStats.AVERAGE, average);
+ proto.write(AggStats.MAX, max);
+ proto.end(aggStatsToken);
+ }
+}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index d988d66..a346863 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -366,7 +366,7 @@
// These can be accessed by any thread, must be protected with a lock.
// Surface can never be reassigned or cleared (use Surface.clear()).
- final Surface mSurface = new Surface();
+ public final Surface mSurface = new Surface();
boolean mAdded;
boolean mAddedTouchMode;
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index 0ecd20d..f671c34 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -378,7 +378,7 @@
*
* <p>Typically used when the view is a container for an HTML document.
*
- * @param domain URL representing the domain; only the host part will be used.
+ * @param domain RFC 2396-compliant URI representing the domain.
*/
public abstract void setWebDomain(@Nullable String domain);
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 077a901..dfc81b2 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2972,8 +2972,12 @@
return webviewPackage;
}
+ IWebViewUpdateService service = WebViewFactory.getUpdateService();
+ if (service == null) {
+ return null;
+ }
try {
- return WebViewFactory.getUpdateService().getCurrentWebViewPackage();
+ return service.getCurrentWebViewPackage();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 994512f..4773cda 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -51,9 +51,6 @@
private static final String CHROMIUM_WEBVIEW_FACTORY_METHOD = "create";
- private static final String NULL_WEBVIEW_FACTORY =
- "com.android.webview.nullwebview.NullWebViewFactoryProvider";
-
public static final String CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY =
"persist.sys.webview.vmsize";
@@ -66,6 +63,7 @@
private static WebViewFactoryProvider sProviderInstance;
private static final Object sProviderLock = new Object();
private static PackageInfo sPackageInfo;
+ private static Boolean sWebViewSupported;
// Error codes for loadWebViewNativeLibraryFromPackage
public static final int LIBLOAD_SUCCESS = 0;
@@ -105,6 +103,16 @@
public MissingWebViewPackageException(Exception e) { super(e); }
}
+ private static boolean isWebViewSupported() {
+ // No lock; this is a benign race as Boolean's state is final and the PackageManager call
+ // will always return the same value.
+ if (sWebViewSupported == null) {
+ sWebViewSupported = AppGlobals.getInitialApplication().getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_WEBVIEW);
+ }
+ return sWebViewSupported;
+ }
+
/**
* @hide
*/
@@ -135,6 +143,10 @@
*/
public static int loadWebViewNativeLibraryFromPackage(String packageName,
ClassLoader clazzLoader) {
+ if (!isWebViewSupported()) {
+ return LIBLOAD_WRONG_PACKAGE_NAME;
+ }
+
WebViewProviderResponse response = null;
try {
response = getUpdateService().waitForAndGetProvider();
@@ -188,6 +200,11 @@
"For security reasons, WebView is not allowed in privileged processes");
}
+ if (!isWebViewSupported()) {
+ // Device doesn't support WebView; don't try to load it, just throw.
+ throw new UnsupportedOperationException();
+ }
+
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getProvider()");
try {
@@ -410,15 +427,6 @@
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
}
} catch (MissingWebViewPackageException e) {
- // If the package doesn't exist, then try loading the null WebView instead.
- // If that succeeds, then this is a device without WebView support; if it fails then
- // swallow the failure, complain that the real WebView is missing and rethrow the
- // original exception.
- try {
- return (Class<WebViewFactoryProvider>) Class.forName(NULL_WEBVIEW_FACTORY);
- } catch (ClassNotFoundException e2) {
- // Ignore.
- }
Log.e(LOGTAG, "Chromium WebView package does not exist", e);
throw new AndroidRuntimeException(e);
}
@@ -483,6 +491,15 @@
/** @hide */
public static IWebViewUpdateService getUpdateService() {
+ if (isWebViewSupported()) {
+ return getUpdateServiceUnchecked();
+ } else {
+ return null;
+ }
+ }
+
+ /** @hide */
+ static IWebViewUpdateService getUpdateServiceUnchecked() {
return IWebViewUpdateService.Stub.asInterface(
ServiceManager.getService(WEBVIEW_UPDATE_SERVICE_NAME));
}
diff --git a/core/java/android/webkit/WebViewLibraryLoader.java b/core/java/android/webkit/WebViewLibraryLoader.java
index 6f9e8ec..21316e7 100644
--- a/core/java/android/webkit/WebViewLibraryLoader.java
+++ b/core/java/android/webkit/WebViewLibraryLoader.java
@@ -80,7 +80,7 @@
} finally {
// We must do our best to always notify the update service, even if something fails.
try {
- WebViewFactory.getUpdateService().notifyRelroCreationCompleted();
+ WebViewFactory.getUpdateServiceUnchecked().notifyRelroCreationCompleted();
} catch (RemoteException e) {
Log.e(LOGTAG, "error notifying update service", e);
}
diff --git a/core/java/android/webkit/WebViewUpdateService.java b/core/java/android/webkit/WebViewUpdateService.java
index 2f7d685..629891c 100644
--- a/core/java/android/webkit/WebViewUpdateService.java
+++ b/core/java/android/webkit/WebViewUpdateService.java
@@ -31,8 +31,12 @@
* Fetch all packages that could potentially implement WebView.
*/
public static WebViewProviderInfo[] getAllWebViewPackages() {
+ IWebViewUpdateService service = getUpdateService();
+ if (service == null) {
+ return new WebViewProviderInfo[0];
+ }
try {
- return getUpdateService().getAllWebViewPackages();
+ return service.getAllWebViewPackages();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -42,8 +46,12 @@
* Fetch all packages that could potentially implement WebView and are currently valid.
*/
public static WebViewProviderInfo[] getValidWebViewPackages() {
+ IWebViewUpdateService service = getUpdateService();
+ if (service == null) {
+ return new WebViewProviderInfo[0];
+ }
try {
- return getUpdateService().getValidWebViewPackages();
+ return service.getValidWebViewPackages();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -53,8 +61,12 @@
* Used by DevelopmentSetting to get the name of the WebView provider currently in use.
*/
public static String getCurrentWebViewPackageName() {
+ IWebViewUpdateService service = getUpdateService();
+ if (service == null) {
+ return null;
+ }
try {
- return getUpdateService().getCurrentWebViewPackageName();
+ return service.getCurrentWebViewPackageName();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 0f61724..afd1188 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -119,6 +119,7 @@
import com.android.internal.util.GrowingArrayUtils;
import com.android.internal.util.Preconditions;
import com.android.internal.widget.EditableInputConnection;
+import com.android.internal.widget.Magnifier;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -138,6 +139,9 @@
public class Editor {
private static final String TAG = "Editor";
private static final boolean DEBUG_UNDO = false;
+ // Specifies whether to use or not the magnifier when pressing the insertion or selection
+ // handles.
+ private static final boolean FLAG_USE_MAGNIFIER = true;
static final int BLINK = 500;
private static final int DRAG_SHADOW_MAX_TEXT_LENGTH = 20;
@@ -161,6 +165,17 @@
private static final int MENU_ITEM_ORDER_PASTE_AS_PLAIN_TEXT = 11;
private static final int MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START = 100;
+ private static final float MAGNIFIER_ZOOM = 1.5f;
+ @IntDef({MagnifierHandleTrigger.SELECTION_START,
+ MagnifierHandleTrigger.SELECTION_END,
+ MagnifierHandleTrigger.INSERTION})
+ @Retention(RetentionPolicy.SOURCE)
+ private @interface MagnifierHandleTrigger {
+ int INSERTION = 0;
+ int SELECTION_START = 1;
+ int SELECTION_END = 2;
+ }
+
// Each Editor manages its own undo stack.
private final UndoManager mUndoManager = new UndoManager();
private UndoOwner mUndoOwner = mUndoManager.getOwner(UNDO_OWNER_TAG, this);
@@ -179,6 +194,8 @@
private final boolean mHapticTextHandleEnabled;
+ private final Magnifier mMagnifier;
+
// Used to highlight a word when it is corrected by the IME
private CorrectionHighlighter mCorrectionHighlighter;
@@ -250,7 +267,7 @@
SuggestionRangeSpan mSuggestionRangeSpan;
private Runnable mShowSuggestionRunnable;
- Drawable mCursorDrawable = null;
+ Drawable mDrawableForCursor = null;
private Drawable mSelectHandleLeft;
private Drawable mSelectHandleRight;
@@ -325,6 +342,8 @@
mProcessTextIntentActionsHandler = new ProcessTextIntentActionsHandler(this);
mHapticTextHandleEnabled = mTextView.getContext().getResources().getBoolean(
com.android.internal.R.bool.config_enableHapticTextHandle);
+
+ mMagnifier = FLAG_USE_MAGNIFIER ? new Magnifier(mTextView) : null;
}
ParcelableParcel saveInstanceState() {
@@ -1678,7 +1697,7 @@
mCorrectionHighlighter.draw(canvas, cursorOffsetVertical);
}
- if (highlight != null && selectionStart == selectionEnd && mCursorDrawable != null) {
+ if (highlight != null && selectionStart == selectionEnd && mDrawableForCursor != null) {
drawCursor(canvas, cursorOffsetVertical);
// Rely on the drawable entirely, do not draw the cursor line.
// Has to be done after the IMM related code above which relies on the highlight.
@@ -1873,8 +1892,8 @@
private void drawCursor(Canvas canvas, int cursorOffsetVertical) {
final boolean translate = cursorOffsetVertical != 0;
if (translate) canvas.translate(0, cursorOffsetVertical);
- if (mCursorDrawable != null) {
- mCursorDrawable.draw(canvas);
+ if (mDrawableForCursor != null) {
+ mDrawableForCursor.draw(canvas);
}
if (translate) canvas.translate(0, -cursorOffsetVertical);
}
@@ -1933,7 +1952,7 @@
void updateCursorPosition() {
if (mTextView.mCursorDrawableRes == 0) {
- mCursorDrawable = null;
+ mDrawableForCursor = null;
return;
}
@@ -2314,17 +2333,17 @@
@VisibleForTesting
@Nullable
public Drawable getCursorDrawable() {
- return mCursorDrawable;
+ return mDrawableForCursor;
}
private void updateCursorPosition(int top, int bottom, float horizontal) {
- if (mCursorDrawable == null) {
- mCursorDrawable = mTextView.getContext().getDrawable(
+ if (mDrawableForCursor == null) {
+ mDrawableForCursor = mTextView.getContext().getDrawable(
mTextView.mCursorDrawableRes);
}
- final int left = clampHorizontalPosition(mCursorDrawable, horizontal);
- final int width = mCursorDrawable.getIntrinsicWidth();
- mCursorDrawable.setBounds(left, top - mTempRect.top, left + width,
+ final int left = clampHorizontalPosition(mDrawableForCursor, horizontal);
+ final int width = mDrawableForCursor.getIntrinsicWidth();
+ mDrawableForCursor.setBounds(left, top - mTempRect.top, left + width,
bottom + mTempRect.bottom);
}
@@ -4353,6 +4372,9 @@
protected abstract void updatePosition(float x, float y, boolean fromTouchScreen);
+ @MagnifierHandleTrigger
+ protected abstract int getMagnifierHandleTrigger();
+
protected boolean isAtRtlRun(@NonNull Layout layout, int offset) {
return layout.isRtlCharAt(offset);
}
@@ -4490,6 +4512,53 @@
return 0;
}
+ protected final void showMagnifier() {
+ if (mMagnifier == null) {
+ return;
+ }
+
+ final int trigger = getMagnifierHandleTrigger();
+ final int offset;
+ switch (trigger) {
+ case MagnifierHandleTrigger.INSERTION: // Fall through.
+ case MagnifierHandleTrigger.SELECTION_START:
+ offset = mTextView.getSelectionStart();
+ break;
+ case MagnifierHandleTrigger.SELECTION_END:
+ offset = mTextView.getSelectionEnd();
+ break;
+ default:
+ offset = -1;
+ break;
+ }
+
+ if (offset == -1) {
+ dismissMagnifier();
+ }
+
+ final Layout layout = mTextView.getLayout();
+ final int lineNumber = layout.getLineForOffset(offset);
+ // Horizontally snap to character offset.
+ final float xPosInView = getHorizontal(mTextView.getLayout(), offset);
+ // Vertically snap to middle of current line.
+ final float yPosInView = (mTextView.getLayout().getLineTop(lineNumber)
+ + mTextView.getLayout().getLineBottom(lineNumber)) / 2.0f;
+ final int[] coordinatesOnScreen = new int[2];
+ mTextView.getLocationOnScreen(coordinatesOnScreen);
+ final float centerXOnScreen = xPosInView + mTextView.getTotalPaddingLeft()
+ - mTextView.getScrollX() + coordinatesOnScreen[0];
+ final float centerYOnScreen = yPosInView + mTextView.getTotalPaddingTop()
+ - mTextView.getScrollY() + coordinatesOnScreen[1];
+
+ mMagnifier.show(centerXOnScreen, centerYOnScreen, MAGNIFIER_ZOOM);
+ }
+
+ protected final void dismissMagnifier() {
+ if (mMagnifier != null) {
+ mMagnifier.dismiss();
+ }
+ }
+
@Override
public boolean onTouchEvent(MotionEvent ev) {
updateFloatingToolbarVisibility(ev);
@@ -4542,10 +4611,7 @@
case MotionEvent.ACTION_UP:
filterOnTouchUp(ev.isFromSource(InputDevice.SOURCE_TOUCHSCREEN));
- mIsDragging = false;
- updateDrawable();
- break;
-
+ // Fall through.
case MotionEvent.ACTION_CANCEL:
mIsDragging = false;
updateDrawable();
@@ -4646,9 +4712,9 @@
@Override
protected int getCursorOffset() {
int offset = super.getCursorOffset();
- if (mCursorDrawable != null) {
- mCursorDrawable.getPadding(mTempRect);
- offset += (mCursorDrawable.getIntrinsicWidth()
+ if (mDrawableForCursor != null) {
+ mDrawableForCursor.getPadding(mTempRect);
+ offset += (mDrawableForCursor.getIntrinsicWidth()
- mTempRect.left - mTempRect.right) / 2;
}
return offset;
@@ -4656,9 +4722,9 @@
@Override
int getCursorHorizontalPosition(Layout layout, int offset) {
- if (mCursorDrawable != null) {
+ if (mDrawableForCursor != null) {
final float horizontal = getHorizontal(layout, offset);
- return clampHorizontalPosition(mCursorDrawable, horizontal) + mTempRect.left;
+ return clampHorizontalPosition(mDrawableForCursor, horizontal) + mTempRect.left;
}
return super.getCursorHorizontalPosition(layout, offset);
}
@@ -4671,6 +4737,11 @@
case MotionEvent.ACTION_DOWN:
mDownPositionX = ev.getRawX();
mDownPositionY = ev.getRawY();
+ showMagnifier();
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ showMagnifier();
break;
case MotionEvent.ACTION_UP:
@@ -4696,11 +4767,10 @@
mTextActionMode.invalidateContentRect();
}
}
- hideAfterDelay();
- break;
-
+ // Fall through.
case MotionEvent.ACTION_CANCEL:
hideAfterDelay();
+ dismissMagnifier();
break;
default:
@@ -4751,6 +4821,12 @@
super.onDetached();
removeHiderCallback();
}
+
+ @Override
+ @MagnifierHandleTrigger
+ protected int getMagnifierHandleTrigger() {
+ return MagnifierHandleTrigger.INSERTION;
+ }
}
@Retention(RetentionPolicy.SOURCE)
@@ -5009,12 +5085,26 @@
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean superResult = super.onTouchEvent(event);
- if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
- // Reset the touch word offset and x value when the user
- // re-engages the handle.
- mTouchWordDelta = 0.0f;
- mPrevX = UNSET_X_VALUE;
+
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ // Reset the touch word offset and x value when the user
+ // re-engages the handle.
+ mTouchWordDelta = 0.0f;
+ mPrevX = UNSET_X_VALUE;
+ showMagnifier();
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ showMagnifier();
+ break;
+
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ dismissMagnifier();
+ break;
}
+
return superResult;
}
@@ -5110,6 +5200,13 @@
return isRtlChar == isRtlParagraph ? primaryOffset : secondaryOffset;
}
}
+
+ @MagnifierHandleTrigger
+ protected int getMagnifierHandleTrigger() {
+ return isStartHandle()
+ ? MagnifierHandleTrigger.SELECTION_START
+ : MagnifierHandleTrigger.SELECTION_END;
+ }
}
private int getCurrentLineAdjustedForSlop(Layout layout, int prevLine, float y) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 791a8fa..24ae03c 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -6281,7 +6281,7 @@
final int horizontalPadding = getCompoundPaddingLeft();
final int verticalPadding = getExtendedPaddingTop() + getVerticalOffset(true);
- if (mEditor.mCursorDrawable == null) {
+ if (mEditor.mDrawableForCursor == null) {
synchronized (TEMP_RECTF) {
/*
* The reason for this concern about the thickness of the
@@ -6308,7 +6308,7 @@
(int) Math.ceil(verticalPadding + TEMP_RECTF.bottom + thick));
}
} else {
- final Rect bounds = mEditor.mCursorDrawable.getBounds();
+ final Rect bounds = mEditor.mDrawableForCursor.getBounds();
invalidate(bounds.left + horizontalPadding, bounds.top + verticalPadding,
bounds.right + horizontalPadding, bounds.bottom + verticalPadding);
}
@@ -6360,8 +6360,8 @@
int bottom = mLayout.getLineBottom(lineEnd);
// mEditor can be null in case selection is set programmatically.
- if (invalidateCursor && mEditor != null && mEditor.mCursorDrawable != null) {
- final Rect bounds = mEditor.mCursorDrawable.getBounds();
+ if (invalidateCursor && mEditor != null && mEditor.mDrawableForCursor != null) {
+ final Rect bounds = mEditor.mDrawableForCursor.getBounds();
top = Math.min(top, bounds.top);
bottom = Math.max(bottom, bounds.bottom);
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index eb639bd..6e0ba341 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -100,7 +100,7 @@
private static final boolean DEBUG = false;
private static final int QUERY_TARGET_SERVICE_LIMIT = 5;
- private static final int WATCHDOG_TIMEOUT_MILLIS = 5000;
+ private static final int WATCHDOG_TIMEOUT_MILLIS = 2000;
private Bundle mReplacementExtras;
private IntentSender mChosenComponentSender;
@@ -1585,8 +1585,8 @@
} catch (RemoteException e) {
Log.e(TAG, "Querying ChooserTargetService " + name + " failed.", e);
mChooserActivity.unbindService(this);
- destroy();
mChooserActivity.mServiceConnections.remove(this);
+ destroy();
}
}
}
@@ -1602,7 +1602,6 @@
}
mChooserActivity.unbindService(this);
- destroy();
mChooserActivity.mServiceConnections.remove(this);
if (mChooserActivity.mServiceConnections.isEmpty()) {
mChooserActivity.mChooserHandler.removeMessages(
@@ -1610,6 +1609,7 @@
mChooserActivity.sendVoiceChoicesIfNeeded();
}
mConnectedComponent = null;
+ destroy();
}
}
diff --git a/core/java/com/android/internal/app/procstats/DumpUtils.java b/core/java/com/android/internal/app/procstats/DumpUtils.java
index ebedc89..0bc8c483 100644
--- a/core/java/com/android/internal/app/procstats/DumpUtils.java
+++ b/core/java/com/android/internal/app/procstats/DumpUtils.java
@@ -29,6 +29,7 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
import static com.android.internal.app.procstats.ProcessStats.*;
@@ -66,6 +67,8 @@
"cch-activity", "cch-aclient", "cch-empty"
};
+ // State enum is defined in frameworks/base/core/proto/android/service/procstats.proto
+ // Update states must sync enum definition as well, the ordering must not be changed.
static final String[] ADJ_SCREEN_TAGS = new String[] {
"0", "1"
};
@@ -177,6 +180,13 @@
printArrayEntry(pw, STATE_TAGS, state, 1);
}
+ public static void printProcStateTagProto(ProtoOutputStream proto, long screenId, long memId,
+ long stateId, int state) {
+ state = printProto(proto, screenId, ADJ_SCREEN_TAGS, state, ADJ_SCREEN_MOD * STATE_COUNT);
+ state = printProto(proto, memId, ADJ_MEM_TAGS, state, STATE_COUNT);
+ printProto(proto, stateId, STATE_TAGS, state, 1);
+ }
+
public static void printAdjTag(PrintWriter pw, int state) {
state = printArrayEntry(pw, ADJ_SCREEN_TAGS, state, ADJ_SCREEN_MOD);
printArrayEntry(pw, ADJ_MEM_TAGS, state, 1);
@@ -352,6 +362,15 @@
return value - index*mod;
}
+ public static int printProto(ProtoOutputStream proto, long fieldId, String[] array, int value, int mod) {
+ int index = value/mod;
+ if (index >= 0 && index < array.length) {
+ // Valid state enum number starts at 1, 0 stands for unknown.
+ proto.write(fieldId, index + 1);
+ } // else enum default is always zero in proto3
+ return value - index*mod;
+ }
+
public static String collapseString(String pkgName, String itemName) {
if (itemName.startsWith(pkgName)) {
final int ITEMLEN = itemName.length();
diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
index e0a4053..42c051d 100644
--- a/core/java/com/android/internal/app/procstats/ProcessState.java
+++ b/core/java/com/android/internal/app/procstats/ProcessState.java
@@ -21,6 +21,8 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.service.pm.PackageProto;
+import android.service.procstats.ProcessStatsProto;
import android.text.format.DateFormat;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -29,6 +31,8 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
+import android.util.proto.ProtoUtils;
import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.app.procstats.ProcessStats.PackageState;
@@ -69,6 +73,9 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import java.util.Objects;
public final class ProcessState {
@@ -1157,6 +1164,7 @@
}
}
+ @Override
public String toString() {
StringBuilder sb = new StringBuilder(128);
sb.append("ProcessState{").append(Integer.toHexString(System.identityHashCode(this)))
@@ -1167,4 +1175,77 @@
sb.append("}");
return sb.toString();
}
+
+ public void toProto(ProtoOutputStream proto, String procName, int uid, long now) {
+ proto.write(ProcessStatsProto.PROCESS, procName);
+ proto.write(ProcessStatsProto.UID, uid);
+ if (mNumExcessiveCpu > 0 || mNumCachedKill > 0 ) {
+ final long killToken = proto.start(ProcessStatsProto.KILL);
+ proto.write(ProcessStatsProto.Kill.WAKES, mNumExcessiveWake);
+ proto.write(ProcessStatsProto.Kill.CPU, mNumExcessiveCpu);
+ proto.write(ProcessStatsProto.Kill.CACHED, mNumCachedKill);
+ ProtoUtils.toAggStatsProto(proto, ProcessStatsProto.Kill.CACHED_PSS,
+ mMinCachedKillPss, mAvgCachedKillPss, mMaxCachedKillPss);
+ proto.end(killToken);
+ }
+
+ // Group proc stats by type (screen state + mem state + process state)
+ Map<Integer, Long> durationByState = new HashMap<>();
+ boolean didCurState = false;
+ for (int i=0; i<mDurations.getKeyCount(); i++) {
+ final int key = mDurations.getKeyAt(i);
+ final int type = SparseMappingTable.getIdFromKey(key);
+ long time = mDurations.getValue(key);
+ if (mCurState == type) {
+ didCurState = true;
+ time += now - mStartTime;
+ }
+ durationByState.put(type, time);
+ }
+ if (!didCurState && mCurState != STATE_NOTHING) {
+ durationByState.put(mCurState, now - mStartTime);
+ }
+
+ for (int i=0; i<mPssTable.getKeyCount(); i++) {
+ final int key = mPssTable.getKeyAt(i);
+ final int type = SparseMappingTable.getIdFromKey(key);
+ if (!durationByState.containsKey(type)) {
+ // state without duration should not have stats!
+ continue;
+ }
+ final long stateToken = proto.start(ProcessStatsProto.STATES);
+ DumpUtils.printProcStateTagProto(proto,
+ ProcessStatsProto.State.SCREEN_STATE,
+ ProcessStatsProto.State.MEMORY_STATE,
+ ProcessStatsProto.State.PROCESS_STATE,
+ type);
+
+ long duration = durationByState.get(type);
+ durationByState.remove(type); // remove the key since it is already being dumped.
+ proto.write(ProcessStatsProto.State.DURATION_MS, duration);
+
+ proto.write(ProcessStatsProto.State.SAMPLE_SIZE, mPssTable.getValue(key, PSS_SAMPLE_COUNT));
+ ProtoUtils.toAggStatsProto(proto, ProcessStatsProto.State.PSS,
+ mPssTable.getValue(key, PSS_MINIMUM),
+ mPssTable.getValue(key, PSS_AVERAGE),
+ mPssTable.getValue(key, PSS_MAXIMUM));
+ ProtoUtils.toAggStatsProto(proto, ProcessStatsProto.State.USS,
+ mPssTable.getValue(key, PSS_USS_MINIMUM),
+ mPssTable.getValue(key, PSS_USS_AVERAGE),
+ mPssTable.getValue(key, PSS_USS_MAXIMUM));
+
+ proto.end(stateToken);
+ }
+
+ for (Map.Entry<Integer, Long> entry : durationByState.entrySet()) {
+ final long stateToken = proto.start(ProcessStatsProto.STATES);
+ DumpUtils.printProcStateTagProto(proto,
+ ProcessStatsProto.State.SCREEN_STATE,
+ ProcessStatsProto.State.MEMORY_STATE,
+ ProcessStatsProto.State.PROCESS_STATE,
+ entry.getKey());
+ proto.write(ProcessStatsProto.State.DURATION_MS, entry.getValue());
+ proto.end(stateToken);
+ }
+ }
}
diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java
index 35b53c2..14f5e5b 100644
--- a/core/java/com/android/internal/app/procstats/ProcessStats.java
+++ b/core/java/com/android/internal/app/procstats/ProcessStats.java
@@ -22,6 +22,7 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.service.procstats.ProcessStatsSectionProto;
import android.text.format.DateFormat;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -30,6 +31,7 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.app.ProcessMap;
import com.android.internal.app.procstats.DurationsTable;
@@ -1706,6 +1708,46 @@
}
}
+ public void toProto(ProtoOutputStream proto, long now) {
+ final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
+
+ proto.write(ProcessStatsSectionProto.START_REALTIME_MS, mTimePeriodStartRealtime);
+ proto.write(ProcessStatsSectionProto.END_REALTIME_MS,
+ mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime);
+ proto.write(ProcessStatsSectionProto.START_UPTIME_MS, mTimePeriodStartUptime);
+ proto.write(ProcessStatsSectionProto.END_UPTIME_MS, mTimePeriodEndUptime);
+ proto.write(ProcessStatsSectionProto.RUNTIME, mRuntime);
+ proto.write(ProcessStatsSectionProto.HAS_SWAPPED_PSS, mHasSwappedOutPss);
+ boolean partial = true;
+ if ((mFlags&FLAG_SHUTDOWN) != 0) {
+ proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_SHUTDOWN);
+ partial = false;
+ }
+ if ((mFlags&FLAG_SYSPROPS) != 0) {
+ proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_SYSPROPS);
+ partial = false;
+ }
+ if ((mFlags&FLAG_COMPLETE) != 0) {
+ proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_COMPLETE);
+ partial = false;
+ }
+ if (partial) {
+ proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_PARTIAL);
+ }
+
+ ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+ for (int ip=0; ip<procMap.size(); ip++) {
+ String procName = procMap.keyAt(ip);
+ SparseArray<ProcessState> uids = procMap.valueAt(ip);
+ for (int iu=0; iu<uids.size(); iu++) {
+ final int uid = uids.keyAt(iu);
+ final ProcessState procState = uids.valueAt(iu);
+ final long processStateToken = proto.start(ProcessStatsSectionProto.PROCESS_STATS);
+ procState.toProto(proto, procName, uid, now);
+ proto.end(processStateToken);
+ }
+ }
+ }
final public static class ProcessStateHolder {
public final int appVersion;
diff --git a/core/java/com/android/internal/widget/Magnifier.java b/core/java/com/android/internal/widget/Magnifier.java
new file mode 100644
index 0000000..86e7b38
--- /dev/null
+++ b/core/java/com/android/internal/widget/Magnifier.java
@@ -0,0 +1,184 @@
+/*
+ * 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.internal.widget;
+
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
+import android.annotation.UiThread;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.PixelCopy;
+import android.view.View;
+import android.view.ViewRootImpl;
+import android.widget.ImageView;
+import android.widget.PopupWindow;
+
+import com.android.internal.R;
+import com.android.internal.util.Preconditions;
+
+/**
+ * Android magnifier widget. Can be used by any view which is attached to window.
+ */
+public final class Magnifier {
+ private static final String LOG_TAG = "magnifier";
+ // The view for which this magnifier is attached.
+ private final View mView;
+ // The window containing the magnifier.
+ private final PopupWindow mWindow;
+ // The center coordinates of the window containing the magnifier.
+ private final Point mWindowCoords = new Point();
+ // The width of the window containing the magnifier.
+ private final int mWindowWidth;
+ // The height of the window containing the magnifier.
+ private final int mWindowHeight;
+ // The bitmap used to display the contents of the magnifier.
+ private final Bitmap mBitmap;
+ // The center coordinates of the content that is to be magnified.
+ private final Point mCenterZoomCoords = new Point();
+ // The callback of the pixel copy request will be invoked on this Handler when
+ // the copy is finished.
+ private final Handler mPixelCopyHandler = Handler.getMain();
+
+ /**
+ * Initializes a magnifier.
+ *
+ * @param view the view for which this magnifier is attached
+ */
+ @UiThread
+ public Magnifier(@NonNull View view) {
+ mView = Preconditions.checkNotNull(view);
+ final Context context = mView.getContext();
+ final View content = LayoutInflater.from(context).inflate(R.layout.magnifier, null);
+ mWindowWidth = context.getResources().getDimensionPixelSize(R.dimen.magnifier_width);
+ mWindowHeight = context.getResources().getDimensionPixelSize(R.dimen.magnifier_height);
+ final float elevation = context.getResources().getDimension(R.dimen.magnifier_elevation);
+
+ mWindow = new PopupWindow(context);
+ mWindow.setContentView(content);
+ mWindow.setWidth(mWindowWidth);
+ mWindow.setHeight(mWindowHeight);
+ mWindow.setElevation(elevation);
+ mWindow.setTouchable(false);
+ mWindow.setBackgroundDrawable(null);
+
+ mBitmap = Bitmap.createBitmap(mWindowWidth, mWindowHeight, Bitmap.Config.ARGB_8888);
+ getImageView().setImageBitmap(mBitmap);
+ }
+
+ /**
+ * Shows the magnifier on the screen.
+ *
+ * @param centerXOnScreen horizontal coordinate of the center point of the magnifier source
+ * @param centerYOnScreen vertical coordinate of the center point of the magnifier source
+ * @param scale the scale at which the magnifier zooms on the source content
+ */
+ public void show(@FloatRange(from=0) float centerXOnScreen,
+ @FloatRange(from=0) float centerYOnScreen,
+ @FloatRange(from=1, to=10) float scale) {
+ maybeResizeBitmap(scale);
+ configureCoordinates(centerXOnScreen, centerYOnScreen);
+ performPixelCopy();
+
+ if (mWindow.isShowing()) {
+ mWindow.update(mWindowCoords.x, mWindowCoords.y, mWindow.getWidth(),
+ mWindow.getHeight());
+ } else {
+ mWindow.showAtLocation(mView.getRootView(), Gravity.NO_GRAVITY,
+ mWindowCoords.x, mWindowCoords.y);
+ }
+ }
+
+ /**
+ * Dismisses the magnifier from the screen.
+ */
+ public void dismiss() {
+ mWindow.dismiss();
+ }
+
+ /**
+ * @return the height of the magnifier window.
+ */
+ public int getHeight() {
+ return mWindowHeight;
+ }
+
+ /**
+ * @return the width of the magnifier window.
+ */
+ public int getWidth() {
+ return mWindowWidth;
+ }
+
+ private void maybeResizeBitmap(float scale) {
+ final int bitmapWidth = (int) (mWindowWidth / scale);
+ final int bitmapHeight = (int) (mWindowHeight / scale);
+ if (mBitmap.getWidth() != bitmapWidth || mBitmap.getHeight() != bitmapHeight) {
+ mBitmap.reconfigure(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
+ getImageView().setImageBitmap(mBitmap);
+ }
+ }
+
+ private void configureCoordinates(float posXOnScreen, float posYOnScreen) {
+ mCenterZoomCoords.x = (int) posXOnScreen;
+ mCenterZoomCoords.y = (int) posYOnScreen;
+
+ final int verticalMagnifierOffset = mView.getContext().getResources().getDimensionPixelSize(
+ R.dimen.magnifier_offset);
+ final int availableTopSpace = (mCenterZoomCoords.y - mWindowHeight / 2)
+ - verticalMagnifierOffset - (mBitmap.getHeight() / 2);
+
+ mWindowCoords.x = mCenterZoomCoords.x - mWindowWidth / 2;
+ mWindowCoords.y = mCenterZoomCoords.y - mWindowHeight / 2
+ + verticalMagnifierOffset * (availableTopSpace > 0 ? -1 : 1);
+ }
+
+ private void performPixelCopy() {
+ int startX = mCenterZoomCoords.x - mBitmap.getWidth() / 2;
+ // Clamp startX value to avoid distorting the rendering of the magnifier content.
+ if (startX < 0) {
+ startX = 0;
+ } else if (startX + mBitmap.getWidth() > mView.getWidth()) {
+ startX = mView.getWidth() - mBitmap.getWidth();
+ }
+
+ final int startY = mCenterZoomCoords.y - mBitmap.getHeight() / 2;
+ final ViewRootImpl viewRootImpl = mView.getViewRootImpl();
+
+ if (viewRootImpl != null && viewRootImpl.mSurface != null
+ && viewRootImpl.mSurface.isValid()) {
+ PixelCopy.request(
+ viewRootImpl.mSurface,
+ new Rect(startX, startY, startX + mBitmap.getWidth(),
+ startY + mBitmap.getHeight()),
+ mBitmap,
+ result -> getImageView().invalidate(),
+ mPixelCopyHandler);
+ } else {
+ Log.d(LOG_TAG, "Could not perform PixelCopy request");
+ }
+ }
+
+ private ImageView getImageView() {
+ return mWindow.getContentView().findViewById(R.id.magnifier_image);
+ }
+}
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index eb3bf8a..83ffeff 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -234,7 +234,7 @@
}
// Basically similar to Paint.getTextRunAdvances but with C++ interface
-static jfloat nAddStyleRun(JNIEnv* env, jclass, jlong nativePtr, jlong nativePaint, jint start,
+static void nAddStyleRun(JNIEnv* env, jclass, jlong nativePtr, jlong nativePaint, jint start,
jint end, jboolean isRtl, jstring langTags, jlongArray hyphenators) {
minikin::LineBreaker* b = reinterpret_cast<minikin::LineBreaker*>(nativePtr);
Paint* paint = reinterpret_cast<Paint*>(nativePaint);
@@ -245,20 +245,8 @@
typeface);
ScopedNullableUtfString langTagsString(env, langTags);
- float result = b->addStyleRun(&minikinPaint, resolvedTypeface->fFontCollection, style, start,
+ b->addStyleRun(&minikinPaint, resolvedTypeface->fFontCollection, style, start,
end, isRtl, langTagsString.get(), makeHyphenators(env, hyphenators));
- return result;
-}
-
-// Accept width measurements for the run, passed in from Java
-static void nAddMeasuredRun(JNIEnv* env, jclass, jlong nativePtr,
- jint start, jint end, jfloatArray widths, jstring langTags, jlongArray hyphenators) {
- minikin::LineBreaker* b = reinterpret_cast<minikin::LineBreaker*>(nativePtr);
- env->GetFloatArrayRegion(widths, start, end - start, b->charWidths() + start);
-
- ScopedNullableUtfString langTagsString(env, langTags);
- b->addStyleRun(nullptr, nullptr, minikin::FontStyle{}, start, end, false,
- langTagsString.get(), makeHyphenators(env, hyphenators));
}
static void nAddReplacementRun(JNIEnv* env, jclass, jlong nativePtr,
@@ -279,8 +267,7 @@
{"nFreeBuilder", "(J)V", (void*) nFreeBuilder},
{"nFinishBuilder", "(J)V", (void*) nFinishBuilder},
{"nSetupParagraph", "(J[CIFIF[IIIIZ[I[I[II)V", (void*) nSetupParagraph},
- {"nAddStyleRun", "(JJIIZLjava/lang/String;[J)F", (void*) nAddStyleRun},
- {"nAddMeasuredRun", "(JII[FLjava/lang/String;[J)V", (void*) nAddMeasuredRun},
+ {"nAddStyleRun", "(JJIIZLjava/lang/String;[J)V", (void*) nAddStyleRun},
{"nAddReplacementRun", "(JIIFLjava/lang/String;[J)V", (void*) nAddReplacementRun},
{"nGetWidths", "(J[F)V", (void*) nGetWidths},
{"nComputeLineBreaks", "(JLandroid/text/StaticLayout$LineBreaks;[I[F[F[F[II)I",
diff --git a/core/proto/android/app/notification_channel.proto b/core/proto/android/app/notification_channel.proto
new file mode 100644
index 0000000..bbc1956
--- /dev/null
+++ b/core/proto/android/app/notification_channel.proto
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+option java_package = "android.app";
+option java_multiple_files = true;
+
+package android.app;
+
+import "frameworks/base/core/proto/android/media/audioattributes.proto";
+
+/**
+ * An android.app.NotificationChannel object.
+ */
+message NotificationChannelProto {
+ string id = 1;
+ string name = 2;
+ string description = 3;
+ int32 importance = 4;
+ bool can_bypass_dnd = 5;
+ // Default is VISIBILITY_NO_OVERRIDE (-1000).
+ int32 lockscreen_visibility = 6;
+ string sound = 7;
+ bool use_lights = 8;
+ // Default is 0.
+ int32 light_color = 9;
+ repeated int64 vibration = 10;
+ // Bitwise representation of fields that have been changed by the user,
+ // preventing the app from making changes to these fields.
+ int32 user_locked_fields = 11;
+ bool is_vibration_enabled = 12;
+ // Default is true.
+ bool show_badge = 13;
+ // Default is false.
+ bool is_deleted = 14;
+ string group = 15;
+ android.media.AudioAttributesProto audio_attributes = 16;
+ // If this is a blockable system notification channel.
+ bool is_blockable_system = 17;
+}
diff --git a/core/proto/android/app/notification_channel_group.proto b/core/proto/android/app/notification_channel_group.proto
new file mode 100644
index 0000000..9cb456f
--- /dev/null
+++ b/core/proto/android/app/notification_channel_group.proto
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+option java_package = "android.app";
+option java_multiple_files = true;
+
+package android.app;
+
+import "frameworks/base/core/proto/android/app/notification_channel.proto";
+
+/**
+ * An android.app.NotificationChannelGroup object.
+ */
+message NotificationChannelGroupProto {
+ string id = 1;
+ string name = 2;
+ string description = 3;
+ bool is_blocked = 4;
+ repeated android.app.NotificationChannelProto channels = 5;
+}
diff --git a/core/proto/android/media/audioattributes.proto b/core/proto/android/media/audioattributes.proto
new file mode 100644
index 0000000..3aa2792
--- /dev/null
+++ b/core/proto/android/media/audioattributes.proto
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+option java_package = "android.media";
+option java_multiple_files = true;
+
+package android.media;
+
+/**
+ * An android.media.AudioAttributes object.
+ */
+message AudioAttributesProto {
+ Usage usage = 1;
+ ContentType content_type = 2;
+ // Bit representation of set flags.
+ int32 flags = 3;
+ repeated string tags = 4;
+}
+
+enum ContentType {
+ // Content type value to use when the content type is unknown, or other than
+ // the ones defined.
+ CONTENT_TYPE_UNKNOWN = 0;
+ // Content type value to use when the content type is speech.
+ SPEECH = 1;
+ // Content type value to use when the content type is music.
+ MUSIC = 2;
+ // Content type value to use when the content type is a soundtrack,
+ // typically accompanying a movie or TV program.
+ MOVIE = 3;
+ // Content type value to use when the content type is a sound used to
+ // accompany a user action, such as a beep or sound effect expressing a key
+ // click, or event, such as the type of a sound for a bonus being received
+ // in a game. These sounds are mostly synthesized or short Foley sounds.
+ SONIFICATION = 4;
+}
+
+enum Usage {
+ // Usage value to use when the usage is unknown.
+ USAGE_UNKNOWN = 0;
+ // Usage value to use when the usage is media, such as music, or movie
+ // soundtracks.
+ MEDIA = 1;
+ // Usage value to use when the usage is voice communications, such as
+ // telephony or VoIP.
+ VOICE_COMMUNICATION = 2;
+ // Usage value to use when the usage is in-call signalling, such as with a
+ // "busy" beep, or DTMF tones.
+ VOICE_COMMUNICATION_SIGNALLING = 3;
+ // Usage value to use when the usage is an alarm (e.g. wake-up alarm).
+ ALARM = 4;
+ // Usage value to use when the usage is notification. Other notification
+ // usages are for more specialized uses.
+ NOTIFICATION = 5;
+ // Usage value to use when the usage is telephony ringtone.
+ NOTIFICATION_RINGTONE = 6;
+ // Usage value to use when the usage is a request to enter/end a
+ // communication, such as a VoIP communication or video-conference.
+ NOTIFICATION_COMMUNICATION_REQUEST = 7;
+ // Usage value to use when the usage is notification for an "instant"
+ // communication such as a chat, or SMS.
+ NOTIFICATION_COMMUNICATION_INSTANT = 8;
+ // Usage value to use when the usage is notification for a non-immediate
+ // type of communication such as e-mail.
+ NOTIFICATION_COMMUNICATION_DELAYED = 9;
+ // Usage value to use when the usage is to attract the user's attention,
+ // such as a reminder or low battery warning.
+ NOTIFICATION_EVENT = 10;
+ // Usage value to use when the usage is for accessibility, such as with a
+ // screen reader.
+ ASSISTANCE_ACCESSIBILITY = 11;
+ // Usage value to use when the usage is driving or navigation directions.
+ ASSISTANCE_NAVIGATION_GUIDANCE = 12;
+ // Usage value to use when the usage is sonification, such as with user
+ // interface sounds.
+ ASSISTANCE_SONIFICATION = 13;
+ // Usage value to use when the usage is for game audio.
+ GAME = 14;
+ // Usage value to use when feeding audio to the platform and replacing
+ // "traditional" audio source, such as audio capture devices.
+ VIRTUAL_SOURCE = 15;
+ // Usage value to use for audio responses to user queries, audio
+ // instructions or help utterances.
+ ASSISTANT = 16;
+}
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index e823561..c3ceb1c 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -30,6 +30,7 @@
import "frameworks/base/core/proto/android/service/package.proto";
import "frameworks/base/core/proto/android/service/power.proto";
import "frameworks/base/core/proto/android/service/print.proto";
+import "frameworks/base/core/proto/android/service/procstats.proto";
import "frameworks/base/core/proto/android/providers/settings.proto";
import "frameworks/base/core/proto/android/os/incidentheader.proto";
import "frameworks/base/core/proto/android/os/kernelwake.proto";
@@ -96,4 +97,9 @@
android.service.pm.PackageServiceDumpProto package = 3008;
android.service.power.PowerServiceDumpProto power = 3009;
android.service.print.PrintServiceDumpProto print = 3010;
+
+ android.service.procstats.ProcessStatsServiceDumpProto procstats = 3011 [
+ (section).type = SECTION_DUMPSYS,
+ (section).args = "procstats --proto"
+ ];
}
diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto
index 05afe52..d8cb1a7 100644
--- a/core/proto/android/service/notification.proto
+++ b/core/proto/android/service/notification.proto
@@ -21,6 +21,8 @@
option java_multiple_files = true;
option java_outer_classname = "NotificationServiceProto";
+import "frameworks/base/core/proto/android/app/notification_channel.proto";
+import "frameworks/base/core/proto/android/app/notification_channel_group.proto";
import "frameworks/base/core/proto/android/app/notificationmanager.proto";
import "frameworks/base/core/proto/android/content/component_name.proto";
@@ -38,6 +40,8 @@
ManagedServicesProto notification_assistants = 6;
ManagedServicesProto condition_providers = 7;
+
+ RankingHelperProto ranking_config = 8;
}
message NotificationRecordProto {
@@ -86,6 +90,28 @@
repeated android.content.ComponentNameProto snoozed = 5;
}
+message RankingHelperProto {
+ repeated string notification_signal_extractors = 1;
+
+ message RecordProto {
+ string package = 1;
+ // Default value is UNKNOWN_UID = USER_NULL = -10000.
+ int32 uid = 2;
+ // Default is IMPORTANCE_UNSPECIFIED (-1000).
+ int32 importance = 3;
+ // Default is PRIORITY_DEFAULT (0).
+ int32 priority = 4;
+ // Default is VISIBILITY_NO_OVERRIDE (-1000).
+ int32 visibility = 5;
+ // Default is true.
+ bool show_badge = 6;
+ repeated android.app.NotificationChannelProto channels = 7;
+ repeated android.app.NotificationChannelGroupProto channel_groups = 8;
+ }
+ repeated RecordProto records = 2;
+ repeated RecordProto records_restored_without_uid = 3;
+}
+
enum State {
ENQUEUED = 0;
diff --git a/core/proto/android/service/procstats.proto b/core/proto/android/service/procstats.proto
new file mode 100644
index 0000000..885150e
--- /dev/null
+++ b/core/proto/android/service/procstats.proto
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+option java_multiple_files = true;
+option java_outer_classname = "ProcessStatsServiceProto";
+
+import "frameworks/base/core/proto/android/util/common.proto";
+
+package android.service.procstats;
+
+/**
+ * Data from ProcStatsService Dumpsys
+ *
+ * Next Tag: 4
+ */
+message ProcessStatsServiceDumpProto {
+
+ ProcessStatsSectionProto procstats_now = 1;
+
+ ProcessStatsSectionProto procstats_over_3hrs = 2;
+
+ ProcessStatsSectionProto procstats_over_24hrs = 3;
+}
+
+/**
+ * Data model from /frameworks/base/core/java/com/android/internal/app/procstats/ProcessStats.java
+ * This proto is defined based on the writeToParcel method.
+ *
+ * Next Tag: 9
+ */
+message ProcessStatsSectionProto {
+
+ // Elapsed realtime at start of report.
+ int64 start_realtime_ms = 1;
+
+ // Elapsed realtime at end of report.
+ int64 end_realtime_ms = 2;
+
+ // CPU uptime at start of report.
+ int64 start_uptime_ms = 3;
+
+ // CPU uptime at end of report.
+ int64 end_uptime_ms = 4;
+
+ // System runtime library. e.g. "libdvm.so", "libart.so".
+ string runtime = 5;
+
+ // whether kernel reports swapped pss.
+ bool has_swapped_pss = 6;
+
+ // Data completeness. e.g. "complete", "partial", shutdown", or "sysprops".
+ enum Status {
+ STATUS_UNKNOWN = 0;
+ STATUS_COMPLETE = 1;
+ STATUS_PARTIAL = 2;
+ STATUS_SHUTDOWN = 3;
+ STATUS_SYSPROPS = 4;
+ }
+ repeated Status status = 7;
+
+ // Stats for each process.
+ repeated ProcessStatsProto process_stats = 8;
+}
+
+// Next Tag: 6
+message ProcessStatsProto {
+
+ // Name of process.
+ string process = 1;
+
+ // Uid of the process.
+ int32 uid = 2;
+
+ // Information about how often kills occurred
+ message Kill {
+ // Count of excessive wakes kills
+ int32 wakes = 1;
+
+ // Count of excessive CPU kills
+ int32 cpu = 2;
+
+ // Count of kills when cached
+ int32 cached = 3;
+
+ // PSS stats during cached kill
+ android.util.AggStats cached_pss = 4;
+ }
+ Kill kill = 3;
+
+ message State {
+ enum ScreenState {
+ SCREEN_UNKNOWN = 0;
+ OFF = 1;
+ ON = 2;
+ }
+ ScreenState screen_state = 1;
+
+ enum MemoryState {
+ MEMORY_UNKNOWN = 0;
+ NORMAL = 1; // normal.
+ MODERATE = 2; // moderate memory pressure.
+ LOW = 3; // low memory.
+ CRITICAL = 4; // critical memory.
+ }
+ MemoryState memory_state = 2;
+
+ enum ProcessState {
+ PROCESS_UNKNOWN = 0;
+ // Persistent system process.
+ PERSISTENT = 1;
+ // Top activity; actually any visible activity.
+ TOP = 2;
+ // Important foreground process (ime, wallpaper, etc).
+ IMPORTANT_FOREGROUND = 3;
+ // Important background process.
+ IMPORTANT_BACKGROUND = 4;
+ // Performing backup operation.
+ BACKUP = 5;
+ // Heavy-weight process (currently not used).
+ HEAVY_WEIGHT = 6;
+ // Background process running a service.
+ SERVICE = 7;
+ // Process not running, but would be if there was enough RAM.
+ SERVICE_RESTARTING = 8;
+ // Process running a receiver.
+ RECEIVER = 9;
+ // Process hosting home/launcher app when not on top.
+ HOME = 10;
+ // Process hosting the last app the user was in.
+ LAST_ACTIVITY = 11;
+ // Cached process hosting a previous activity.
+ CACHED_ACTIVITY = 12;
+ // Cached process hosting a client activity.
+ CACHED_ACTIVITY_CLIENT = 13;
+ // Cached process that is empty.
+ CACHED_EMPTY = 14;
+ }
+ ProcessState process_state = 3;
+
+ // Millisecond duration spent in this state
+ int64 duration_ms = 4;
+
+ // # of samples taken
+ int32 sample_size = 5;
+
+ // PSS is memory reserved for this process
+ android.util.AggStats pss = 6;
+
+ // USS is memory shared between processes, divided evenly for accounting
+ android.util.AggStats uss = 7;
+ }
+ repeated State states = 5;
+}
diff --git a/core/proto/android/util/common.proto b/core/proto/android/util/common.proto
new file mode 100644
index 0000000..6dd4c02
--- /dev/null
+++ b/core/proto/android/util/common.proto
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+package android.util;
+
+option java_multiple_files = true;
+
+/**
+ * Very basic data structure used by aggregated stats.
+ */
+message AggStats {
+
+ int64 min = 1;
+
+ int64 average = 2;
+
+ int64 max = 3;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4159c21..a9fda8e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -204,8 +204,8 @@
android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_DELIVERY" />
<protected-broadcast
android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" />
- <protected-broadcast android:name="android.bluetooth.pbap.intent.action.PBAP_STATE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.pbapclient.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.sap.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast android:name="android.btopp.intent.action.INCOMING_FILE_NOTIFICATION" />
<protected-broadcast android:name="android.btopp.intent.action.USER_CONFIRMATION_TIMEOUT" />
diff --git a/core/res/res/drawable/ic_ab_back_material_settings.xml b/core/res/res/drawable/ic_ab_back_material_settings.xml
new file mode 100644
index 0000000..7325a41
--- /dev/null
+++ b/core/res/res/drawable/ic_ab_back_material_settings.xml
@@ -0,0 +1,28 @@
+<?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.0"
+ android:viewportHeight="24.0"
+ android:autoMirrored="true"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@color/white"
+ android:pathData="M20,11H7.62l4.88,-4.88a0.996,0.996 0,1 0,-1.41 -1.41l-6.94,6.94c-0.2,0.2 -0.2,0.51 0,0.71l6.94,6.94a0.996,0.996 0,1 0,1.41 -1.41L7.62,13H20c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1z"/>
+</vector>
diff --git a/core/res/res/layout/magnifier.xml b/core/res/res/layout/magnifier.xml
new file mode 100644
index 0000000..181e5e5
--- /dev/null
+++ b/core/res/res/layout/magnifier.xml
@@ -0,0 +1,27 @@
+<?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
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/floatingToolbarPopupBackgroundDrawable">
+ <ImageView
+ android:id="@+id/magnifier_image"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+</LinearLayout>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 86191af..9e4184b 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Foon"</string>
<string name="map" msgid="6068210738233985748">"Kaarte"</string>
<string name="browse" msgid="6993590095938149861">"Blaaier"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Bergingspasie word min"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Sommige stelselfunksies werk moontlik nie"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nie genoeg berging vir die stelsel nie. Maak seker jy het 250 MB spasie beskikbaar en herbegin."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Kanselleer"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Kanselleer"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"MAAK TOE"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Aandag"</string>
<string name="loading" msgid="7933681260296021180">"Laai tans..."</string>
<string name="capital_on" msgid="1544682755514494298">"AAN"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skaal"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Wys altyd"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Heraktiveer hierdie in Stelselinstellings > Programme > Afgelaai."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Program reageer nie"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> gebruik dalk te veel berging."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> steun nie die huidige skermgrootte-instelling nie en sal dalk onverwags reageer."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Wys altyd"</string>
<string name="smv_application" msgid="3307209192155442829">"Die program <xliff:g id="APPLICATION">%1$s</xliff:g> (proses <xliff:g id="PROCESS">%2$s</xliff:g>) het sy selfopgelegde StrictMode-beleid oortree."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index e9d67a9..00257ee 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"ስልክ"</string>
<string name="map" msgid="6068210738233985748">"ካርታዎች"</string>
<string name="browse" msgid="6993590095938149861">"አሳሽ"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"የማከማቻ ቦታ እያለቀ ነው"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"አንዳንድ የስርዓት ተግባራት ላይሰሩ ይችላሉ"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"ለስርዓቱ የሚሆን በቂ ቦታ የለም። 250 ሜባ ነጻ ቦታ እንዳለዎት ያረጋግጡና ዳግም ያስጀምሩ።"</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"ይቅር"</string>
<string name="yes" msgid="5362982303337969312">"እሺ"</string>
<string name="no" msgid="5141531044935541497">"ይቅር"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"ዝጋ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"ትኩረት"</string>
<string name="loading" msgid="7933681260296021180">"በመጫን ላይ…"</string>
<string name="capital_on" msgid="1544682755514494298">"በ"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"የልኬት ለውጥ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"ሁልጊዜ አሳይ"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"በስርዓት ቅንብሮች ውስጥ ይሄንን ዳግም አንቃ> Apps &gt፤ወርዷል፡፡"</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"መተግበሪያው ምላሽ እየሰጠ አይደለም"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> በጣም ብዙ ማህደረ ትውስታ እየተጠቀመ ሊሆን ይችላል።"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> አሁን ያለውን የማሳያ መጠን ቅንብር አይደግፍም እና ያልተጠብቀ ባሕሪ ሊያሳይ ይችላል።"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"ሁልጊዜ አሳይ"</string>
<string name="smv_application" msgid="3307209192155442829">"መተግበሪያው <xliff:g id="APPLICATION">%1$s</xliff:g>( ሂደት<xliff:g id="PROCESS">%2$s</xliff:g>) በራስ ተነሳሺ StrictMode ደንብን ይተላለፋል።"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 63274da..8f78cfa 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1060,6 +1060,10 @@
<string name="dial" msgid="4204975095406423102">"الهاتف"</string>
<string name="map" msgid="6068210738233985748">"الخرائط"</string>
<string name="browse" msgid="6993590095938149861">"المتصفح"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"مساحة التخزين منخفضة"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"قد لا تعمل بعض وظائف النظام"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"ليست هناك سعة تخزينية كافية للنظام. تأكد من أنه لديك مساحة خالية تبلغ ٢٥٠ ميغابايت وأعد التشغيل."</string>
@@ -1069,8 +1073,7 @@
<string name="cancel" msgid="6442560571259935130">"إلغاء"</string>
<string name="yes" msgid="5362982303337969312">"حسنًا"</string>
<string name="no" msgid="5141531044935541497">"إلغاء"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"إغلاق"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"تنبيه"</string>
<string name="loading" msgid="7933681260296021180">"جارٍ التحميل…"</string>
<string name="capital_on" msgid="1544682755514494298">"تشغيل"</string>
@@ -1127,10 +1130,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"تدرج"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"الإظهار دائمًا"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"يمكنك إعادة تمكين هذا في إعدادات النظام > التطبيقات > ما تم تنزيله."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"التطبيق لا يستجيب"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"ربما يشغل <xliff:g id="APP_NAME">%1$s</xliff:g> مساحة كبيرة جدًا من الذاكرة."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> غير متوافق مع الإعداد الحالي لحجم شاشة العرض وربما يعمل بطريقة غير متوقعة."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"العرض دائمًا"</string>
<string name="smv_application" msgid="3307209192155442829">"انتهك التطبيق <xliff:g id="APPLICATION">%1$s</xliff:g> (العملية <xliff:g id="PROCESS">%2$s</xliff:g>) سياسة StrictMode المفروضة ذاتيًا."</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 97dbbda..97a67e0 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefon"</string>
<string name="map" msgid="6068210738233985748">"Xəritə"</string>
<string name="browse" msgid="6993590095938149861">"Brauzer"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Yaddaş yeri bitir"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Bəzi sistem funksiyaları işləməyə bilər"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Sistem üçün yetərincə yaddaş ehtiyatı yoxdur. 250 MB yaddaş ehtiyatının olmasına əmin olun və yenidən başladın."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Ləğv et"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Ləğv et"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"BAĞLAYIN"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Diqqət"</string>
<string name="loading" msgid="7933681260296021180">"Yüklənir…"</string>
<string name="capital_on" msgid="1544682755514494298">"AÇIQ"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Miqyas"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Həmişə göstər"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Bunları Sistem ayarlarında yenidən aktivləşdir Yüklənmiş > Tətbiqlər >."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Tətbiq cavab vermir"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> daha çox yaddaş istifadə edə bilər."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> cari Ekran ölçüsü ayarını dəstəkləmir və gözlənilməz şəkildə davrana bilər."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Həmişə göstərin"</string>
<string name="smv_application" msgid="3307209192155442829">"Tətbiq <xliff:g id="APPLICATION">%1$s</xliff:g> (proses <xliff:g id="PROCESS">%2$s</xliff:g>) StrictMode siyasətini pozdu."</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 4f8e102..2daf942 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1000,6 +1000,10 @@
<string name="dial" msgid="4204975095406423102">"Pozovi"</string>
<string name="map" msgid="6068210738233985748">"Mape"</string>
<string name="browse" msgid="6993590095938149861">"Pregledač"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Memorijski prostor je na izmaku"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Neke sistemske funkcije možda ne funkcionišu"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nema dovoljno memorijskog prostora za sistem. Uverite se da imate 250 MB slobodnog prostora i ponovo pokrenite."</string>
@@ -1009,8 +1013,7 @@
<string name="cancel" msgid="6442560571259935130">"Otkaži"</string>
<string name="yes" msgid="5362982303337969312">"Potvrdi"</string>
<string name="no" msgid="5141531044935541497">"Otkaži"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"ZATVORI"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Pažnja"</string>
<string name="loading" msgid="7933681260296021180">"Učitava se…"</string>
<string name="capital_on" msgid="1544682755514494298">"DA"</string>
@@ -1067,10 +1070,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Razmera"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Uvek prikazuj"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Ponovo omogućite u meniju Sistemska podešavanja > Aplikacije > Preuzeto."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikacija ne reaguje"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> možda koristi previše memorije."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava trenutno podešavanje veličine prikaza i može da se ponaša neočekivano."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Uvek prikazuj"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) je prekršila samonametnute StrictMode smernice."</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index c4e9255a..c89987b 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1020,6 +1020,10 @@
<string name="dial" msgid="4204975095406423102">"Тэлефон"</string>
<string name="map" msgid="6068210738233985748">"Карты"</string>
<string name="browse" msgid="6993590095938149861">"Браўзер"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Месца для захавання на зыходзе"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Некаторыя сістэмныя функцыі могуць не працаваць"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Не хапае сховішча для сістэмы. Пераканайцеся, што ў вас ёсць 250 МБ свабоднага месца, і перазапусціце."</string>
@@ -1029,8 +1033,7 @@
<string name="cancel" msgid="6442560571259935130">"Скасаваць"</string>
<string name="yes" msgid="5362982303337969312">"ОК"</string>
<string name="no" msgid="5141531044935541497">"Скасаваць"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"ЗАКРЫЦЬ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Увага"</string>
<string name="loading" msgid="7933681260296021180">"Загрузка..."</string>
<string name="capital_on" msgid="1544682755514494298">"Уключыць"</string>
@@ -1087,10 +1090,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Шкала"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Заўсёды паказваць"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Зноў уключыце гэта ў раздзеле \"Сістэмныя налады > Прыкладанні > Спампаваныя\"."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Праграма не адказвае"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> можа выкарыстоўваць занадта шмат памяці."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> не падтрымлівае бягучую наладу Памеру дысплэя і можа паводзіць сябе непрадказальным чынам."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Заўсёды паказваць"</string>
<string name="smv_application" msgid="3307209192155442829">"Прыкладанне <xliff:g id="APPLICATION">%1$s</xliff:g> (працэс <xliff:g id="PROCESS">%2$s</xliff:g>) парушыла ўласную палітыку StrictMode."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 5123eba..07bdc3d 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Телефон"</string>
<string name="map" msgid="6068210738233985748">"Карти"</string>
<string name="browse" msgid="6993590095938149861">"Браузър"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Мястото в хранилището е на изчерпване"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Възможно е някои функции на системата да не работят"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"За системата няма достатъчно място в хранилището. Уверете се, че имате свободни 250 МБ, и рестартирайте."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Отказ"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Отказ"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"ЗАТВАРЯНЕ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Внимание"</string>
<string name="loading" msgid="7933681260296021180">"Зарежда се..."</string>
<string name="capital_on" msgid="1544682755514494298">"ВКЛ"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Мащаб"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Винаги да се показва"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Активирайте отново това в „Системни настройки“ > „Приложения“ > „Изтеглени“."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Приложението не реагира"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Възможно е <xliff:g id="APP_NAME">%1$s</xliff:g> да използва твърде много памет."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> не поддържа текущата настройка за размер на дисплея и може да се държи по неочакван начин."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Винаги да се показва"</string>
<string name="smv_application" msgid="3307209192155442829">"Приложението „<xliff:g id="APPLICATION">%1$s</xliff:g>“ (процес „<xliff:g id="PROCESS">%2$s</xliff:g>“) наруши правилото за стриктен режим, наложено от самото него."</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 2fbf7d2..5d19486 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"ফোন করুন"</string>
<string name="map" msgid="6068210738233985748">"মানচিত্র"</string>
<string name="browse" msgid="6993590095938149861">"ব্রাউজার"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"স্টোরেজ পূর্ণ হতে চলেছে"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"কিছু কিছু সিস্টেম ক্রিয়াকলাপ কাজ নাও করতে পারে"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"সিস্টেমের জন্য যথেষ্ট স্টোরেজ নেই৷ আপনার কাছে ২৫০এমবি ফাঁকা স্থান রয়েছে কিনা সে বিষয়ে নিশ্চিত হন এবং সিস্টেম চালু করুন৷"</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"বাতিল করুন"</string>
<string name="yes" msgid="5362982303337969312">"ঠিক আছে"</string>
<string name="no" msgid="5141531044935541497">"বাতিল করুন"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"বন্ধ করুন"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"খেয়াল করুন"</string>
<string name="loading" msgid="7933681260296021180">"লোড হচ্ছে..."</string>
<string name="capital_on" msgid="1544682755514494298">"চালু করুন"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"স্কেল"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"সবসময় দেখান"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"সিস্টেম সেটিংস> অ্যাপ্স> ডাউনলোড করাগুলি এ এটি পুনঃসক্ষম করুন৷"</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"অ্যাপটি সাড়া দিচ্ছে না"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"মনে হচ্ছে <xliff:g id="APP_NAME">%1$s</xliff:g> খুব বেশি মেমরি ব্যবহার করছে।"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g>, বর্তমান প্রদর্শনের আকারের সেটিংস সমর্থন করে না এবং অপ্রত্যাশিত আচরণ করতে পারে৷"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"সর্বদা দেখান"</string>
<string name="smv_application" msgid="3307209192155442829">"অ্যাপ্লিকেশানটি <xliff:g id="APPLICATION">%1$s</xliff:g> (প্রক্রিয়া <xliff:g id="PROCESS">%2$s</xliff:g>) তার স্ব-প্রয়োগ করা কঠোর মোড নীতি লঙ্ঘন করেছে৷"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 06b34a3..31ecfc5 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1000,6 +1000,10 @@
<string name="dial" msgid="4204975095406423102">"Pozovi"</string>
<string name="map" msgid="6068210738233985748">"Mape"</string>
<string name="browse" msgid="6993590095938149861">"Preglednik"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ponestaje prostora za pohranu"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Neke funkcije sistema možda neće raditi"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nema dovoljno prostora za sistem. Obezbijedite 250MB slobodnog prostora i ponovo pokrenite uređaj."</string>
@@ -1009,8 +1013,7 @@
<string name="cancel" msgid="6442560571259935130">"Otkaži"</string>
<string name="yes" msgid="5362982303337969312">"Uredu"</string>
<string name="no" msgid="5141531044935541497">"Otkaži"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"ZATVORI"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Pažnja"</string>
<string name="loading" msgid="7933681260296021180">"Učitavanje..."</string>
<string name="capital_on" msgid="1544682755514494298">"Uključeno"</string>
@@ -1069,10 +1072,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Razmjer"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Uvijek prikaži"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Ponovo omogućite ovu opciju u meniju Postavke sistema > Aplikacije > Preuzete aplikacije."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikacija ne reagira"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Moguće je da aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> koristi previše memorije."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava trenutnu postavku veličine ekrana i može se ponašati neočekivano."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Uvijek prikaži"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) prekršila je vlastita StrictMode pravila."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index a1a8cd6..082513d 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Truca"</string>
<string name="map" msgid="6068210738233985748">"Mapes"</string>
<string name="browse" msgid="6993590095938149861">"Navegador"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"L\'espai d\'emmagatzematge s\'està esgotant"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"És possible que algunes funcions del sistema no funcionin"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"No hi ha prou espai d\'emmagatzematge per al sistema. Comprova que tinguis 250 MB d\'espai lliure i reinicia."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Cancel·la"</string>
<string name="yes" msgid="5362982303337969312">"D\'acord"</string>
<string name="no" msgid="5141531044935541497">"Cancel·la"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"TANCA"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Atenció"</string>
<string name="loading" msgid="7933681260296021180">"S\'està carregant…"</string>
<string name="capital_on" msgid="1544682755514494298">"SÍ"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostra sempre"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Torna a activar-ho a Configuració del sistema > Aplicacions > Baixades."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"L\'aplicació no respon"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"És possible que <xliff:g id="APP_NAME">%1$s</xliff:g> faci servir massa memòria."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admet la mida de pantalla actual i és possible que funcioni de manera inesperada."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostra sempre"</string>
<string name="smv_application" msgid="3307209192155442829">"L\'aplicació <xliff:g id="APPLICATION">%1$s</xliff:g>(procés <xliff:g id="PROCESS">%2$s</xliff:g>) ha incomplert la seva política autoimposada de mode estricte."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 21c40bd..23f3cb9 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1020,6 +1020,10 @@
<string name="dial" msgid="4204975095406423102">"Telefon"</string>
<string name="map" msgid="6068210738233985748">"Mapy"</string>
<string name="browse" msgid="6993590095938149861">"Prohlížeč"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"V úložišti je málo místa"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Některé systémové funkce nemusí fungovat"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Pro systém není dostatek místa v úložišti. Uvolněte alespoň 250 MB místa a restartujte zařízení."</string>
@@ -1029,8 +1033,7 @@
<string name="cancel" msgid="6442560571259935130">"Zrušit"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Zrušit"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"ZAVŘÍT"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Upozornění"</string>
<string name="loading" msgid="7933681260296021180">"Načítání..."</string>
<string name="capital_on" msgid="1544682755514494298">"I"</string>
@@ -1087,10 +1090,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Měřítko"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Vždy zobrazovat"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Tento režim znovu povolíte v sekci Nastavení systému > Aplikace > Stažené."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikace nereaguje"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> pravděpodobně využívá příliš mnoho paměti."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> aktuální nastavení velikosti zobrazení nepodporuje a může se chovat neočekávaně."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Vždy zobrazovat"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikace <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) porušila své vlastní vynucené zásady StrictMode."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index ddc494c..9360cbe 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Opkald"</string>
<string name="map" msgid="6068210738233985748">"Kort"</string>
<string name="browse" msgid="6993590095938149861">"Browser"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Der er snart ikke mere lagerplads"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Nogle systemfunktioner virker måske ikke"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Der er ikke nok ledig lagerplads til systemet. Sørg for, at du har 250 MB ledig plads, og genstart."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Annuller"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Annuller"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"LUK"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Bemærk"</string>
<string name="loading" msgid="7933681260296021180">"Indlæser…"</string>
<string name="capital_on" msgid="1544682755514494298">"TIL"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skaler"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Vis altid"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Aktivér dette igen i Systemindstillinger > Apps > Downloadet."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Appen svarer ikke"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> bruger muligvis for meget hukommelse."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> understøtter ikke den aktuelle indstilling for visningsstørrelse og vil muligvis ikke fungere som forventet."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Vis altid"</string>
<string name="smv_application" msgid="3307209192155442829">"Appen <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) har overtrådt sin egen StrictMode-politik."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index c9a61df..8b31d96 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefon"</string>
<string name="map" msgid="6068210738233985748">"Karten"</string>
<string name="browse" msgid="6993590095938149861">"Browser"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Der Speicherplatz wird knapp"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Einige Systemfunktionen funktionieren möglicherweise nicht."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Der Speicherplatz reicht nicht für das System aus. Stelle sicher, dass 250 MB freier Speicherplatz vorhanden sind, und starte das Gerät dann neu."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index adb48cf..19aafc8 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Τηλέφωνο"</string>
<string name="map" msgid="6068210738233985748">"Χάρτες"</string>
<string name="browse" msgid="6993590095938149861">"Πρόγραμμα περιήγησης"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ο αποθηκευτικός χώρος εξαντλείται"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Ορισμένες λειτουργίες συστήματος ενδέχεται να μην λειτουργούν"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Δεν υπάρχει αρκετός αποθηκευτικός χώρος για το σύστημα. Βεβαιωθείτε ότι διαθέτετε 250 MB ελεύθερου χώρου και κάντε επανεκκίνηση."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Ακύρωση"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Ακύρωση"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"ΚΛΕΙΣΙΜΟ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Προσοχή"</string>
<string name="loading" msgid="7933681260296021180">"Φόρτωση…"</string>
<string name="capital_on" msgid="1544682755514494298">"Ενεργό"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Κλίμακα"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Να εμφανίζονται πάντα"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Ενεργοποιήστε το ξανά στις Ρυθμίσεις συστημάτων > Εφαρμογές > Ληφθείσες."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Η εφαρμογή δεν αποκρίνεται"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> μπορεί να χρησιμοποιεί υπερβολική μνήμη."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> δεν υποστηρίζει την τρέχουσα ρύθμιση Μεγέθους οθόνης και ενδέχεται να παρουσιάζει μη αναμενόμενη συμπεριφορά."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Να εμφανίζεται πάντα"</string>
<string name="smv_application" msgid="3307209192155442829">"Η εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g> (διεργασία <xliff:g id="PROCESS">%2$s</xliff:g>) παραβίασε την αυτοεπιβαλλόμενη πολιτική StrictMode."</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 9c55175..7fff878 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Phone"</string>
<string name="map" msgid="6068210738233985748">"Maps"</string>
<string name="browse" msgid="6993590095938149861">"Browser"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Storage space running out"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Some system functions may not work"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Not enough storage for the system. Make sure that you have 250 MB of free space and restart."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Cancel"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Cancel"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"CLOSE"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Attention"</string>
<string name="loading" msgid="7933681260296021180">"Loading…"</string>
<string name="capital_on" msgid="1544682755514494298">"ON"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scale"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Always show"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Re-enable this in System settings > Apps > Downloaded."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"App isn\'t responding"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> may be using too much memory."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support the current Display size setting and may behave unexpectedly."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Always show"</string>
<string name="smv_application" msgid="3307209192155442829">"The app <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) has violated its self-enforced Strict Mode policy."</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 9c55175..7fff878 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Phone"</string>
<string name="map" msgid="6068210738233985748">"Maps"</string>
<string name="browse" msgid="6993590095938149861">"Browser"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Storage space running out"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Some system functions may not work"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Not enough storage for the system. Make sure that you have 250 MB of free space and restart."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Cancel"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Cancel"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"CLOSE"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Attention"</string>
<string name="loading" msgid="7933681260296021180">"Loading…"</string>
<string name="capital_on" msgid="1544682755514494298">"ON"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scale"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Always show"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Re-enable this in System settings > Apps > Downloaded."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"App isn\'t responding"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> may be using too much memory."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support the current Display size setting and may behave unexpectedly."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Always show"</string>
<string name="smv_application" msgid="3307209192155442829">"The app <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) has violated its self-enforced Strict Mode policy."</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 9c55175..7fff878 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Phone"</string>
<string name="map" msgid="6068210738233985748">"Maps"</string>
<string name="browse" msgid="6993590095938149861">"Browser"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Storage space running out"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Some system functions may not work"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Not enough storage for the system. Make sure that you have 250 MB of free space and restart."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Cancel"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Cancel"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"CLOSE"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Attention"</string>
<string name="loading" msgid="7933681260296021180">"Loading…"</string>
<string name="capital_on" msgid="1544682755514494298">"ON"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scale"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Always show"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Re-enable this in System settings > Apps > Downloaded."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"App isn\'t responding"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> may be using too much memory."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support the current Display size setting and may behave unexpectedly."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Always show"</string>
<string name="smv_application" msgid="3307209192155442829">"The app <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) has violated its self-enforced Strict Mode policy."</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 9c55175..7fff878 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Phone"</string>
<string name="map" msgid="6068210738233985748">"Maps"</string>
<string name="browse" msgid="6993590095938149861">"Browser"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Storage space running out"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Some system functions may not work"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Not enough storage for the system. Make sure that you have 250 MB of free space and restart."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Cancel"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Cancel"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"CLOSE"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Attention"</string>
<string name="loading" msgid="7933681260296021180">"Loading…"</string>
<string name="capital_on" msgid="1544682755514494298">"ON"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scale"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Always show"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Re-enable this in System settings > Apps > Downloaded."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"App isn\'t responding"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> may be using too much memory."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support the current Display size setting and may behave unexpectedly."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Always show"</string>
<string name="smv_application" msgid="3307209192155442829">"The app <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) has violated its self-enforced Strict Mode policy."</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 7eff4b0..b93db1c 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Phone"</string>
<string name="map" msgid="6068210738233985748">"Maps"</string>
<string name="browse" msgid="6993590095938149861">"Browser"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Storage space running out"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Some system functions may not work"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Not enough storage for the system. Make sure you have 250MB of free space and restart."</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index c5b4880..3946e7d 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Teléfono"</string>
<string name="map" msgid="6068210738233985748">"Mapas"</string>
<string name="browse" msgid="6993590095938149861">"Navegador"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Queda poco espacio de almacenamiento"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Es posible que algunas funciones del sistema no estén disponibles."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"No hay espacio suficiente para el sistema. Asegúrate de que haya 250 MB libres y reinicia el dispositivo."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
<string name="yes" msgid="5362982303337969312">"Aceptar"</string>
<string name="no" msgid="5141531044935541497">"Cancelar"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"CERRAR"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Atención"</string>
<string name="loading" msgid="7933681260296021180">"Cargando…"</string>
<string name="capital_on" msgid="1544682755514494298">"Sí"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostrar siempre"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Volver a activar Configuración del sistema > Aplicaciones > Descargas"</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"La app no responde"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Es posible que <xliff:g id="APP_NAME">%1$s</xliff:g> esté consumiendo demasiada memoria."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> no es compatible con la configuración del tamaño de pantalla actual. Es posible que no se comporte de manera correcta."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar siempre"</string>
<string name="smv_application" msgid="3307209192155442829">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) ha infringido su política StrictMode de aplicación automática."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 38359ad..7085fda 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -524,12 +524,12 @@
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que la aplicación modifique cómo se registra el uso de red en relación con las aplicaciones. Las aplicaciones normales no deben usar este permiso."</string>
<string name="permlab_accessNotifications" msgid="7673416487873432268">"acceder a las notificaciones"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que la aplicación recupere, examine y borre notificaciones, incluidas las que han publicado otras aplicaciones."</string>
- <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"enlazar con un servicio de detector de notificaciones"</string>
- <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite enlazar con la interfaz de nivel superior de un servicio de detector de notificaciones. No debe ser necesario para las aplicaciones normales."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"enlazar con un servicio de proveedor de condiciones"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite enlazar con la interfaz de nivel superior de un servicio de proveedor de condiciones. Las aplicaciones normales no deberían necesitar este permiso."</string>
- <string name="permlab_bindDreamService" msgid="4153646965978563462">"enlazar con un servicio de salvapantallas"</string>
- <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Permite enlazar con la interfaz de nivel superior de un servicio de salvapantallas. Las aplicaciones normales no deberían necesitar este permiso."</string>
+ <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincular con un servicio de detector de notificaciones"</string>
+ <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite vincular con la interfaz de nivel superior de un servicio de detector de notificaciones. No debe ser necesario para las aplicaciones normales."</string>
+ <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"vincular con un servicio de proveedor de condiciones"</string>
+ <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite vincular con la interfaz de nivel superior de un servicio de proveedor de condiciones. Las aplicaciones normales no deberían necesitar este permiso."</string>
+ <string name="permlab_bindDreamService" msgid="4153646965978563462">"vincular con un servicio de salvapantallas"</string>
+ <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Permite vincular con la interfaz de nivel superior de un servicio de salvapantallas. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"ejecutar la aplicación de configuración proporcionada por el operador"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite ejecutar la aplicación de configuración proporcionada por el operador. No debe ser necesario para aplicaciones normales."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"detectar cambios en el estado de la red"</string>
@@ -542,10 +542,10 @@
<string name="permdesc_handoverStatus" msgid="4788144087245714948">"Permite que esta aplicación reciba información sobre las transferencias actuales de Android Beam"</string>
<string name="permlab_removeDrmCertificates" msgid="7044888287209892751">"quitar certificados DRM"</string>
<string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Permite a una aplicación eliminar los certificados DRM. Las aplicaciones normales no deberían necesitar este permiso."</string>
- <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"enlazar con el servicio de mensajería de un operador"</string>
- <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Permite enlazar con la interfaz de nivel superior del servicio de mensajería de un operador. Las aplicaciones normales no deberían necesitar este permiso."</string>
- <string name="permlab_bindCarrierServices" msgid="3233108656245526783">"enlazar con servicios de operador"</string>
- <string name="permdesc_bindCarrierServices" msgid="1391552602551084192">"Permite enlazar con servicios de operador. Las aplicaciones normales no deberían necesitar este permiso."</string>
+ <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"vincular con el servicio de mensajería de un operador"</string>
+ <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Permite vincular con la interfaz de nivel superior del servicio de mensajería de un operador. Las aplicaciones normales no deberían necesitar este permiso."</string>
+ <string name="permlab_bindCarrierServices" msgid="3233108656245526783">"vincular con servicios de operador"</string>
+ <string name="permdesc_bindCarrierServices" msgid="1391552602551084192">"Permite vincular con servicios de operador. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_access_notification_policy" msgid="4247510821662059671">"acceso a No molestar"</string>
<string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Permite que la aplicación lea y modifique la configuración de No molestar."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Establecimiento de reglas de contraseña"</string>
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Teléfono"</string>
<string name="map" msgid="6068210738233985748">"Mapas"</string>
<string name="browse" msgid="6993590095938149861">"Navegador"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Queda poco espacio"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Es posible que algunas funciones del sistema no funcionen."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"No hay espacio suficiente para el sistema. Comprueba que haya 250 MB libres y reinicia el dispositivo."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
<string name="yes" msgid="5362982303337969312">"Aceptar"</string>
<string name="no" msgid="5141531044935541497">"Cancelar"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"CERRAR"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Atención"</string>
<string name="loading" msgid="7933681260296021180">"Cargando..."</string>
<string name="capital_on" msgid="1544682755514494298">"ACTIVADO"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostrar siempre"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Para volver a habilitar esta opción, accede a Ajustes > Aplicaciones > Descargadas."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"La aplicación no responde"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Es posible que <xliff:g id="APP_NAME">%1$s</xliff:g> esté usando demasiada memoria."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admite el tamaño de pantalla actual y es posible que funcione de forma inesperada."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar siempre"</string>
<string name="smv_application" msgid="3307209192155442829">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) ha infringido su política StrictMode autoaplicable."</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index c335d93..2565e62 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefon"</string>
<string name="map" msgid="6068210738233985748">"Maps"</string>
<string name="browse" msgid="6993590095938149861">"Brauser"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Talletusruum saab täis"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Mõned süsteemifunktsioonid ei pruugi töötada"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Süsteemis pole piisavalt talletusruumi. Veenduge, et seadmes oleks 250 MB vaba ruumi, ja käivitage seade uuesti."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Tühista"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Tühista"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"SULGE"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Tähelepanu"</string>
<string name="loading" msgid="7933681260296021180">"Laadimine ..."</string>
<string name="capital_on" msgid="1544682755514494298">"SEES"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Mõõtkava"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Kuva alati"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Lubage see uuesti valikutes Süsteemiseaded > Rakendused > Allalaaditud."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Rakendus ei reageeri"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Võimalik, et rakendus <xliff:g id="APP_NAME">%1$s</xliff:g> kasutab liiga palju mälu."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Rakendus <xliff:g id="APP_NAME">%1$s</xliff:g> ei toeta praegust ekraani suuruse seadet ja võib ootamatult käituda."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Kuva alati"</string>
<string name="smv_application" msgid="3307209192155442829">"Rakendus <xliff:g id="APPLICATION">%1$s</xliff:g> (protsess <xliff:g id="PROCESS">%2$s</xliff:g>) on rikkunud isekehtestatud StrictMode\'i eeskirju."</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 9ecc8fc..f88d4c4 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefonoa"</string>
<string name="map" msgid="6068210738233985748">"Mapak"</string>
<string name="browse" msgid="6993590095938149861">"Arakatzailea"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Memoria betetzen ari da"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Sistemaren funtzio batzuek ez dute agian funtzionatuko"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Sisteman ez dago behar adina memoria. Ziurtatu gutxienez 250 MB erabilgarri dituzula eta, ondoren, berrabiarazi gailua."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Utzi"</string>
<string name="yes" msgid="5362982303337969312">"Ados"</string>
<string name="no" msgid="5141531044935541497">"Utzi"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"ITXI"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Abisua"</string>
<string name="loading" msgid="7933681260296021180">"Kargatzen…"</string>
<string name="capital_on" msgid="1544682755514494298">"AKTIBATUTA"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Eskala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Erakutsi beti"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Gaitu hori berriro Sistemaren ezarpenak > Aplikazioak > Deskargatutakoak."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikazioak ez du erantzuten"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> memoria gehiegi erabiltzen ari liteke."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak ez du onartzen uneko pantailaren tamaina eta espero ez bezala joka lezake."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Erakutsi beti"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> aplikazioak (<xliff:g id="PROCESS">%2$s</xliff:g> prozesua) berak aplikatutako StrictMode gidalerroa urratu du."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 439eff4..2bd7696 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"تلفن"</string>
<string name="map" msgid="6068210738233985748">"نقشهها"</string>
<string name="browse" msgid="6993590095938149861">"مرورگر"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"حافظه درحال پر شدن است"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"برخی از عملکردهای سیستم ممکن است کار نکنند"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"فضای ذخیرهسازی سیستم کافی نیست. اطمینان حاصل کنید که دارای ۲۵۰ مگابایت فضای خالی هستید و سیستم را راهاندازی مجدد کنید."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"لغو"</string>
<string name="yes" msgid="5362982303337969312">"تأیید"</string>
<string name="no" msgid="5141531044935541497">"لغو"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"بستن"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"توجه"</string>
<string name="loading" msgid="7933681260296021180">"در حال بارکردن…"</string>
<string name="capital_on" msgid="1544682755514494298">"روشن"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"مقیاس"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"همیشه نشان داده شود"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"در تنظیمات سیستم >برنامهها > مورد بارگیری شده آن را دوباره فعال کنید."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"برنامه پاسخ نمیدهد"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> ممکن است حافظه خیلی زیادی مصرف کند."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> از تنظیم فعلی اندازه نمایشگر پشتیبانی نمیکند و ممکن است رفتار غیرمنتظرهای داشته باشد."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"همیشه نشان داده شود"</string>
<string name="smv_application" msgid="3307209192155442829">"برنامه <xliff:g id="APPLICATION">%1$s</xliff:g> (پردازش <xliff:g id="PROCESS">%2$s</xliff:g>) خطمشی StrictMode اجرایی خود را نقض کرده است."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index c31b379..c2a2ccb 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Puhelin"</string>
<string name="map" msgid="6068210738233985748">"Kartat"</string>
<string name="browse" msgid="6993590095938149861">"Selain"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Tallennustila loppumassa"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Kaikki järjestelmätoiminnot eivät välttämättä toimi"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Tallennustila ei riitä. Varmista, että vapaata tilaa on 250 Mt, ja käynnistä uudelleen."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Peruuta"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Peruuta"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"SULJE"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Huomio"</string>
<string name="loading" msgid="7933681260296021180">"Ladataan…"</string>
<string name="capital_on" msgid="1544682755514494298">"PÄÄLLÄ"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Asteikko"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Näytä aina"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Ota tämä uudelleen käyttöön kohdassa Järjestelmäasetukset > Sovellukset > Ladattu."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Sovellus ei vastaa"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> saattaa käyttää liikaa muistia."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei tue nykyistä näytön kokoasetusta ja saattaa toimia odottamattomalla tavalla."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Näytä aina"</string>
<string name="smv_application" msgid="3307209192155442829">"Sovellus <xliff:g id="APPLICATION">%1$s</xliff:g> (prosessi <xliff:g id="PROCESS">%2$s</xliff:g>) on rikkonut itse käyttöön ottamaansa StrictMode-käytäntöä."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index e12657e..fbed666 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Téléphone"</string>
<string name="map" msgid="6068210738233985748">"Cartes"</string>
<string name="browse" msgid="6993590095938149861">"Navigateur"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Espace de stockage bientôt saturé"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Il est possible que certaines fonctionnalités du système ne soient pas opérationnelles."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Espace de stockage insuffisant pour le système. Assurez-vous de disposer de 250 Mo d\'espace libre, puis redémarrez."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Annuler"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Annuler"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"FERMER"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Attention"</string>
<string name="loading" msgid="7933681260296021180">"Chargement en cours..."</string>
<string name="capital_on" msgid="1544682755514494298">"OUI"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Redimensionner"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Toujours afficher"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Réactivez ce mode en accédant à Paramètres système > Applications > Téléchargements"</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"L\'application ne répond pas"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> utilise peut-être trop de mémoire."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas compatible avec le paramètre de taille d\'affichage actuel et peut se comporter de manière inattendue."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Toujours afficher"</string>
<string name="smv_application" msgid="3307209192155442829">"L\'application <xliff:g id="APPLICATION">%1$s</xliff:g> (du processus <xliff:g id="PROCESS">%2$s</xliff:g>) a enfreint ses propres règles du mode strict."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 4a66034..fcdccad 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Téléphone"</string>
<string name="map" msgid="6068210738233985748">"Cartes"</string>
<string name="browse" msgid="6993590095938149861">"Navigateur"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Espace de stockage bientôt saturé"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Il est possible que certaines fonctionnalités du système ne soient pas opérationnelles."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Espace de stockage insuffisant pour le système. Assurez-vous de disposer de 250 Mo d\'espace libre, puis redémarrez."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Annuler"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Annuler"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"FERMER"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Attention"</string>
<string name="loading" msgid="7933681260296021180">"Chargement…"</string>
<string name="capital_on" msgid="1544682755514494298">"OUI"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Mise à l\'échelle"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Toujours afficher"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Réactivez ce mode en accédant à Paramètres système > Applications > Téléchargements"</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"L\'application ne répond pas"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> utilise peut-être trop de mémoire."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas compatible avec le paramètre de taille d\'affichage actuel et peut présenter un comportement inattendu."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Toujours afficher"</string>
<string name="smv_application" msgid="3307209192155442829">"L\'application <xliff:g id="APPLICATION">%1$s</xliff:g> (du processus <xliff:g id="PROCESS">%2$s</xliff:g>) a enfreint ses propres règles du mode strict."</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 106583f..0c0e12a 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Teléfono"</string>
<string name="map" msgid="6068210738233985748">"Mapas"</string>
<string name="browse" msgid="6993590095938149861">"Navegador"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Estase esgotando o espazo de almacenamento"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"É posible que algunhas funcións do sistema non funcionen"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Non hai almacenamento suficiente para o sistema. Asegúrate de ter un espazo libre de 250 MB e reinicia o dispositivo."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
<string name="yes" msgid="5362982303337969312">"Aceptar"</string>
<string name="no" msgid="5141531044935541497">"Cancelar"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"PECHAR"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Atención"</string>
<string name="loading" msgid="7933681260296021180">"Cargando..."</string>
<string name="capital_on" msgid="1544682755514494298">"SI"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostrar sempre"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Volve activar esta función en Configuración do sistema > Aplicacións > Descargadas."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"A aplicación non responde"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"É posible que <xliff:g id="APP_NAME">%1$s</xliff:g> estea utilizando demasiada memoria."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> non admite a configuración do tamaño de pantalla actual e quizais presente un comportamento inesperado."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar sempre"</string>
<string name="smv_application" msgid="3307209192155442829">"A aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) infrinxiu a súa política StrictMode autoaplicada."</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index c2d6060..d985e28 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"ફોન"</string>
<string name="map" msgid="6068210738233985748">"નકશા"</string>
<string name="browse" msgid="6993590095938149861">"બ્રાઉઝર"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"સ્ટોરેજ સ્થાન સમાપ્ત થયું"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"કેટલાક સિસ્ટમ કાર્યો કામ કરી શકશે નહીં"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"સિસ્ટમ માટે પર્યાપ્ત સ્ટોરેજ નથી. ખાતરી કરો કે તમારી પાસે 250MB ખાલી સ્થાન છે અને ફરીથી પ્રારંભ કરો."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"રદ કરો"</string>
<string name="yes" msgid="5362982303337969312">"ઓકે"</string>
<string name="no" msgid="5141531044935541497">"રદ કરો"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"બંધ કરો"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"ધ્યાન આપો"</string>
<string name="loading" msgid="7933681260296021180">"લોડ કરી રહ્યું છે…"</string>
<string name="capital_on" msgid="1544682755514494298">"ચાલુ"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"સ્કેલ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"હંમેશા બતાવો"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"આને સિસ્ટમ સેટિંગ્સ > ઍપ્લિકેશનો > ડાઉનલોડ કરેલમાં ફરીથી સક્ષમ કરો."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"ઍપ પ્રતિસાદ આપી રહી નથી"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> ખૂબ વધારે મેમરીનો ઉપયોગ કરતી હોઈ શકે."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> વર્તમાન પ્રદર્શન કદની સેટિંગનું સમર્થન કરતું નથી અને અનપેક્ષિત રીતે વર્તી શકે છે."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"હંમેશાં બતાવો"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> ઍપ્લિકેશન (<xliff:g id="PROCESS">%2$s</xliff:g> પ્રક્રિયા)એ તેની સ્વ-લાગુ કરેલ StrictMode નીતિનું ઉલ્લંઘન કર્યું છે."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 5d42d15..e29deab 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"फ़ोन"</string>
<string name="map" msgid="6068210738233985748">"मानचित्र"</string>
<string name="browse" msgid="6993590095938149861">"ब्राउज़र"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"मेमोरी में जगह नहीं बची है"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"हो सकता है कुछ सिस्टम फ़ंक्शन कार्य न करें"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"सिस्टम के लिए ज़रूरी मेमोरी नहीं है. पक्का करें कि आपके पास 250एमबी की खाली जगह है और फिर से शुरू करें."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"रद्द करें"</string>
<string name="yes" msgid="5362982303337969312">"ठीक है"</string>
<string name="no" msgid="5141531044935541497">"रद्द करें"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"बंद करें"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"ध्यान दें"</string>
<string name="loading" msgid="7933681260296021180">"लोड हो रहे हैं..."</string>
<string name="capital_on" msgid="1544682755514494298">"ऑन"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"स्केल"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"हमेशा दिखाएं"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"इसे सिस्टम सेटिंग > ऐप > डाउनलोड किए गए में फिर से चालू करें."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"ऐप काम नहीं कर रहा है"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> शायद बहुत ज़्यादा मेमोरी इस्तेमाल कर रहा है."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> वर्तमान स्क्रीन के आकार की सेटिंग का समर्थन नहीं करता है और अनपेक्षित रूप से व्यवहार कर सकता है."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"हमेशा दिखाएं"</string>
<string name="smv_application" msgid="3307209192155442829">"ऐप्स <xliff:g id="APPLICATION">%1$s</xliff:g> (प्रक्रिया <xliff:g id="PROCESS">%2$s</xliff:g>) ने उसकी स्वयं लागू होने वाली StrictMode नीति का उल्लंघन किया है."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 846ce5a..bcf789b 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1000,6 +1000,10 @@
<string name="dial" msgid="4204975095406423102">"Telefon"</string>
<string name="map" msgid="6068210738233985748">"Karte"</string>
<string name="browse" msgid="6993590095938149861">"Preglednik"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ponestaje prostora za pohranu"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Neke sistemske funkcije možda neće raditi"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nema dovoljno pohrane za sustav. Oslobodite 250 MB prostora i pokrenite uređaj ponovo."</string>
@@ -1009,8 +1013,7 @@
<string name="cancel" msgid="6442560571259935130">"Odustani"</string>
<string name="yes" msgid="5362982303337969312">"U redu"</string>
<string name="no" msgid="5141531044935541497">"Odustani"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"ZATVORI"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Pažnja"</string>
<string name="loading" msgid="7933681260296021180">"Učitavanje…"</string>
<string name="capital_on" msgid="1544682755514494298">"Uklj."</string>
@@ -1067,10 +1070,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Mjerilo"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Uvijek prikaži"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Omogućiti to ponovo u Postavkama sustava > Aplikacije > Preuzimanja."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikacija ne reagira"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> možda upotrebljava previše memorije."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava trenutačnu postavku veličine zaslona i može se ponašati neočekivano."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Uvijek prikaži"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) prekršila je vlastito pravilo StrictMode."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 10ce3e3..93eb9ac 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefon"</string>
<string name="map" msgid="6068210738233985748">"Térkép"</string>
<string name="browse" msgid="6993590095938149861">"Böngésző"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Kevés a szabad terület"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Előfordulhat, hogy néhány rendszerfunkció nem működik."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nincs elegendő tárhely a rendszerhez. Győződjön meg arról, hogy rendelkezik 250 MB szabad területtel, majd kezdje elölről."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Mégse"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Mégse"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"BEZÁRÁS"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Figyelem"</string>
<string name="loading" msgid="7933681260296021180">"Betöltés..."</string>
<string name="capital_on" msgid="1544682755514494298">"Be"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skála"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Mindig megjelenik"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Újbóli engedélyezés itt: Rendszerbeállítások > Alkalmazások > Letöltve."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Az alkalmazás nem válaszol"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Lehetséges, hogy a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> túl sok memóriát használ."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazás nem támogatja a képernyőméret jelenlegi beállításait, ezért nem várt módon viselkedhet."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Mindig megjelenik"</string>
<string name="smv_application" msgid="3307209192155442829">"A(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazás (<xliff:g id="PROCESS">%2$s</xliff:g> folyamat) megsértette az általa kényszerített Szigorú üzemmód irányelvet."</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 11a662c..e5d92c6 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Հեռախոս"</string>
<string name="map" msgid="6068210738233985748">"Քարտեզներ"</string>
<string name="browse" msgid="6993590095938149861">"Դիտարկիչ"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Հիշողությունը սպառվում է"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Որոշ գործառույթներ կարող են չաշխատել"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Համակարգի համար բավարար հիշողություն չկա: Համոզվեք, որ ունեք 250ՄԲ ազատ տարածություն և վերագործարկեք:"</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Չեղարկել"</string>
<string name="yes" msgid="5362982303337969312">"Լավ"</string>
<string name="no" msgid="5141531044935541497">"Չեղարկել"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"ՓԱԿԵԼ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Ուշադրություն"</string>
<string name="loading" msgid="7933681260296021180">"Բեռնում..."</string>
<string name="capital_on" msgid="1544682755514494298">"I"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Աստիճանակարգել"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Միշտ ցույց տալ"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Կրկին ակտիվացնել սա Համակարգի կարգավորումներում &gt Ծրագրեր > Ներբեռնումներ:"</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Հավելվածը չի արձագանքում"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Հնարավոր է, որ <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը չափազանց շատ հիշողություն է օգտագործում:"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը չի աջակցում Էկրանի չափի ընթացիկ կարգավորումները, ինչի պատճառով կարող են խնդիրներ առաջանալ:"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Միշտ ցուցադրել"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> ծրագիրը (գործընթաց <xliff:g id="PROCESS">%2$s</xliff:g>) խախտել է իր ինքնահարկադրված Խիստ ռեժիմ քաղաքականությունը:"</string>
@@ -1767,10 +1768,10 @@
<item quantity="one"><xliff:g id="COUNT">%1$s</xliff:g> ինքնալցման առաջարկ</item>
<item quantity="other"><xliff:g id="COUNT">%1$s</xliff:g> ինքնալցման առաջարկ</item>
</plurals>
- <string name="autofill_save_title" msgid="3345527308992082601">"Պահե՞լ <b><xliff:g id="LABEL">%1$s</xliff:g></b>-ում:"</string>
- <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Պահե՞լ <xliff:g id="TYPE">%1$s</xliff:g>-ը <b><xliff:g id="LABEL">%2$s</xliff:g></b>-ում:"</string>
- <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Պահե՞լ <xliff:g id="TYPE_0">%1$s</xliff:g>-ը և <xliff:g id="TYPE_1">%2$s</xliff:g>-ը <b><xliff:g id="LABEL">%3$s</xliff:g></b>-ում:"</string>
- <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Պահե՞լ <xliff:g id="TYPE_0">%1$s</xliff:g>-ը, <xliff:g id="TYPE_1">%2$s</xliff:g>-ը և <xliff:g id="TYPE_2">%3$s</xliff:g>-ը <b><xliff:g id="LABEL">%4$s</xliff:g></b>-ում:"</string>
+ <string name="autofill_save_title" msgid="3345527308992082601">"Պահե՞լ <b><xliff:g id="LABEL">%1$s</xliff:g></b> ծառայությունում"</string>
+ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Պահե՞լ <xliff:g id="TYPE">%1$s</xliff:g>ը <b><xliff:g id="LABEL">%2$s</xliff:g></b> ծառայությունում"</string>
+ <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Պահե՞լ <xliff:g id="TYPE_0">%1$s</xliff:g>ն ու <xliff:g id="TYPE_1">%2$s</xliff:g>ը <b><xliff:g id="LABEL">%3$s</xliff:g></b> ծառայությունում"</string>
+ <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Պահե՞լ <xliff:g id="TYPE_0">%1$s</xliff:g>ը, <xliff:g id="TYPE_1">%2$s</xliff:g>ն ու <xliff:g id="TYPE_2">%3$s</xliff:g>ը <b><xliff:g id="LABEL">%4$s</xliff:g></b> ծառայությունում"</string>
<string name="autofill_save_yes" msgid="6398026094049005921">"Պահել"</string>
<string name="autofill_save_no" msgid="2625132258725581787">"Ոչ"</string>
<string name="autofill_save_type_password" msgid="5288448918465971568">"գաղտնաբառ"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 2d04fa0..89e96f9 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telepon"</string>
<string name="map" msgid="6068210738233985748">"Peta"</string>
<string name="browse" msgid="6993590095938149861">"Browser"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ruang penyimpanan hampir habis"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Beberapa fungsi sistem mungkin tidak dapat bekerja"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Penyimpanan tidak cukup untuk sistem. Pastikan Anda memiliki 250 MB ruang kosong, lalu mulai ulang."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Batal"</string>
<string name="yes" msgid="5362982303337969312">"Oke"</string>
<string name="no" msgid="5141531044935541497">"Batal"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"TUTUP"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Perhatian"</string>
<string name="loading" msgid="7933681260296021180">"Memuat..."</string>
<string name="capital_on" msgid="1544682755514494298">"AKTIF"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Selalu tampilkan"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Aktifkan kembali dialog ini di Setelan sistem > Apl > Terdownload."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikasi tidak merespons"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> mungkin menggunakan terlalu banyak memori."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak mendukung setelan Ukuran layar saat ini dan dapat menunjukkan perilaku yang tak diharapkan."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Selalu tampilkan"</string>
<string name="smv_application" msgid="3307209192155442829">"Apl <xliff:g id="APPLICATION">%1$s</xliff:g> (proses <xliff:g id="PROCESS">%2$s</xliff:g>) telah melanggar kebijakan StrictMode yang diberlakukannya sendiri."</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 482ce8a..2850fec 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Sími"</string>
<string name="map" msgid="6068210738233985748">"Kort"</string>
<string name="browse" msgid="6993590095938149861">"Vafri"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Geymslurýmið er senn á þrotum"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Sumir kerfiseiginleikar kunna að vera óvirkir"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Ekki nægt geymslurými fyrir kerfið. Gakktu úr skugga um að 250 MB séu laus og endurræstu."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Hætta við"</string>
<string name="yes" msgid="5362982303337969312">"Í lagi"</string>
<string name="no" msgid="5141531044935541497">"Hætta við"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"LOKA"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Athugaðu"</string>
<string name="loading" msgid="7933681260296021180">"Hleður…"</string>
<string name="capital_on" msgid="1544682755514494298">"KVEIKT"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Breyta stærð"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Sýna alltaf"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Þú getur kveikt aftur á þessu undir Kerfisstillingar > Forrit > Sótt."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Forritið svarar ekki"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> notar hugsanlega of mikið minni."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> styður ekki núverandi skjástærðarstillingu og gæti því ekki virkað sem skyldi."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Sýna alltaf"</string>
<string name="smv_application" msgid="3307209192155442829">"Forritið <xliff:g id="APPLICATION">%1$s</xliff:g> (ferli <xliff:g id="PROCESS">%2$s</xliff:g>) hefur brotið gegn eigin StrictMode-stefnu."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index ba1a866..0274602 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefono"</string>
<string name="map" msgid="6068210738233985748">"Mappe"</string>
<string name="browse" msgid="6993590095938149861">"Browser"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Spazio di archiviazione in esaurimento"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Alcune funzioni di sistema potrebbero non funzionare"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Memoria insufficiente per il sistema. Assicurati di avere 250 MB di spazio libero e riavvia."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Annulla"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Annulla"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"CHIUDI"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Attenzione"</string>
<string name="loading" msgid="7933681260296021180">"Caricamento..."</string>
<string name="capital_on" msgid="1544682755514494298">"ON"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostra sempre"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Riattivala in Impostazioni di sistema > Applicazioni > Scaricate."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"L\'app non risponde"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Probabilmente <xliff:g id="APP_NAME">%1$s</xliff:g> utilizza troppa memoria."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> non supporta le dimensioni di visualizzazione attualmente impostate e potrebbe comportarsi in modo imprevisto."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostra sempre"</string>
<string name="smv_application" msgid="3307209192155442829">"L\'applicazione <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) ha violato la norma StrictMode autoimposta."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 41530ce..5fa6c52 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1020,6 +1020,10 @@
<string name="dial" msgid="4204975095406423102">"טלפון"</string>
<string name="map" msgid="6068210738233985748">"מפות"</string>
<string name="browse" msgid="6993590095938149861">"דפדפן"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"שטח האחסון אוזל"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"ייתכן שפונקציות מערכת מסוימות לא יפעלו"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"אין מספיק שטח אחסון עבור המערכת. ודא שיש לך שטח פנוי בגודל 250MB התחל שוב."</string>
@@ -1029,8 +1033,7 @@
<string name="cancel" msgid="6442560571259935130">"ביטול"</string>
<string name="yes" msgid="5362982303337969312">"אישור"</string>
<string name="no" msgid="5141531044935541497">"ביטול"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"סגירה"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"זהירות"</string>
<string name="loading" msgid="7933681260296021180">"טוען..."</string>
<string name="capital_on" msgid="1544682755514494298">"מופעל"</string>
@@ -1087,10 +1090,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"שינוי קנה-מידה"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"הצג תמיד"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"אפשר תכונה זו מחדש ב\'הגדרות מערכת\' < Google Apps < \'הורדות\'."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"האפליקציה לא מגיבה"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"ייתכן שהאפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> משתמשת ביותר מדי שטח זיכרון."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> אינו תומך בהגדרת הגודל הנוכחית של התצוגה, והתנהגותו עשויה להיות בלתי צפויה."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"הצג תמיד"</string>
<string name="smv_application" msgid="3307209192155442829">"האפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g> (תהליך <xliff:g id="PROCESS">%2$s</xliff:g>) הפר את מדיניות StrictMode באכיפה עצמית שלו."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 3b9bf410..78e59a3 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"電話"</string>
<string name="map" msgid="6068210738233985748">"マップ"</string>
<string name="browse" msgid="6993590095938149861">"ブラウザ"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"空き容量わずか"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"一部のシステム機能が動作しない可能性があります"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"システムに十分な容量がありません。250MBの空き容量を確保して再起動してください。"</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"キャンセル"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"キャンセル"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"閉じる"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"注意"</string>
<string name="loading" msgid="7933681260296021180">"読み込んでいます..."</string>
<string name="capital_on" msgid="1544682755514494298">"ON"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"スケール"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"常に表示"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"[システム設定]>[アプリ]>[ダウンロード済み]で再度有効にします。"</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"このアプリは応答していません"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」のメモリの使用量は多すぎる可能性があります。"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」は現在の [表示サイズ] 設定に対応していないため、予期しない動作が発生するおそれがあります。"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"常に表示"</string>
<string name="smv_application" msgid="3307209192155442829">"アプリ「<xliff:g id="APPLICATION">%1$s</xliff:g>」(プロセス「<xliff:g id="PROCESS">%2$s</xliff:g>」)でStrictModeポリシー違反がありました。"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 241da78..d9947b0 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"ტელეფონი"</string>
<string name="map" msgid="6068210738233985748">"Maps"</string>
<string name="browse" msgid="6993590095938149861">"ბრაუზერი"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"თავისუფალი ადგილი იწურება"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"სისტემის ზოგიერთმა ფუნქციამ შესაძლოა არ იმუშავოს"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"სისტემისათვის საკმარისი საცავი არ არის. დარწმუნდით, რომ იქონიოთ სულ მცირე 250 მბაიტი თავისუფალი სივრცე და დაიწყეთ ხელახლა."</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 13e5e71..95e1459 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Телефон"</string>
<string name="map" msgid="6068210738233985748">"Maps"</string>
<string name="browse" msgid="6993590095938149861">"Браузер"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Жадта орын азайып барады"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Жүйенің кейбір функциялары жұмыс істемеуі мүмкін"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Жүйе үшін жад жеткіліксіз. 250 МБ бос орын бар екенін тексеріп, қайта іске қосыңыз."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Бас тарту"</string>
<string name="yes" msgid="5362982303337969312">"Жарайды"</string>
<string name="no" msgid="5141531044935541497">"Бас тарту"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"ЖАБУ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Назар аударыңыз"</string>
<string name="loading" msgid="7933681260296021180">"Жүктелуде…"</string>
<string name="capital_on" msgid="1544682755514494298">"Қосулы"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Меже"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Үнемі көрсету"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Мұны «Жүйелік параметрлер» > «Қолданбалар» > «Жүктелгендер» тармағында қосыңыз."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Қолданба жауап бермеуде"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> жадтан тым көп орын пайдалануда."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасында \"Дисплей өлшемі\" параметрінің таңдалған мәніне қолдау көрсетілмейді, сондықтан дұрыс жұмыс істемеуі мүмкін."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Үнемі көрсету"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасы (<xliff:g id="PROCESS">%2$s</xliff:g> процесі) өзі қолданған StrictMode саясатын бұзды."</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 4509196..ae11db4 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"ទូរសព្ទ"</string>
<string name="map" msgid="6068210738233985748">"ផែនទី"</string>
<string name="browse" msgid="6993590095938149861">"កម្មវិធីរុករកតាមអ៊ីនធឺណិត"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"អស់ទំហំផ្ទុក"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"មុខងារប្រព័ន្ធមួយចំនួនអាចមិនដំណើរការ"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"មិនមានទំហំផ្ទុកគ្រប់គ្រាន់សម្រាប់ប្រព័ន្ធ។ សូមប្រាកដថាអ្នកមានទំហំទំនេរ 250MB ហើយចាប់ផ្ដើមឡើងវិញ។"</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"បោះបង់"</string>
<string name="yes" msgid="5362982303337969312">"យល់ព្រម"</string>
<string name="no" msgid="5141531044935541497">"បោះបង់"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"បិទ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"ប្រយ័ត្ន"</string>
<string name="loading" msgid="7933681260296021180">"កំពុងផ្ទុក..."</string>
<string name="capital_on" msgid="1544682755514494298">"បើក"</string>
@@ -1049,10 +1052,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"មាត្រដ្ឋាន"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"បង្ហាញជានិច្ច"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"បើកវាឡើងវិញក្នុងការកំណត់ប្រព័ន្ធ > កម្មវិធី > ទាញយក។"</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"កម្មវិធីមិនមានការឆ្លើយតបទេ"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> អាចកំពុងប្រើអង្គចងចាំច្រើនពេក។"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> មិនគាំទ្រការកំណត់ទំហំនៃការបង្ហាញបច្ចុប្បន្ន និងអាចមានសកម្មភាពខុសពីការរំពឹងទុក។"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"បង្ហាញជានិច្ច"</string>
<string name="smv_application" msgid="3307209192155442829">"កម្មវិធី <xliff:g id="APPLICATION">%1$s</xliff:g> (ដំណើរការ <xliff:g id="PROCESS">%2$s</xliff:g>) បានបំពានគោលនយោបាយរបៀបតឹងរ៉ឹងអនុវត្តដោយខ្លួនឯង។"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index ef5aba9..125ccbb 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"ಫೋನ್"</string>
<string name="map" msgid="6068210738233985748">"ನಕ್ಷೆಗಳು"</string>
<string name="browse" msgid="6993590095938149861">"ಬ್ರೌಸರ್"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"ಸಂಗ್ರಹಣೆ ಸ್ಥಳವು ತುಂಬಿದೆ"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"ಕೆಲವು ಸಿಸ್ಟಂ ಕಾರ್ಯವಿಧಾನಗಳು ಕಾರ್ಯನಿರ್ವಹಿಸದೇ ಇರಬಹುದು"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"ಸಿಸ್ಟಂನಲ್ಲಿ ಸಾಕಷ್ಟು ಸಂಗ್ರಹಣೆಯಿಲ್ಲ. ನೀವು 250MB ನಷ್ಟು ಖಾಲಿ ಸ್ಥಳವನ್ನು ಹೊಂದಿರುವಿರಾ ಎಂಬುದನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ ಹಾಗೂ ಮರುಪ್ರಾರಂಭಿಸಿ."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"ರದ್ದುಮಾಡಿ"</string>
<string name="yes" msgid="5362982303337969312">"ಸರಿ"</string>
<string name="no" msgid="5141531044935541497">"ರದ್ದುಮಾಡಿ"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"ಮುಚ್ಚಿ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"ಗಮನಿಸಿ"</string>
<string name="loading" msgid="7933681260296021180">"ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ..."</string>
<string name="capital_on" msgid="1544682755514494298">"ಆನ್ ಮಾಡಿ"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"ಮಾಪಕ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"ಯಾವಾಗಲೂ ತೋರಿಸಿ"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"ಸಿಸ್ಟಂ ಸೆಟ್ಟಿಂಗ್ಗಳು > ಅಪ್ಲಿಕೇಶನ್ಗಳು > ಡೌನ್ಲೋಡ್ ಆಗಿರುವುದರಲ್ಲಿ ಇದನ್ನು ಮರು ಸಕ್ರಿಯಗೊಳಿಸಿ."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"ಅಪ್ಲಿಕೇಶನ್ ಪ್ರತಿಕ್ರಿಯಿಸುತ್ತಿಲ್ಲ"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಹೆಚ್ಚು ಮೆಮೊರಿಯನ್ನು ಬಳಸಿಕೊಳ್ಳುತ್ತಿರಬಹುದು."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಪ್ರಸ್ತುತ ಪ್ರದರ್ಶನ ಗಾತ್ರದ ಸೆಟ್ಟಿಂಗ್ ಅನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ ಮತ್ತು ಅನಿರೀಕ್ಷಿತವಾಗಿ ವರ್ತಿಸಬಹುದು."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"ಯಾವಾಗಲೂ ತೋರಿಸು"</string>
<string name="smv_application" msgid="3307209192155442829">"ಅಪ್ಲಿಕೇಶನ್ <xliff:g id="APPLICATION">%1$s</xliff:g> (ಪ್ರಕ್ರಿಯೆಯು <xliff:g id="PROCESS">%2$s</xliff:g>) ತನ್ನ ಸ್ವಯಂ-ಜಾರಿ ಕಠಿಣ ಮೋಡ್ ನೀತಿಯನ್ನು ಉಲ್ಲಂಘನೆ ಮಾಡಿದೆ."</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 9a9a36c..c253742 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"전화"</string>
<string name="map" msgid="6068210738233985748">"지도"</string>
<string name="browse" msgid="6993590095938149861">"브라우저"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"저장 공간이 부족함"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"일부 시스템 기능이 작동하지 않을 수 있습니다."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"시스템의 저장 공간이 부족합니다. 250MB의 여유 공간이 확보한 후 다시 시작하세요."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"취소"</string>
<string name="yes" msgid="5362982303337969312">"확인"</string>
<string name="no" msgid="5141531044935541497">"취소"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"닫기"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"주의"</string>
<string name="loading" msgid="7933681260296021180">"로드 중.."</string>
<string name="capital_on" msgid="1544682755514494298">"ON"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"배율"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"항상 표시"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"시스템 설정 > 앱 > 다운로드로 이동하여 이 모드를 다시 사용하도록 설정합니다."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"앱이 응답하지 않음"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 메모리를 과도하게 사용하는 것으로 보입니다."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> 앱은 현재 디스플레이 크기 설정을 지원하지 않으며 예기치 않게 동작할 수 있습니다."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"항상 표시"</string>
<string name="smv_application" msgid="3307209192155442829">"앱 <xliff:g id="APPLICATION">%1$s</xliff:g>(프로세스 <xliff:g id="PROCESS">%2$s</xliff:g>)이(가) 자체 시행 StrictMode 정책을 위반했습니다."</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 70e23a8..77f3b0c 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Телефон"</string>
<string name="map" msgid="6068210738233985748">"Карталар"</string>
<string name="browse" msgid="6993590095938149861">"Серепчи"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Сактагычта орун калбай баратат"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Системанын кээ бир функциялары иштебеши мүмкүн"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Тутумда сактагыч жетишсиз. 250МБ бош орун бар экенин текшерип туруп, өчүрүп күйгүзүңүз."</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 175b27f..d53c702 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"ໂທລະສັບ"</string>
<string name="map" msgid="6068210738233985748">"ແຜນທີ່"</string>
<string name="browse" msgid="6993590095938149861">"ໂປຣແກຣມທ່ອງເວັບ"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"ພື້ນທີ່ຈັດເກັບຂໍ້ມູນກຳລັງຈະເຕັມ"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"ການເຮັດວຽກບາງຢ່າງຂອງລະບົບບາງອາດຈະໃຊ້ບໍ່ໄດ້"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"ບໍ່ມີບ່ອນເກັບຂໍ້ມູນພຽງພໍສຳລັບລະບົບ. ກວດສອບໃຫ້ແນ່ໃຈວ່າທ່ານມີພື້ນທີ່ຫວ່າງຢ່າງໜ້ອຍ 250MB ແລ້ວລອງໃໝ່."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"ຍົກເລີກ"</string>
<string name="yes" msgid="5362982303337969312">"ຕົກລົງ"</string>
<string name="no" msgid="5141531044935541497">"ຍົກເລີກ"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"ປິດ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"ກະລຸນາຮັບຊາບ"</string>
<string name="loading" msgid="7933681260296021180">"ກຳລັງໂຫລດ..."</string>
<string name="capital_on" msgid="1544682755514494298">"ເປີດ"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"ຂະໜາດ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"ສະແດງຕະຫຼອດເວລາ"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"ເປີດການເຮັດວຽກນີ້ຄືນໄດ້ໃນ ການຕັ້ງຄ່າລະບົບ > ແອັບຯ > ດາວໂຫລດແລ້ວ"</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"ແອັບບໍ່ຕອບສະໜອງ"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> ອາດກຳລັງໃຊ້ໜ່ວຍຄວາມຈຳຫຼາຍເກີນໄປ"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ່ຮອງຮັບການຕັ້ງຄ່າຂະໜາດສະແດງຜົນປັດຈຸບັນ ແລະ ອາດມີຄວາມຜິດພາດໄດ້."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"ສະແດງທຸກເທື່ອ"</string>
<string name="smv_application" msgid="3307209192155442829">"ແອັບຯ <xliff:g id="APPLICATION">%1$s</xliff:g> (ໂປຣເຊສ <xliff:g id="PROCESS">%2$s</xliff:g>) ໄດ້ລະເມີດນະໂຍບາຍ StrictMode ທີ່ບັງຄັບໃຊ້ດ້ວຍໂຕເອງ."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index d011d8b..a3deaa7 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1020,6 +1020,10 @@
<string name="dial" msgid="4204975095406423102">"Telefonas"</string>
<string name="map" msgid="6068210738233985748">"Žemėlapiai"</string>
<string name="browse" msgid="6993590095938149861">"Naršyklė"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Mažėja laisvos saugyklos vietos"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Kai kurios sistemos funkcijos gali neveikti"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Sistemos saugykloje nepakanka vietos. Įsitikinkite, kad yra 250 MB laisvos vietos, ir paleiskite iš naujo."</string>
@@ -1029,8 +1033,7 @@
<string name="cancel" msgid="6442560571259935130">"Atšaukti"</string>
<string name="yes" msgid="5362982303337969312">"Gerai"</string>
<string name="no" msgid="5141531044935541497">"Atšaukti"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"UŽDARYTI"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Dėmesio"</string>
<string name="loading" msgid="7933681260296021180">"Įkeliama..."</string>
<string name="capital_on" msgid="1544682755514494298">"ĮJ."</string>
@@ -1087,10 +1090,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Mastelis"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Visada rodyti"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Įgalinkite jį iš naujo nuėję į „Sistemos nustatymai“ > „Programos“ > „Atsisiųsta“."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Programa nereaguoja"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ gali naudoti per daug atminties."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Programoje „<xliff:g id="APP_NAME">%1$s</xliff:g>“ nepalaikomas dabartinis ekrano dydžio nustatymas ir ji gali netinkamai veikti."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Visada rodyti"</string>
<string name="smv_application" msgid="3307209192155442829">"Programa „<xliff:g id="APPLICATION">%1$s</xliff:g>“ (procesas „<xliff:g id="PROCESS">%2$s</xliff:g>“) pažeidė savo vykdomą „StrictMode“ politiką."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index ab55434..c323fcc 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1000,6 +1000,10 @@
<string name="dial" msgid="4204975095406423102">"Tālrunis"</string>
<string name="map" msgid="6068210738233985748">"Kartes"</string>
<string name="browse" msgid="6993590095938149861">"Pārlūkprogramma"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Paliek maz brīvas vietas"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Dažas sistēmas funkcijas var nedarboties."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Sistēmai pietrūkst vietas. Atbrīvojiet vismaz 250 MB vietas un restartējiet ierīci."</string>
@@ -1009,8 +1013,7 @@
<string name="cancel" msgid="6442560571259935130">"Atcelt"</string>
<string name="yes" msgid="5362982303337969312">"Labi"</string>
<string name="no" msgid="5141531044935541497">"Atcelt"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"AIZVĒRT"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Uzmanību!"</string>
<string name="loading" msgid="7933681260296021180">"Notiek ielāde..."</string>
<string name="capital_on" msgid="1544682755514494298">"IESLĒGT"</string>
@@ -1067,10 +1070,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Mērogs"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Rādīt vienmēr"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Atkārtoti iespējojiet šeit: Sistēmas iestatījumi > Lietotnes > Lejupielādētās."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Lietotne nereaģē"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Iespējams, lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> aizņem pārāk daudz vietas atmiņā."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Lietotnē <xliff:g id="APP_NAME">%1$s</xliff:g> netiek atbalstīts pašreizējais displeja lieluma iestatījums, tādēļ tā var tikt attēlota neparedzētā veidā."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Rādīt vienmēr"</string>
<string name="smv_application" msgid="3307209192155442829">"Lietotne <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) ir pārkāpusi savu pašieviesto StrictMode politiku."</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 934e9b10..c3de4a9 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Телефон"</string>
<string name="map" msgid="6068210738233985748">"„Карти“"</string>
<string name="browse" msgid="6993590095938149861">"Прелистувач"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Меморијата е речиси полна"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Некои системски функции може да не работат"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Нема доволно меморија во системот. Проверете дали има слободен простор од 250 МБ и рестартирајте."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Откажи"</string>
<string name="yes" msgid="5362982303337969312">"Во ред"</string>
<string name="no" msgid="5141531044935541497">"Откажи"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"ЗАТВОРИ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Внимание"</string>
<string name="loading" msgid="7933681260296021180">"Се вчитува..."</string>
<string name="capital_on" msgid="1544682755514494298">"ВКЛУЧЕНО"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Размер"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Покажи секогаш"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Повторно овозможете го ова во Системски поставки > Апликации > Преземено."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Апликацијата не реагира"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> може да користи премногу меморија."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> не ја поддржува тековната поставка за големина на екранот и може да се однесува непредвидено."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Секогаш прикажувај"</string>
<string name="smv_application" msgid="3307209192155442829">"Апликацијата <xliff:g id="APPLICATION">%1$s</xliff:g> (процес <xliff:g id="PROCESS">%2$s</xliff:g>) ја прекрши политиката StrictMode што си ја наметна врз себеси."</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 9a1cacd..2623167 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"ഫോണ്"</string>
<string name="map" msgid="6068210738233985748">"മാപ്സ്"</string>
<string name="browse" msgid="6993590095938149861">"ബ്രൗസർ"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"സംഭരണയിടം കഴിഞ്ഞു"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"ചില സിസ്റ്റം പ്രവർത്തനങ്ങൾ പ്രവർത്തിക്കണമെന്നില്ല."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"സിസ്റ്റത്തിനായി മതിയായ സംഭരണമില്ല. 250MB സൗജന്യ സംഭരണമുണ്ടെന്ന് ഉറപ്പുവരുത്തി പുനരാരംഭിക്കുക."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"റദ്ദാക്കുക"</string>
<string name="yes" msgid="5362982303337969312">"ശരി"</string>
<string name="no" msgid="5141531044935541497">"റദ്ദാക്കുക"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"അടയ്ക്കുക"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"ശ്രദ്ധിക്കുക"</string>
<string name="loading" msgid="7933681260296021180">"ലോഡുചെയ്യുന്നു..."</string>
<string name="capital_on" msgid="1544682755514494298">"ഓൺ"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"സ്കെയിൽ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"എപ്പോഴും പ്രദര്ശിപ്പിക്കുക"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"സിസ്റ്റം ക്രമീകരണങ്ങൾ > അപ്ലിക്കേഷനുകൾ > ഡൗൺലോഡുചെയ്തവ എന്നതിൽ ഇത് വീണ്ടും പ്രവർത്തനക്ഷമമാക്കുക."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"ആപ്പ് പ്രതികരിക്കുന്നില്ല"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> വളരെയധികം മെമ്മറി ഉപയോഗിക്കുന്നുണ്ടാകാം."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"നിലവിലെ ഡിസ്പ്ലേ വലുപ്പ ക്രമീകരണത്തെ <xliff:g id="APP_NAME">%1$s</xliff:g> പിന്തുണയ്ക്കുന്നില്ല, അതിനാൽ പ്രതീക്ഷിക്കാത്ത തരത്തിൽ ആപ്പ് പ്രവർത്തിച്ചേക്കാം."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"എല്ലായ്പ്പോഴും ദൃശ്യമാക്കുക"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> എന്ന അപ്ലിക്കേഷൻ (<xliff:g id="PROCESS">%2$s</xliff:g> പ്രോസസ്സ്) അതിന്റെ സ്വയം നിർബന്ധിത StrictMode നയം ലംഘിച്ചു."</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index ffac0f2..ce09140 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Утас"</string>
<string name="map" msgid="6068210738233985748">"Газрын зураг"</string>
<string name="browse" msgid="6993590095938149861">"Хөтөч"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Сангийн хэмжээ дутагдаж байна"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Зарим систем функц ажиллахгүй байна"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Системд хангалттай сан байхгүй байна. 250MБ чөлөөтэй зай байгаа эсэхийг шалгаад дахин эхлүүлнэ үү."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Цуцлах"</string>
<string name="yes" msgid="5362982303337969312">"ОК"</string>
<string name="no" msgid="5141531044935541497">"Цуцлах"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"ХААХ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Анхаар"</string>
<string name="loading" msgid="7933681260296021180">"Ачааллаж байна..."</string>
<string name="capital_on" msgid="1544682755514494298">"Идэвхтэй"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Цар хэмжээ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Байнга харуулах"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Энийг Системийн тохиргоо > Апп > Татаж авсан дотроос дахин идэвхтэй болгох боломжтой."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Апп хариу өгөхгүй байна"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> хэт их санах ой ашиглаж байж болзошгүй."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> нь Дэлгэцийн хэмжээний одоогийн тохиргоог дэмждэггүй учир буруу ажиллаж болзошгүй."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Байнга харуулах"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> апп (<xliff:g id="PROCESS">%2$s</xliff:g> процесс) өөрийнхөө StrictMode бодлогыг зөрчив."</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index cca0a5e..2d0cad7 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"फोन"</string>
<string name="map" msgid="6068210738233985748">"नकाशे"</string>
<string name="browse" msgid="6993590095938149861">"ब्राउझर"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"संचयन स्थान संपत आहे"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"काही सिस्टम कार्ये कार्य करू शकत नाहीत"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"सिस्टीमसाठी पुरेसे संचयन नाही. आपल्याकडे 250MB मोकळे स्थान असल्याचे सुनिश्चित करा आणि रीस्टार्ट करा."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"रद्द करा"</string>
<string name="yes" msgid="5362982303337969312">"ठीक"</string>
<string name="no" msgid="5141531044935541497">"रद्द करा"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"बंद करा"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"लक्ष द्या"</string>
<string name="loading" msgid="7933681260296021180">"लोड करीत आहे..."</string>
<string name="capital_on" msgid="1544682755514494298">"चालू"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"स्केल"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"नेहमी दर्शवा"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"सिस्टम सेटिंग्ज > Apps > डाउनलोड केलेले मध्ये हे पुन्हा-सक्षम करा."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"अॅप प्रतिसाद देत नाही"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> कदाचित बरीच मेमरी वापरत आहे."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> वर्तमान डिस्प्ले आकार सेटिंगला समर्थन देत नाही आणि अनपेक्षित वर्तन करू शकते."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"नेहमी दर्शवा"</string>
<string name="smv_application" msgid="3307209192155442829">"अॅप <xliff:g id="APPLICATION">%1$s</xliff:g> (प्रक्रिया <xliff:g id="PROCESS">%2$s</xliff:g>) ने तिच्या स्वयं-लागू केलेल्या StrictMode धोरणाचे उल्लंघन केले आहे."</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 179ea4a..536f2c2 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefon"</string>
<string name="map" msgid="6068210738233985748">"Peta"</string>
<string name="browse" msgid="6993590095938149861">"Penyemak imbas"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ruang storan semakin berkurangan"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Beberapa fungsi sistem mungkin tidak berfungsi"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Tidak cukup storan untuk sistem. Pastikan anda mempunyai 250MB ruang kosong dan mulakan semula."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Batal"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Batal"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"TUTUP"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Perhatian"</string>
<string name="loading" msgid="7933681260296021180">"Memuatkan…"</string>
<string name="capital_on" msgid="1544682755514494298">"HIDUP"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Sentiasa tunjukkan"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Dayakan semula kod kompak ini tetapan Sistem > Apl > Dimuat turun."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Apl tidak bertindak balas"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> mungkin menggunakan terlalu banyak memori."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak menyokong tetapan saiz Paparan semasa dan mungkin menunjukkan gelagat yang tidak dijangka."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Sentiasa tunjukkan"</string>
<string name="smv_application" msgid="3307209192155442829">"Apl <xliff:g id="APPLICATION">%1$s</xliff:g> (proses <xliff:g id="PROCESS">%2$s</xliff:g>) telah melanggar dasar Mod Tegasnya sendiri."</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 8e252da..c0539a5 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"ဖုန်း"</string>
<string name="map" msgid="6068210738233985748">"Maps"</string>
<string name="browse" msgid="6993590095938149861">"ဘရောင်ဇာ"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"သိမ်းဆည်သော နေရာ နည်းနေပါသည်"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"တချို့ စနစ်လုပ်ငန်းများ အလုပ် မလုပ်ခြင်း ဖြစ်နိုင်ပါသည်"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"စနစ်အတွက် သိုလှောင်ခန်း မလုံလောက်ပါ။ သင့်ဆီမှာ နေရာလွတ် ၂၅၀ MB ရှိတာ စစ်ကြည့်ပြီး စတင်ပါ။"</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"မလုပ်တော့"</string>
<string name="yes" msgid="5362982303337969312">"အိုကေ"</string>
<string name="no" msgid="5141531044935541497">"မလုပ်တော့"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"ပိတ်ရန်"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"သတိပြုရန်"</string>
<string name="loading" msgid="7933681260296021180">"တင်နေ…"</string>
<string name="capital_on" msgid="1544682755514494298">"ဖွင့်ရန်"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"စကေး"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"အမြဲပြသရန်"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"ဒါကို စနစ် ဆက်တင်များထဲ ပြန်ဖွင့်ပေးရန် > Apps > ဒေါင်းလုဒ် လုပ်ပြီး။"</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"အက်ပ်က တုံ့ပြန်မှုမရှိပါ"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> က နေရာအလွန်အကျွံ ယူထားပုံရပါသည်။"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> သည် လက်ရှိ မျက်နှာပြင်အရွယ်အစားကို ပံ့ပိုးထားခြင်း မရှိပါ။ မမျှော်လင့်နိုင်သည့် ချွတ်ယွင်းချက်များ ဖြစ်ပေါ်နိုင်ပါသည်။"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"အမြဲပြပါ"</string>
<string name="smv_application" msgid="3307209192155442829">"app <xliff:g id="APPLICATION">%1$s</xliff:g> (လုပ်ငန်းစဉ် <xliff:g id="PROCESS">%2$s</xliff:g>) က ကိုယ်တိုင် ပြဌာန်းခဲ့သည့် StrictMode မူဝါဒကို ချိုးဖောက်ခဲ့သည်။"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 2672fd3..4eb0f1d 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefon"</string>
<string name="map" msgid="6068210738233985748">"Kart"</string>
<string name="browse" msgid="6993590095938149861">"Nettleser"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Lite ledig lagringsplass"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Enkelte systemfunksjoner fungerer muligens ikke slik de skal"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Det er ikke nok lagringsplass for systemet. Kontrollér at du har 250 MB ledig plass, og start på nytt."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Avbryt"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Avbryt"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"LUKK"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Merk"</string>
<string name="loading" msgid="7933681260296021180">"Laster inn …"</string>
<string name="capital_on" msgid="1544682755514494298">"På"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Vis alltid"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reaktiver dette i systeminnstillingene > Apper > Nedlastet."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Appen svarer ikke"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> bruker muligens for mye minne."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> støtter ikke den nåværende innstillingen for skjermstørrelse og fungerer kanskje ikke som den skal."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Vis alltid"</string>
<string name="smv_application" msgid="3307209192155442829">"Appen <xliff:g id="APPLICATION">%1$s</xliff:g> (prosessen <xliff:g id="PROCESS">%2$s</xliff:g>) har brutt de selvpålagte StrictMode-retningslinjene."</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index a61563d..16743d5 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"फोन गर्नुहोस्"</string>
<string name="map" msgid="6068210738233985748">"नक्सा"</string>
<string name="browse" msgid="6993590095938149861">"ब्राउजर"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"भण्डारण ठाउँ सकिँदै छ"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"सायद केही प्रणाली कार्यक्रमहरूले काम गर्दैनन्"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"प्रणालीको लागि पर्याप्त भण्डारण छैन। तपाईँसँग २५० मेगा बाइट ठाउँ खाली भएको निश्चित गर्नुहोस् र फेरि सुरु गर्नुहोस्।"</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"रद्द गर्नुहोस्"</string>
<string name="yes" msgid="5362982303337969312">"ठीक छ"</string>
<string name="no" msgid="5141531044935541497">"रद्द गर्नुहोस्"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"बन्द गर्नुहोस्"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"सावधानी"</string>
<string name="loading" msgid="7933681260296021180">"लोड हुँदै..."</string>
<string name="capital_on" msgid="1544682755514494298">"चालु"</string>
@@ -1053,10 +1056,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"स्केल"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"सधैँ देखाउनुहोस्"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"प्रणाली सेटिङहरूमा यसलाई पुनःसक्षम गराउनुहोस् > अनुप्रयोगहरू > डाउनलोड गरेको।"</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"अनुप्रयोग चलिरहेको छैन"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> ले अत्यधिक मेमोरी प्रयोग गरिरहेको हुनसक्छ।"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ले हालको प्रदर्शनको आकार सम्बन्धी सेटिङलाई समर्थन गर्दैन र अप्रत्याशित तरिकाले व्यवहार गर्न सक्छ।"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"सधैँ देखाउनुहोस्"</string>
<string name="smv_application" msgid="3307209192155442829">"अनुप्रयोग <xliff:g id="APPLICATION">%1$s</xliff:g> (प्रक्रिया <xliff:g id="PROCESS">%2$s</xliff:g>) ले यसको स्वयं-लागु गरिएको स्ट्रिटमोड नीति उलङ्घन गरेको छ।"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 0771ded..e914caf 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefoon"</string>
<string name="map" msgid="6068210738233985748">"Kaarten"</string>
<string name="browse" msgid="6993590095938149861">"Browser"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Opslagruimte is bijna vol"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Bepaalde systeemfuncties werken mogelijk niet"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Onvoldoende opslagruimte voor het systeem. Zorg ervoor dat je 250 MB vrije ruimte hebt en start opnieuw."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Annuleren"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Annuleren"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"SLUITEN"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Let op"</string>
<string name="loading" msgid="7933681260296021180">"Laden..."</string>
<string name="capital_on" msgid="1544682755514494298">"AAN"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Schaal"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Altijd weergeven"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"U kunt dit opnieuw inschakelen via Systeeminstellingen > Apps > Gedownload."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"App reageert niet"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> gebruikt mogelijk te veel geheugen"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> biedt geen ondersteuning voor de huidige instelling voor weergavegrootte en kan onverwacht gedrag vertonen."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Altijd weergeven"</string>
<string name="smv_application" msgid="3307209192155442829">"De app <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) heeft het zelf afgedwongen StrictMode-beleid geschonden."</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 6cbc135..7917b23 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"ਫ਼ੋਨ ਕਰੋ"</string>
<string name="map" msgid="6068210738233985748">"ਨਕਸ਼ੇ"</string>
<string name="browse" msgid="6993590095938149861">"ਬ੍ਰਾਊਜ਼ਰ"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"ਸਟੋਰੇਜ ਦੀ ਜਗ੍ਹਾ ਖਤਮ ਹੋ ਰਹੀ ਹੈ"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"ਕੁਝ ਸਿਸਟਮ ਫੰਕਸ਼ਨ ਕੰਮ ਨਹੀਂ ਵੀ ਕਰ ਸਕਦੇ"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"ਸਿਸਟਮ ਲਈ ਲੋੜੀਂਦੀ ਸਟੋਰੇਜ ਨਹੀਂ ਹੈ। ਯਕੀਨੀ ਬਣਾਓ ਕਿ ਤੁਹਾਡੇ ਕੋਲ 250MB ਖਾਲੀ ਜਗ੍ਹਾ ਹੈ ਅਤੇ ਮੁੜ-ਚਾਲੂ ਕਰੋ।"</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"ਰੱਦ ਕਰੋ"</string>
<string name="yes" msgid="5362982303337969312">"ਠੀਕ"</string>
<string name="no" msgid="5141531044935541497">"ਰੱਦ ਕਰੋ"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"ਬੰਦ ਕਰੋ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"ਧਿਆਨ ਦਿਓ"</string>
<string name="loading" msgid="7933681260296021180">"ਲੋਡ ਹੋ ਰਿਹਾ ਹੈ..."</string>
<string name="capital_on" msgid="1544682755514494298">"ਚਾਲੂ"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"ਸਕੇਲ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"ਹਮੇਸ਼ਾਂ ਦਿਖਾਓ"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"ਸਿਸਟਮ ਸੈਟਿੰਗਾਂ > ਐਪਾਂ > ਡਾਊਨਲੋਡ ਕੀਤਿਆਂ ਵਿੱਚ ਇਸਨੂੰ ਮੁੜ-ਸਮਰੱਥ ਬਣਾਓ।"</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"ਐਪ ਪ੍ਰਤਿਕਿਰਿਆ ਨਹੀਂ ਦੇ ਰਹੀ ਹੈ"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"ਸ਼ਾਇਦ <xliff:g id="APP_NAME">%1$s</xliff:g> ਵੱਲੋਂ ਬਹੁਤ ਜ਼ਿਆਦਾ ਮੈਮੋਰੀ ਦੀ ਵਰਤੋਂ ਕੀਤੀ ਜਾ ਰਹੀ ਹੋਵੇ।"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਵਰਤਮਾਨ ਡਿਸਪਲੇ ਆਕਾਰ ਸੈਟਿੰਗ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ ਹੈ ਅਤੇ ਅਣਕਿਆਸੇ ਤੌਰ \'ਤੇ ਵਿਹਾਰ ਕਰ ਸਕਦੀ ਹੈ।"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"ਹਮੇਸ਼ਾ ਦਿਖਾਓ"</string>
<string name="smv_application" msgid="3307209192155442829">"ਐਪ <xliff:g id="APPLICATION">%1$s</xliff:g> (ਪ੍ਰਕਿਰਿਆ <xliff:g id="PROCESS">%2$s</xliff:g>) ਨੇ ਆਪਣੀ ਖੁਦ-ਲਾਗੂ ਕੀਤੀ ਸਟ੍ਰਿਕਟਮੋਡ ਨੀਤੀ ਦੀ ਉਲੰਘਣਾ ਕੀਤੀ ਹੈ।"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 25fc20e..0989576 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1020,6 +1020,10 @@
<string name="dial" msgid="4204975095406423102">"Telefon"</string>
<string name="map" msgid="6068210738233985748">"Mapy"</string>
<string name="browse" msgid="6993590095938149861">"Internet"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Kończy się miejsce"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Niektóre funkcje systemu mogą nie działać"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Za mało pamięci w systemie. Upewnij się, że masz 250 MB wolnego miejsca i uruchom urządzenie ponownie."</string>
@@ -1029,8 +1033,7 @@
<string name="cancel" msgid="6442560571259935130">"Anuluj"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Anuluj"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"ZAMKNIJ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Uwaga"</string>
<string name="loading" msgid="7933681260296021180">"Wczytuję…"</string>
<string name="capital_on" msgid="1544682755514494298">"Wł."</string>
@@ -1087,10 +1090,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Zawsze pokazuj"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Włącz ponownie, wybierając Ustawienia systemowe > Aplikacje > Pobrane."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikacja nie reaguje"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> może wykorzystywać za dużo pamięci"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> nie obsługuje obecnie ustawionego rozmiaru wyświetlacza i może działać niestabilnie."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Zawsze pokazuj"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) naruszyła wymuszone przez siebie zasady StrictMode."</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index e619572..a9e0ac9 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefone"</string>
<string name="map" msgid="6068210738233985748">"Mapas"</string>
<string name="browse" msgid="6993590095938149861">"Navegador"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Pouco espaço de armazenamento"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Algumas funções do sistema podem não funcionar"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Não há armazenamento suficiente para o sistema. Certifique-se de ter 250 MB de espaço livre e reinicie."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Cancelar"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"FECHAR"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Atenção"</string>
<string name="loading" msgid="7933681260296021180">"Carregando…"</string>
<string name="capital_on" msgid="1544682755514494298">"LIG"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostrar sempre"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reativar isso em Configurações do sistema > Apps > Transferidos."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"O app não está respondendo"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> pode estar usando muita memória."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não é compatível com a configuração atual de tamanho de exibição e pode se comportar de forma inesperada."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar sempre"</string>
<string name="smv_application" msgid="3307209192155442829">"O app <xliff:g id="APPLICATION">%1$s</xliff:g>, processo <xliff:g id="PROCESS">%2$s</xliff:g>, violou a política StrictMode imposta automaticamente."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 59a3e4e..cd26bd5 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telemóvel"</string>
<string name="map" msgid="6068210738233985748">"Mapas"</string>
<string name="browse" msgid="6993590095938149861">"Navegador"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Está quase sem espaço de armazenamento"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Algumas funções do sistema poderão não funcionar"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Não existe armazenamento suficiente para o sistema. Certifique-se de que tem 250 MB de espaço livre e reinicie."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Cancelar"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"FECHAR"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Atenção"</string>
<string name="loading" msgid="7933681260296021180">"A carregar…"</string>
<string name="capital_on" msgid="1544682755514494298">"Ativado"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostrar sempre"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reative este modo nas Definições do Sistema > Aplicações > Transferidas."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"A aplicação não está a responder"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"A aplicação <xliff:g id="APP_NAME">%1$s</xliff:g> pode estar a utilizar demasiada memória."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> não suporta a definição de Tamanho do ecrã atual e pode ter um comportamento inesperado."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar sempre"</string>
<string name="smv_application" msgid="3307209192155442829">"A aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) violou a política StrictMode auto-imposta."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index e619572..a9e0ac9 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefone"</string>
<string name="map" msgid="6068210738233985748">"Mapas"</string>
<string name="browse" msgid="6993590095938149861">"Navegador"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Pouco espaço de armazenamento"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Algumas funções do sistema podem não funcionar"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Não há armazenamento suficiente para o sistema. Certifique-se de ter 250 MB de espaço livre e reinicie."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Cancelar"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"FECHAR"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Atenção"</string>
<string name="loading" msgid="7933681260296021180">"Carregando…"</string>
<string name="capital_on" msgid="1544682755514494298">"LIG"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostrar sempre"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reativar isso em Configurações do sistema > Apps > Transferidos."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"O app não está respondendo"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> pode estar usando muita memória."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não é compatível com a configuração atual de tamanho de exibição e pode se comportar de forma inesperada."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar sempre"</string>
<string name="smv_application" msgid="3307209192155442829">"O app <xliff:g id="APPLICATION">%1$s</xliff:g>, processo <xliff:g id="PROCESS">%2$s</xliff:g>, violou a política StrictMode imposta automaticamente."</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 0751094..67f17b25 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1000,6 +1000,10 @@
<string name="dial" msgid="4204975095406423102">"Telefon"</string>
<string name="map" msgid="6068210738233985748">"Hărți"</string>
<string name="browse" msgid="6993590095938149861">"Browser"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Spațiul de stocare aproape ocupat"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Este posibil ca unele funcții de sistem să nu funcționeze"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Spațiu de stocare insuficient pentru sistem. Asigurați-vă că aveți 250 MB de spațiu liber și reporniți."</string>
@@ -1009,8 +1013,7 @@
<string name="cancel" msgid="6442560571259935130">"Anulați"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Anulați"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"ÎNCHIDEȚI"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Atenție"</string>
<string name="loading" msgid="7933681260296021180">"Se încarcă…"</string>
<string name="capital_on" msgid="1544682755514494298">"DA"</string>
@@ -1067,10 +1070,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scară"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Afișați întotdeauna"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reactivați acest mod din Setări de sistem > Aplicații > Descărcate."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Aplicația nu răspunde"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Este posibil ca <xliff:g id="APP_NAME">%1$s</xliff:g> să utilizeze prea multă memorie."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> nu acceptă setarea actuală pentru Dimensiunea afișării și este posibil să aibă un comportament neașteptat."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Afișează întotdeauna"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplicația <xliff:g id="APPLICATION">%1$s</xliff:g> (procesul <xliff:g id="PROCESS">%2$s</xliff:g>) a încălcat propria politică StrictMode."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index cfa60d9..70631d0 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1020,6 +1020,10 @@
<string name="dial" msgid="4204975095406423102">"Телефон"</string>
<string name="map" msgid="6068210738233985748">"Карты"</string>
<string name="browse" msgid="6993590095938149861">"Браузер"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Недостаточно памяти"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Некоторые функции могут не работать"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Недостаточно свободного места для системы. Освободите не менее 250 МБ дискового пространства и перезапустите устройство."</string>
@@ -1029,8 +1033,7 @@
<string name="cancel" msgid="6442560571259935130">"Отмена"</string>
<string name="yes" msgid="5362982303337969312">"ОК"</string>
<string name="no" msgid="5141531044935541497">"Отмена"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"ЗАКРЫТЬ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Внимание"</string>
<string name="loading" msgid="7933681260296021180">"Загрузка…"</string>
<string name="capital_on" msgid="1544682755514494298">"I"</string>
@@ -1087,10 +1090,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Масштаб"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Всегда показывать"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Включить эту функцию можно в меню \"Настройки > Приложения > Загруженные\"."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Приложение не отвечает"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Возможно, приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" использует слишком много памяти."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" не поддерживает выбранный масштаб изображения на экране и может работать некорректно."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Всегда показывать"</string>
<string name="smv_application" msgid="3307209192155442829">"Приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" (процесс: <xliff:g id="PROCESS">%2$s</xliff:g>) нарушило собственную политику StrictMode."</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index afbdfb1..11c42dc 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -982,6 +982,10 @@
<string name="dial" msgid="4204975095406423102">"දුරකථනය"</string>
<string name="map" msgid="6068210738233985748">"සිතියම්"</string>
<string name="browse" msgid="6993590095938149861">"බ්රවුසරය"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"ආචයනය ඉඩ ප්රමාණය අඩු වී ඇත"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"සමහර පද්ධති කාර්යයන් ක්රියා නොකරනු ඇත"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"පද්ධතිය සඳහා ප්රමාණවත් ඉඩ නොමැත. ඔබට 250MB නිදහස් ඉඩක් තිබෙන ඔබට තිබෙන බව සහතික කරගෙන නැවත උත්සාහ කරන්න."</string>
@@ -991,8 +995,7 @@
<string name="cancel" msgid="6442560571259935130">"අවලංගු කරන්න"</string>
<string name="yes" msgid="5362982303337969312">"හරි"</string>
<string name="no" msgid="5141531044935541497">"අවලංගු කරන්න"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"වසන්න"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"අවධානය"</string>
<string name="loading" msgid="7933681260296021180">"පූරණය වෙමින්..."</string>
<string name="capital_on" msgid="1544682755514494298">"සක්රීයයි"</string>
@@ -1049,10 +1052,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"පරිමාණය"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"සැමවිටම පෙන්වන්න"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"පද්ධති සැකසීම් තුළ මෙය නැවත ක්රියාත්මක කරන්න > යෙදුම් > බාගන්නා ලදි."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"යෙදුම ප්රතිචාර නොදක්වයි"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> මතකය ඉතා වැඩියෙන් භාවිත කරනවා විය හැකිය."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> වත්මන් සංදර්ශක තරම සඳහා සහාය නොදක්වන අතර අනපේක්ෂිත ලෙස හැසිරීමට හැකිය."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"සැම විටම පෙන්වන්න"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> යෙදුම (<xliff:g id="PROCESS">%2$s</xliff:g> ක්රියාවලිය) එහි StrictMode කොන්දේසිය උල්ලංඝනය කර ඇත."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 0a1bd83..1eb24ac 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1020,6 +1020,10 @@
<string name="dial" msgid="4204975095406423102">"Telefón"</string>
<string name="map" msgid="6068210738233985748">"Mapy"</string>
<string name="browse" msgid="6993590095938149861">"Prehliadač"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Nedostatok ukladacieho priestoru"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Niektoré systémové funkcie nemusia fungovať"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"V úložisku nie je dostatok voľného miesta pre systém. Zaistite, aby ste mali 250 MB voľného miesta a zariadenie reštartujte."</string>
@@ -1029,8 +1033,7 @@
<string name="cancel" msgid="6442560571259935130">"Zrušiť"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Zrušiť"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"ZAVRIEŤ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Upozornenie"</string>
<string name="loading" msgid="7933681260296021180">"Načítava sa…"</string>
<string name="capital_on" msgid="1544682755514494298">"I"</string>
@@ -1087,10 +1090,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Prispôsobiť veľkosť"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Vždy zobraziť"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Povoľte to znova v sekcii Nastavenia systému > Aplikácie > Stiahnuté súbory."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikácia nereaguje"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> pravdepodobne používa príliš veľa pamäte."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> aktuálne nastavenie veľkosti zobrazenia nepodporuje a môže sa správať neočakávane."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Vždy zobrazovať"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikácia <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) porušila svoje vlastné vynútené pravidlá StrictMode."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 4a52738..4396cd3 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1020,6 +1020,10 @@
<string name="dial" msgid="4204975095406423102">"Telefon"</string>
<string name="map" msgid="6068210738233985748">"Zemljevidi"</string>
<string name="browse" msgid="6993590095938149861">"Brskalnik"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Prostor za shranjevanje bo pošel"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Nekatere sistemske funkcije morda ne delujejo"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"V shrambi ni dovolj prostora za sistem. Sprostite 250 MB prostora in znova zaženite napravo."</string>
@@ -1029,8 +1033,7 @@
<string name="cancel" msgid="6442560571259935130">"Prekliči"</string>
<string name="yes" msgid="5362982303337969312">"V redu"</string>
<string name="no" msgid="5141531044935541497">"Prekliči"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"ZAPRI"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Pozor"</string>
<string name="loading" msgid="7933681260296021180">"Nalaganje …"</string>
<string name="capital_on" msgid="1544682755514494298">"VKLOPLJENO"</string>
@@ -1087,10 +1090,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Lestvica"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Vedno pokaži"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Znova omogočite to v sistemskih nastavitvah > Aplikacije > Preneseno."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikacija se ne odziva"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> morda uporablja preveč pomnilnika."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podpira trenutne nastavitve velikosti zaslona, kar lahko vodi v nepričakovano delovanje."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Vedno pokaži"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) krši svoj samouveljavljiv pravilnik o strogem načinu."</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 464cd30..d62f95f 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefoni"</string>
<string name="map" msgid="6068210738233985748">"Hartat"</string>
<string name="browse" msgid="6993590095938149861">"Shfletuesi"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Hapësira ruajtëse po mbaron"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Disa funksione të sistemit mund të mos punojnë"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nuk ka hapësirë të mjaftueshme ruajtjeje për sistemin. Sigurohu që të kesh 250 MB hapësirë të lirë dhe pastaj të rifillosh."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Anulo"</string>
<string name="yes" msgid="5362982303337969312">"Në rregull"</string>
<string name="no" msgid="5141531044935541497">"Anulo"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"MBYLL"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Kujdes!"</string>
<string name="loading" msgid="7933681260296021180">"Po ngarkohet..."</string>
<string name="capital_on" msgid="1544682755514494298">"Aktivizuar"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Shkalla"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Shfaq gjithnjë"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Aktivizoje sërish këtë te \"Cilësimet e sistemit\" > \"Aplikacionet\" > \"Të shkarkuara\"."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikacioni nuk po përgjigjet"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> mund të jetë duke përdorur shumë memorie."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> nuk mbështet cilësimin aktual të madhësisë së ekranit dhe mund të shfaqë sjellje të papritura."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Shfaq gjithmonë"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikacioni <xliff:g id="APPLICATION">%1$s</xliff:g> (procesi <xliff:g id="PROCESS">%2$s</xliff:g>) ka shkelur politikën e tij të vetë-imponuar \"Modaliteti i ashpër\" (StrictMode)."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index b115801..37552af 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1000,6 +1000,10 @@
<string name="dial" msgid="4204975095406423102">"Позови"</string>
<string name="map" msgid="6068210738233985748">"Мапе"</string>
<string name="browse" msgid="6993590095938149861">"Прегледач"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Меморијски простор је на измаку"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Неке системске функције можда не функционишу"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Нема довољно меморијског простора за систем. Уверите се да имате 250 MB слободног простора и поново покрените."</string>
@@ -1009,8 +1013,7 @@
<string name="cancel" msgid="6442560571259935130">"Откажи"</string>
<string name="yes" msgid="5362982303337969312">"Потврди"</string>
<string name="no" msgid="5141531044935541497">"Откажи"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"ЗАТВОРИ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Пажња"</string>
<string name="loading" msgid="7933681260296021180">"Учитава се…"</string>
<string name="capital_on" msgid="1544682755514494298">"ДА"</string>
@@ -1067,10 +1070,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Размера"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Увек приказуј"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Поново омогућите у менију Системска подешавања > Апликације > Преузето."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Апликација не реагује"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> можда користи превише меморије."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> не подржава тренутно подешавање величине приказа и може да се понаша неочекивано."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Увек приказуј"</string>
<string name="smv_application" msgid="3307209192155442829">"Апликација <xliff:g id="APPLICATION">%1$s</xliff:g> (процес <xliff:g id="PROCESS">%2$s</xliff:g>) је прекршила самонаметнуте StrictMode смернице."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index f40e7e0..64d8cba 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefon"</string>
<string name="map" msgid="6068210738233985748">"Kartor"</string>
<string name="browse" msgid="6993590095938149861">"Webbläsare"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Lagringsutrymmet börjar ta slut"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Det kan hända att vissa systemfunktioner inte fungerar"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Det finns inte tillräckligt med utrymme för systemet. Kontrollera att du har ett lagringsutrymme på minst 250 MB och starta om."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Avbryt"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Avbryt"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"STÄNG"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Obs!"</string>
<string name="loading" msgid="7933681260296021180">"Läser in …"</string>
<string name="capital_on" msgid="1544682755514494298">"PÅ"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Anpassning"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Visa alltid"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Aktivera detta igen i Systeminställningar > Appar > Hämtat."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Appen svarar inte"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> kanske använder för mycket minne."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> har inte stöd för den nuvarande inställningen för skärmstorlek och kanske inte fungerar som förväntat."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Visa alltid"</string>
<string name="smv_application" msgid="3307209192155442829">"Appen <xliff:g id="APPLICATION">%1$s</xliff:g> (processen <xliff:g id="PROCESS">%2$s</xliff:g>) har brutit mot sin egen StrictMode-policy."</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 62d9595..c3ee444 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -978,6 +978,10 @@
<string name="dial" msgid="4204975095406423102">"Simu"</string>
<string name="map" msgid="6068210738233985748">"Ramani"</string>
<string name="browse" msgid="6993590095938149861">"Kivinjari"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Nafasi ya kuhifadhi inakaribia kujaa"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Baadhi ya vipengee vya mfumo huenda visifanye kazi"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Hifadhi haitoshi kwa ajili ya mfumo. Hakikisha una MB 250 za nafasi ya hifadhi isiyotumika na uanzishe upya."</string>
@@ -987,8 +991,7 @@
<string name="cancel" msgid="6442560571259935130">"Ghairi"</string>
<string name="yes" msgid="5362982303337969312">"Sawa"</string>
<string name="no" msgid="5141531044935541497">"Ghairi"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"FUNGA"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Zingatia"</string>
<string name="loading" msgid="7933681260296021180">"Inapakia…"</string>
<string name="capital_on" msgid="1544682755514494298">"Washa"</string>
@@ -1045,10 +1048,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Kipimo"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Onyesha kila wakati"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Wezesha tena hii katika mipangilio ya Mfumo > Programu > iliyopakuliwa."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Programu haifanyi kazi"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Huenda <xliff:g id="APP_NAME">%1$s</xliff:g> inatumia hifadhi nyingi mno."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> haiwezi kutumia mipangilio ya sasa ya ukubwa wa Skrini na huenda isifanye kazi vizuri."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Onyesha kila wakati"</string>
<string name="smv_application" msgid="3307209192155442829">"Programu <xliff:g id="APPLICATION">%1$s</xliff:g> (utaratibu <xliff:g id="PROCESS">%2$s</xliff:g>) imeenda kinyume na sera yake ya StrictMode."</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index be3a156..cd2a566 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"ஃபோன்"</string>
<string name="map" msgid="6068210738233985748">"வரைபடம்"</string>
<string name="browse" msgid="6993590095938149861">"உலாவி"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"சேமிப்பிடம் குறைகிறது"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"சில அமைப்பு செயல்பாடுகள் வேலை செய்யாமல் போகலாம்"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"முறைமையில் போதுமான சேமிப்பகம் இல்லை. 250மெ.பை. அளவு காலி இடவசதி இருப்பதை உறுதிசெய்து மீண்டும் தொடங்கவும்."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"ரத்துசெய்"</string>
<string name="yes" msgid="5362982303337969312">"சரி"</string>
<string name="no" msgid="5141531044935541497">"ரத்துசெய்"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"மூடு"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"கவனத்திற்கு"</string>
<string name="loading" msgid="7933681260296021180">"ஏற்றுகிறது..."</string>
<string name="capital_on" msgid="1544682755514494298">"ஆன்"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"அளவு"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"எப்போதும் காட்டு"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"சிஸ்டம் அமைப்பு > பயன்பாடுகள் > பதிவிறக்கம் என்பதில் இதை மீண்டும் இயக்கவும்."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"பயன்பாடு செயல்படவில்லை"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> பயன்பாடு, அதிகளவு நினைவகத்தைப் பயன்படுத்தக்கூடும்."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"தற்போதைய திரை அளவு அமைப்பை <xliff:g id="APP_NAME">%1$s</xliff:g> ஆதரிக்காததால், அது வழக்கத்திற்கு மாறாகச் செயல்படக்கூடும்."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"எப்போதும் காட்டு"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> பயன்பாடு (செயல்முறை <xliff:g id="PROCESS">%2$s</xliff:g>), தனது சுய-செயலாக்க StrictMode கொள்கையை மீறியது."</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 2f579e2..90981e7 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"ఫోన్"</string>
<string name="map" msgid="6068210738233985748">"మ్యాప్స్"</string>
<string name="browse" msgid="6993590095938149861">"బ్రౌజర్"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"నిల్వ ఖాళీ అయిపోతోంది"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"కొన్ని సిస్టమ్ కార్యాచరణలు పని చేయకపోవచ్చు"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"సిస్టమ్ కోసం తగినంత నిల్వ లేదు. మీకు 250MB ఖాళీ స్థలం ఉందని నిర్ధారించుకుని, పునఃప్రారంభించండి."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"రద్దు చేయి"</string>
<string name="yes" msgid="5362982303337969312">"సరే"</string>
<string name="no" msgid="5141531044935541497">"రద్దు చేయి"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"మూసివేయండి"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"గమనిక"</string>
<string name="loading" msgid="7933681260296021180">"లోడ్ చేస్తోంది…"</string>
<string name="capital_on" msgid="1544682755514494298">"ఆన్లో ఉంది"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"ప్రమాణం"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"ఎల్లప్పుడూ చూపు"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"సిస్టమ్ సెట్టింగ్లు > అనువర్తనాలు > డౌన్లోడ్ చేసినవిలో దీన్ని పునఃప్రారంభించండి."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"యాప్ ప్రతిస్పందించలేదు"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> చాలా ఎక్కువ మెమరీని ఉపయోగించుకోవచ్చు."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ప్రస్తుత ప్రదర్శన పరిమాణ సెట్టింగ్కు మద్దతు ఇవ్వదు, దీని వలన ఊహించని సమస్యలు తలెత్తవచ్చు."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"ఎల్లప్పుడూ చూపు"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> యాప్ (<xliff:g id="PROCESS">%2$s</xliff:g> ప్రాసెస్) అది స్వయంగా అమలు చేసే ఖచ్చితమైన మోడ్ విధానాన్ని ఉల్లంఘించింది."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index d719cdd..310bd95 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"โทรศัพท์"</string>
<string name="map" msgid="6068210738233985748">"Maps"</string>
<string name="browse" msgid="6993590095938149861">"เบราว์เซอร์"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"พื้นที่จัดเก็บเหลือน้อย"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"บางฟังก์ชันระบบอาจไม่ทำงาน"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"พื้นที่เก็บข้อมูลไม่เพียงพอสำหรับระบบ โปรดตรวจสอบว่าคุณมีพื้นที่ว่าง 250 MB แล้วรีสตาร์ท"</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"ยกเลิก"</string>
<string name="yes" msgid="5362982303337969312">"ตกลง"</string>
<string name="no" msgid="5141531044935541497">"ยกเลิก"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"ปิด"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"โปรดทราบ"</string>
<string name="loading" msgid="7933681260296021180">"กำลังโหลด..."</string>
<string name="capital_on" msgid="1544682755514494298">"เปิด"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"สเกล"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"แสดงเสมอ"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"เปิดใช้งานอีกครั้งในการตั้งค่าระบบ > แอปพลิเคชัน > ดาวน์โหลด"</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"แอปไม่ตอบสนอง"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> อาจใช้หน่วยความจำมากเกินไป"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ไม่สนับสนุนการตั้งค่าขนาดการแสดงผลปัจจุบันและอาจแสดงผลผิดปกติ"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"แสดงเสมอ"</string>
<string name="smv_application" msgid="3307209192155442829">"แอปพลิเคชัน <xliff:g id="APPLICATION">%1$s</xliff:g> (กระบวนการ <xliff:g id="PROCESS">%2$s</xliff:g>) ละเมิดนโยบาย StrictMode ที่บังคับใช้ด้วยตัวเอง"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 1c15cbb..50d09a0 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telepono"</string>
<string name="map" msgid="6068210738233985748">"Mga Mapa"</string>
<string name="browse" msgid="6993590095938149861">"Browser"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Nauubusan na ang puwang ng storage"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Maaaring hindi gumana nang tama ang ilang paggana ng system"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Walang sapat na storage para sa system. Tiyaking mayroon kang 250MB na libreng espasyo at i-restart."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Kanselahin"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Kanselahin"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"ISARA"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Bigyang pansin"</string>
<string name="loading" msgid="7933681260296021180">"Naglo-load…"</string>
<string name="capital_on" msgid="1544682755514494298">"I-ON"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Sukat"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Palaging ipakita"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Muling paganahin ito sa mga setting ng System > Apps > Na-download."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Hindi tumutugon ang app"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Maaaring gumagamit ang <xliff:g id="APP_NAME">%1$s</xliff:g> ng masyadong maraming memory."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Hindi sinusuportahan ng <xliff:g id="APP_NAME">%1$s</xliff:g> ang kasalukuyang setting ng laki ng Display at maaaring may mangyaring hindi inaasahan."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Palaging ipakita"</string>
<string name="smv_application" msgid="3307209192155442829">"Ang app na <xliff:g id="APPLICATION">%1$s</xliff:g> (prosesong <xliff:g id="PROCESS">%2$s</xliff:g>) ay lumabag sa sarili nitong ipinapatupad na patakarang StrictMode."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 93f4e6d..9bead0c 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefon"</string>
<string name="map" msgid="6068210738233985748">"Haritalar"</string>
<string name="browse" msgid="6993590095938149861">"Tarayıcı"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Depolama alanı bitiyor"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Bazı sistem işlevleri çalışmayabilir"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Sistem için yeterli depolama alanı yok. 250 MB boş alanınızın bulunduğundan emin olun ve yeniden başlatın."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"İptal"</string>
<string name="yes" msgid="5362982303337969312">"Tamam"</string>
<string name="no" msgid="5141531044935541497">"İptal"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"KAPAT"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Dikkat"</string>
<string name="loading" msgid="7933681260296021180">"Yükleniyor..."</string>
<string name="capital_on" msgid="1544682755514494298">"AÇIK"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Ölçek"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Her zaman göster"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Bunu Sistem ayarları > Uygulamalar > İndirilenler bölümünden yeniden etkinleştirin."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Uygulama yanıt vermiyor"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> çok fazla bellek kullanıyor olabilir."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> geçerli Ekran boyutu ayarını desteklemiyor ve beklenmedik bir şekilde davranabilir."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Her zaman göster"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulaması (<xliff:g id="PROCESS">%2$s</xliff:g> işlemi) kendiliğinden uyguladığı StrictMode politikasını ihlal etti."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 70d0eed..cb2f5b4 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1020,6 +1020,10 @@
<string name="dial" msgid="4204975095406423102">"Телефонувати"</string>
<string name="map" msgid="6068210738233985748">"Карти"</string>
<string name="browse" msgid="6993590095938149861">"Веб-переглядач"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Закінчується пам’ять"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Деякі системні функції можуть не працювати"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Недостатньо місця для системи. Переконайтесь, що на пристрої є 250 МБ вільного місця, і повторіть спробу."</string>
@@ -1029,8 +1033,7 @@
<string name="cancel" msgid="6442560571259935130">"Скасувати"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Скасувати"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"ЗАКРИТИ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Увага"</string>
<string name="loading" msgid="7933681260296021180">"Завантаження..."</string>
<string name="capital_on" msgid="1544682755514494298">"УВІМК"</string>
@@ -1087,10 +1090,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Масштаб"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Завжди показувати"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Знову ввімкнути це в меню Налаштування системи > Програми > Завантажені."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Додаток не відповідає"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Можливо, додаток <xliff:g id="APP_NAME">%1$s</xliff:g> використовує забагато пам’яті."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> не підтримує поточне налаштування розміру екрана та може працювати неналежним чином."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Завжди показувати"</string>
<string name="smv_application" msgid="3307209192155442829">"Програма <xliff:g id="APPLICATION">%1$s</xliff:g> (процес <xliff:g id="PROCESS">%2$s</xliff:g>) порушила свою самозастосовну політику StrictMode."</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index c3e67f8..ab69fc3 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"فون کریں"</string>
<string name="map" msgid="6068210738233985748">"Maps"</string>
<string name="browse" msgid="6993590095938149861">"براؤزر"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"اسٹوریج کی جگہ ختم ہو رہی ہے"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"ممکن ہے سسٹم کے کچھ فنکشنز کام نہ کریں"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"سسٹم کیلئے کافی اسٹوریج نہیں ہے۔ اس بات کو یقینی بنائیں کہ آپ کے پاس 250MB خالی جگہ ہے اور دوبارہ شروع کریں۔"</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"منسوخ کریں"</string>
<string name="yes" msgid="5362982303337969312">"ٹھیک ہے"</string>
<string name="no" msgid="5141531044935541497">"منسوخ کریں"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"بند کریں"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"توجہ دیں"</string>
<string name="loading" msgid="7933681260296021180">"لوڈ ہو رہا ہے…"</string>
<string name="capital_on" msgid="1544682755514494298">"آن"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"پیمانہ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"ہمیشہ دکھائیں"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"سسٹم ترتیبات > ایپس > ڈاؤن لوڈ کردہ میں اسے دوبارہ فعال کریں۔"</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"ایپ جواب نہیں دے رہی ہے"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> کافی زیادہ میموری استعمال کر سکتی ہے۔"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> میں موجودہ ڈسپلے سائز ترتیبات کی معاونت نہیں ہے اور ہو سکتا ہے غیر متوقع طریقے سے کام کرے۔"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"ہمیشہ دکھائیں"</string>
<string name="smv_application" msgid="3307209192155442829">"ایپ <xliff:g id="APPLICATION">%1$s</xliff:g> (کارروائی <xliff:g id="PROCESS">%2$s</xliff:g>) نے خود نافذ کی گئی StrictMode پالیسی کی خلاف ورزی کی ہے۔"</string>
@@ -1309,9 +1310,9 @@
<string name="submit" msgid="1602335572089911941">"جمع کرائیں"</string>
<string name="car_mode_disable_notification_title" msgid="3164768212003864316">"کار وضع فعال ہے"</string>
<string name="car_mode_disable_notification_message" msgid="6301524980144350051">"کار موڈ سے خارج ہونے کیلئے تھپتھپائیں۔"</string>
- <string name="tethered_notification_title" msgid="3146694234398202601">"ٹیتھرنگ یا ہاٹ اسپاٹ فعال"</string>
+ <string name="tethered_notification_title" msgid="3146694234398202601">"ٹیدرنگ یا ہاٹ اسپاٹ فعال"</string>
<string name="tethered_notification_message" msgid="2113628520792055377">"سیٹ اپ کرنے کیلئے تھپتھپائیں۔"</string>
- <string name="disable_tether_notification_title" msgid="7526977944111313195">"ربط بنانا غیر فعال ہے"</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"ٹیدرنگ غیر فعال ہے"</string>
<string name="disable_tether_notification_message" msgid="2913366428516852495">"تفصیلات کے لئے اپنے منتظم سے رابطہ کریں"</string>
<string name="back_button_label" msgid="2300470004503343439">"واپس جائیں"</string>
<string name="next_button_label" msgid="1080555104677992408">"اگلا"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index d69b9f5..f402e26 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefon"</string>
<string name="map" msgid="6068210738233985748">"Xaritalar"</string>
<string name="browse" msgid="6993590095938149861">"Brauzer"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Xotirada bo‘sh joy tugamoqda"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Ba‘zi tizim funksiyalari ishlamasligi mumkin"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Tizim uchun xotirada joy yetarli emas. Avval 250 megabayt joy bo‘shatib, keyin qurilmani o‘chirib yoqing."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Bekor qilish"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Bekor qilish"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"YOPISH"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Diqqat"</string>
<string name="loading" msgid="7933681260296021180">"Yuklanmoqda…"</string>
<string name="capital_on" msgid="1544682755514494298">"I"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Masshtab"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Doimo ko‘rsatish"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Uni Tizim sozlamalari > Ilovalar > Yuklab olingan menyusidan qayta yoqing."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Ilova javob bermayapti"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> ortiqcha xotira ishlatmoqda."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"“<xliff:g id="APP_NAME">%1$s</xliff:g>” ilovasi joriy ekran o‘lchami sozlamalariga mos kelmasligi va noto‘g‘ri ishlashi mumkin."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Har doim ko‘rsatilsin"</string>
<string name="smv_application" msgid="3307209192155442829">"“<xliff:g id="APPLICATION">%1$s</xliff:g>” ilovasi (jarayaon: <xliff:g id="PROCESS">%2$s</xliff:g>) o‘zining StrictMode qoidasini buzdi."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index adc565e..9a057cf 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Điện thoại"</string>
<string name="map" msgid="6068210738233985748">"Bản đồ"</string>
<string name="browse" msgid="6993590095938149861">"Trình duyệt"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Sắp hết dung lượng lưu trữ"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Một số chức năng hệ thống có thể không hoạt động"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Không đủ bộ nhớ cho hệ thống. Đảm bảo bạn có 250 MB dung lượng trống và khởi động lại."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Hủy"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Hủy"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"ĐÓNG"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Chú ý"</string>
<string name="loading" msgid="7933681260296021180">"Đang tải…"</string>
<string name="capital_on" msgid="1544682755514494298">"BẬT"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Tỷ lệ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Luôn hiển thị"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Bật lại chế độ này trong cài đặt Hệ thống > Ứng dụng > Đã tải xuống."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Ứng dụng không phản hồi"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> có thể đang sử dụng quá nhiều bộ nhớ."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> không hỗ trợ cài đặt kích thước Màn hình hiện tại và có thể hoạt động không như mong đợi."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Luôn hiển thị"</string>
<string name="smv_application" msgid="3307209192155442829">"Ứng dụng <xliff:g id="APPLICATION">%1$s</xliff:g> (quá trình <xliff:g id="PROCESS">%2$s</xliff:g>) đã vi phạm chính sách StrictMode tự thi hành của mình."</string>
@@ -1637,7 +1638,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Do quản trị viên của bạn cài đặt"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Do quản trị viên của bạn cập nhật"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Do quản trị viên của bạn xóa"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Để giúp tăng tuổi thọ pin, trình tiết kiệm pin sẽ giảm hiệu suất thiết bị của bạn và hạn chế rung, dịch vụ vị trí và hầu hết dữ liệu nền. Email, nhắn tin và các ứng dụng khác dựa trên đồng bộ hóa có thể không cập nhật nếu bạn không mở chúng.\n\nTrình tiết kiệm pin tự động tắt khi thiết bị của bạn đang sạc."</string>
+ <string name="battery_saver_description" msgid="1960431123816253034">"Để giúp tăng thời lượng pin, trình tiết kiệm pin sẽ giảm hiệu suất thiết bị và hạn chế rung, dịch vụ vị trí và hầu hết dữ liệu nền. Ứng dụng email, nhắn tin và các ứng dụng khác dựa trên đồng bộ hóa có thể không cập nhật nếu bạn không mở.\n\nTrình tiết kiệm pin tự động tắt khi thiết bị của bạn đang sạc."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Để giúp giảm mức sử dụng dữ liệu, Trình tiết kiệm dữ liệu chặn một số ứng dụng gửi hoặc nhận dữ liệu trong nền. Ứng dụng mà bạn hiện sử dụng có thể truy cập dữ liệu nhưng có thể thực hiện việc đó ít thường xuyên hơn. Ví dụ: hình ảnh sẽ không hiển thị cho đến khi bạn nhấn vào hình ảnh đó."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Bật Trình tiết kiệm dữ liệu?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Bật"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index de60bc9..962b05f 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"电话"</string>
<string name="map" msgid="6068210738233985748">"地图"</string>
<string name="browse" msgid="6993590095938149861">"浏览器"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"存储空间不足"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"某些系统功能可能无法正常使用"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"系统存储空间不足。请确保您有250MB的可用空间,然后重新启动。"</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"取消"</string>
<string name="yes" msgid="5362982303337969312">"确定"</string>
<string name="no" msgid="5141531044935541497">"取消"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"关闭"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"注意"</string>
<string name="loading" msgid="7933681260296021180">"正在加载..."</string>
<string name="capital_on" msgid="1544682755514494298">"开启"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"缩放"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"始终显示"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"在“系统设置”>“应用”>“已下载”中重新启用此模式。"</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"应用没有响应"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g>可能占用了过多内存。"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g>不支持当前的显示大小设置,因此可能无法正常显示。"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"一律显示"</string>
<string name="smv_application" msgid="3307209192155442829">"“<xliff:g id="APPLICATION">%1$s</xliff:g>”应用(<xliff:g id="PROCESS">%2$s</xliff:g> 进程)违反了自我强制执行的严格模式 (StrictMode) 政策。"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 13e081b..4b5a4ec 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"撥打電話"</string>
<string name="map" msgid="6068210738233985748">"地圖"</string>
<string name="browse" msgid="6993590095938149861">"瀏覽器"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"儲存空間即將用盡"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"部分系統功能可能無法運作"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"系統儲存空間不足。請確認裝置有 250 MB 的可用空間,然後重新啟動。"</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"取消"</string>
<string name="yes" msgid="5362982303337969312">"確定"</string>
<string name="no" msgid="5141531044935541497">"取消"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"關閉"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"注意"</string>
<string name="loading" msgid="7933681260296021180">"正在載入..."</string>
<string name="capital_on" msgid="1544682755514494298">"開啟"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"比例"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"永遠顯示"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"前往 [系統設定] > [應用程式] > [下載] 重新啟用這個模式。"</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"應用程式沒有回應"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」可能佔用大量記憶體。"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援目前的「螢幕」尺寸設定,畫面可能無法如預期顯示。"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"永遠顯示"</string>
<string name="smv_application" msgid="3307209192155442829">"應用程式 <xliff:g id="APPLICATION">%1$s</xliff:g> (處理程序 <xliff:g id="PROCESS">%2$s</xliff:g>) 已違反其自行強制實施的嚴格模式 (StrictMode) 政策。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index e2d9c1c..5166b87 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"電話"</string>
<string name="map" msgid="6068210738233985748">"地圖"</string>
<string name="browse" msgid="6993590095938149861">"瀏覽器"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"儲存空間即將用盡"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"部分系統功能可能無法運作"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"系統儲存空間不足。請確定你已釋出 250MB 的可用空間,然後重新啟動。"</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"取消"</string>
<string name="yes" msgid="5362982303337969312">"確定"</string>
<string name="no" msgid="5141531044935541497">"取消"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"關閉"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"注意"</string>
<string name="loading" msgid="7933681260296021180">"載入中…"</string>
<string name="capital_on" msgid="1544682755514494298">"開啟"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"比例"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"一律顯示"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"前往 [系統設定] > [應用程式] > [下載] 重新啟用這個模式。"</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"應用程式沒有回應"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」可能使用了過多記憶體。"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援目前的顯示大小設定,可能會發生非預期的行為。"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"一律顯示"</string>
<string name="smv_application" msgid="3307209192155442829">"應用程式 <xliff:g id="APPLICATION">%1$s</xliff:g> (處理程序 <xliff:g id="PROCESS">%2$s</xliff:g>) 已違反其自行強制實施的嚴格模式 (StrictMode) 政策。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 48b32d1..b7a6ae4 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Ifoni"</string>
<string name="map" msgid="6068210738233985748">"Amamephu"</string>
<string name="browse" msgid="6993590095938149861">"Isiphequluli"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Isikhala sokulondoloza siyaphela"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Eminye imisebenzi yohlelo ingahle ingasebenzi"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Akusona isitoreji esanele sesistimu. Qiniseka ukuthi unesikhala esikhululekile esingu-250MB uphinde uqalise kabusha."</string>
@@ -989,8 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Khansela"</string>
<string name="yes" msgid="5362982303337969312">"KULUNGILE"</string>
<string name="no" msgid="5141531044935541497">"Khansela"</string>
- <!-- no translation found for close (2318214661230355730) -->
- <skip />
+ <string name="close" msgid="2318214661230355730">"VALA"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Qaphela"</string>
<string name="loading" msgid="7933681260296021180">"Iyalayisha…"</string>
<string name="capital_on" msgid="1544682755514494298">"VULIWE"</string>
@@ -1047,10 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Isilinganisi"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Bonisa njalo"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Yenza kuphinde kusebenze kuzilungiselelo Zesistimue > Izinhlelo zokusebenza > Okulayishiwe."</string>
- <!-- no translation found for top_app_killed_title (6814231368167994497) -->
- <skip />
- <!-- no translation found for top_app_killed_message (3487519022191609844) -->
- <skip />
+ <string name="top_app_killed_title" msgid="6814231368167994497">"I-App ayiphenduli"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> ingasebenzisa imemori eningi."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> ayisekeli isilungiselelo sosayizi sokubonisa samanje futhi ingasebenza ngokungalindelekile."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Bonisa njalo"</string>
<string name="smv_application" msgid="3307209192155442829">"Inqubo <xliff:g id="APPLICATION">%1$s</xliff:g> (yohlelo <xliff:g id="PROCESS">%2$s</xliff:g>) iphule inqubomgomo oziphoqelela yona Yemodi Ebukhali."</string>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 16c8578..b3d0053 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -520,6 +520,12 @@
<dimen name="floating_toolbar_vertical_margin">8dp</dimen>
<dimen name="content_rect_bottom_clip_allowance">20dp</dimen>
+ <!-- Magnifier dimensions -->
+ <dimen name="magnifier_width">200dp</dimen>
+ <dimen name="magnifier_height">48dp</dimen>
+ <dimen name="magnifier_elevation">2dp</dimen>
+ <dimen name="magnifier_offset">42dp</dimen>
+
<dimen name="chooser_grid_padding">0dp</dimen>
<!-- Spacing around the background change frome service to non-service -->
<dimen name="chooser_service_spacing">8dp</dimen>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 6807e13..085f8dd 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -340,18 +340,19 @@
<!-- Work profile deleted notification--> <skip />
<!-- Shows up in the notification's title when the system deletes the work profile. [CHAR LIMIT=NONE] -->
<string name="work_profile_deleted">Work profile deleted</string>
- <!-- Content text for a notification. The Title of the notification is "work_profile_deleted",
- i.e. "Work profile deleted". This says that the profile is deleted by the system as a result of
- the current profile owner gone missing. [CHAR LIMIT=100]-->
+ <!-- Content text for a notification. The Title of the notification is "Work profile deleted".
+ This says that the profile is deleted by the system as a result of the current profile owner gone missing. [CHAR LIMIT=100]-->
<string name="work_profile_deleted_description">Work profile deleted due to missing admin app</string>
- <!-- Content text for an expanded notification. The Title of the notification is "work_profile_deleted",
- i.e. "Work profile deleted". This further explains that the profile is deleted by the system
- as a result of the current profile admin gone missing. [CHAR LIMIT=NONE]-->
+ <!-- Content text for an expanded notification. The Title of the notification is "Work profile deleted".
+ This further explains that the profile is deleted by the system as a result of the current profile admin gone missing. [CHAR LIMIT=NONE]-->
<string name="work_profile_deleted_details">The work profile admin app is either missing or corrupted.
As a result, your work profile and related data have been deleted. Contact your admin for assistance.</string>
- <!-- Content text for a notification. The Title of the notification is "work_profile_deleted",
+ <!-- Content text for a notification. The Title of the notification is "Work profile deleted",
This indicates that a work profile has been deleted. [CHAR LIMIT=NONE]-->
<string name="work_profile_deleted_description_dpm_wipe">Your work profile is no longer available on this device</string>
+ <!-- Content text for a notification. The Title of the notification is "Work profile deleted",
+ This indicates that a work profile has been deleted because the maximum failed password attempts as been reached. [CHAR LIMIT=NONE]-->
+ <string name="work_profile_deleted_reason_maximum_password_failure">Too many password attempts</string>
<!-- Content title for a notification. This notification indicates that the device is managed
and network logging was activated by a device owner. [CHAR LIMIT=NONE]-->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 0732f0d..a5dbe26 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1155,6 +1155,7 @@
<java-symbol type="string" name="work_profile_deleted_description" />
<java-symbol type="string" name="work_profile_deleted_details" />
<java-symbol type="string" name="work_profile_deleted_description_dpm_wipe" />
+ <java-symbol type="string" name="work_profile_deleted_reason_maximum_password_failure" />
<java-symbol type="string" name="network_logging_notification_title" />
<java-symbol type="string" name="network_logging_notification_text" />
<java-symbol type="string" name="factory_reset_warning" />
@@ -2474,6 +2475,14 @@
<java-symbol type="drawable" name="ft_avd_tooverflow_animation" />
<java-symbol type="attr" name="floatingToolbarDividerColor" />
+ <!-- Magnifier -->
+ <java-symbol type="id" name="magnifier_image" />
+ <java-symbol type="layout" name="magnifier" />
+ <java-symbol type="dimen" name="magnifier_width" />
+ <java-symbol type="dimen" name="magnifier_height" />
+ <java-symbol type="dimen" name="magnifier_elevation" />
+ <java-symbol type="dimen" name="magnifier_offset" />
+
<java-symbol type="string" name="date_picker_prev_month_button" />
<java-symbol type="string" name="date_picker_next_month_button" />
<java-symbol type="layout" name="date_picker_month_item_material" />
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 9dafa7a..9bea3ee 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -1336,6 +1336,7 @@
<!-- Default theme for Settings and activities launched from Settings. -->
<style name="Theme.Material.Settings" parent="Theme.Material.Light.LightStatusBar">
+ <item name="homeAsUpIndicator">@drawable/ic_ab_back_material_settings</item>
<item name="colorPrimary">@color/primary_material_settings_light</item>
<item name="colorPrimaryDark">@color/primary_dark_material_settings_light</item>
<item name="colorSecondary">@color/secondary_material_settings_light</item>
diff --git a/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttf b/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttf
new file mode 100644
index 0000000..1bad6fe
--- /dev/null
+++ b/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttf
Binary files differ
diff --git a/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttx b/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttx
new file mode 100644
index 0000000..0cf0f79
--- /dev/null
+++ b/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttx
@@ -0,0 +1,207 @@
+<?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.
+-->
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
+
+ <GlyphOrder>
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="0em"/>
+ <GlyphID id="2" name="1em"/>
+ <GlyphID id="3" name="3em"/>
+ <GlyphID id="4" name="5em"/>
+ <GlyphID id="5" name="7em"/>
+ <GlyphID id="6" name="10em"/>
+ <GlyphID id="7" name="50em"/>
+ <GlyphID id="8" name="100em"/>
+ </GlyphOrder>
+
+ <head>
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0x640cdb2f"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="100"/>
+ <created value="Fri Mar 17 07:26:00 2017"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="7"/>
+ <fontDirectionHint value="2"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="0x00010000"/>
+ <ascent value="1000"/>
+ <descent value="-200"/>
+ <lineGap value="0"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ </hhea>
+
+ <maxp>
+ <tableVersion value="0x10000"/>
+ <maxZones value="0"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="0"/>
+ <maxSizeOfInstructions value="0"/>
+ <maxComponentElements value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="594"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00001000"/>
+ <ySubscriptXSize value="650"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="650"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="350"/>
+ <yStrikeoutSize value="50"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="5"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="UKWN"/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="32"/>
+ <usLastCharIndex value="122"/>
+ <sTypoAscender value="800"/>
+ <sTypoDescender value="-200"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="200"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="700"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="0"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="50" lsb="0"/>
+ <mtx name="0em" width="0" lsb="0"/>
+ <mtx name="1em" width="100" lsb="0"/>
+ <mtx name="3em" width="300" lsb="0"/>
+ <mtx name="5em" width="500" lsb="0"/>
+ <mtx name="7em" width="700" lsb="0"/>
+ <mtx name="10em" width="1000" lsb="0"/>
+ <mtx name="50em" width="5000" lsb="0"/>
+ <mtx name="100em" width="10000" lsb="0"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_12 format="12" reserved="0" length="6" nGroups="1" platformID="3" platEncID="10" language="0">
+ <map code="0x0020" name="10em" />
+ <map code="0x002e" name="10em" /> <!-- . -->
+ <map code="0x0043" name="100em" /> <!-- C -->
+ <map code="0x0049" name="1em" /> <!-- I -->
+ <map code="0x004c" name="50em" /> <!-- L -->
+ <map code="0x0056" name="5em" /> <!-- V -->
+ <map code="0x0058" name="10em" /> <!-- X -->
+ <map code="0x005f" name="0em" /> <!-- _ -->
+ <map code="0xfffd" name="7em" /> <!-- REPLACEMENT CHAR -->
+ <map code="0x10331" name="10em" />
+ </cmap_format_12>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+ <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="0em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="1em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="3em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="5em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="7em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="10em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="50em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="100em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ </glyf>
+
+ <name>
+ <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Font for StaticLayoutLineBreakingTest
+ </namerecord>
+ <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Font for StaticLayoutLineBreakingTest
+ </namerecord>
+ <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ SampleFont-Regular
+ </namerecord>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+ SampleFont-Regular
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="-75"/>
+ <underlineThickness value="50"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+</ttFont>
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 8395638..d9bcc57d 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -277,6 +277,7 @@
Settings.Global.NEW_CONTACT_AGGREGATOR,
Settings.Global.NITZ_UPDATE_DIFF,
Settings.Global.NITZ_UPDATE_SPACING,
+ Settings.Global.NOTIFICATION_SNOOZE_OPTIONS,
Settings.Global.NSD_ON,
Settings.Global.NTP_SERVER,
Settings.Global.NTP_TIMEOUT,
diff --git a/core/tests/coretests/src/android/service/settings/suggestions/SuggestionTest.java b/core/tests/coretests/src/android/service/settings/suggestions/SuggestionTest.java
index 5548e48..b0ec55d 100644
--- a/core/tests/coretests/src/android/service/settings/suggestions/SuggestionTest.java
+++ b/core/tests/coretests/src/android/service/settings/suggestions/SuggestionTest.java
@@ -21,6 +21,8 @@
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Icon;
import android.os.Parcel;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
@@ -36,6 +38,8 @@
private static final String TEST_ID = "id";
private static final String TEST_TITLE = "title";
private static final String TEST_SUMMARY = "summary";
+
+ private Icon mIcon;
private PendingIntent mTestIntent;
@@ -44,6 +48,7 @@
final Context context = InstrumentationRegistry.getContext();
mTestIntent = PendingIntent.getActivity(context, 0 /* requestCode */,
new Intent(), 0 /* flags */);
+ mIcon = Icon.createWithBitmap(Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888));
}
@Test
@@ -51,12 +56,15 @@
final Suggestion suggestion = new Suggestion.Builder(TEST_ID)
.setTitle(TEST_TITLE)
.setSummary(TEST_SUMMARY)
+ .setIcon(mIcon)
.setPendingIntent(mTestIntent)
.build();
assertThat(suggestion.getId()).isEqualTo(TEST_ID);
assertThat(suggestion.getTitle()).isEqualTo(TEST_TITLE);
assertThat(suggestion.getSummary()).isEqualTo(TEST_SUMMARY);
+ assertThat(suggestion.getIcon()).isEqualTo(mIcon);
+ assertThat(suggestion.getFlags()).isEqualTo(0);
assertThat(suggestion.getPendingIntent()).isEqualTo(mTestIntent);
}
@@ -66,6 +74,7 @@
.setTitle(TEST_TITLE)
.setSummary(TEST_SUMMARY)
.setPendingIntent(mTestIntent)
+ .setIcon(mIcon)
.build();
}
@@ -75,6 +84,8 @@
final Suggestion oldSuggestion = new Suggestion.Builder(TEST_ID)
.setTitle(TEST_TITLE)
.setSummary(TEST_SUMMARY)
+ .setIcon(mIcon)
+ .setFlags(Suggestion.FLAG_HAS_BUTTON)
.setPendingIntent(mTestIntent)
.build();
@@ -85,6 +96,9 @@
assertThat(newSuggestion.getId()).isEqualTo(TEST_ID);
assertThat(newSuggestion.getTitle()).isEqualTo(TEST_TITLE);
assertThat(newSuggestion.getSummary()).isEqualTo(TEST_SUMMARY);
+ assertThat(newSuggestion.getIcon().toString()).isEqualTo(mIcon.toString());
+ assertThat(newSuggestion.getFlags())
+ .isEqualTo(Suggestion.FLAG_HAS_BUTTON);
assertThat(newSuggestion.getPendingIntent()).isEqualTo(mTestIntent);
}
}
diff --git a/core/tests/coretests/src/android/text/StaticLayoutLineBreakingTest.java b/core/tests/coretests/src/android/text/StaticLayoutLineBreakingTest.java
index 2ee855e..f7dbafa 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutLineBreakingTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutLineBreakingTest.java
@@ -18,6 +18,9 @@
import static org.junit.Assert.assertEquals;
+import android.content.Context;;
+import android.graphics.Typeface;
+import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.text.Layout.Alignment;
@@ -45,57 +48,24 @@
private static final int[] NO_BREAK = new int[] {};
- private static final TextPaint sTextPaint = new MockTextPaint();
+ private static final TextPaint sTextPaint = new TextPaint();
- private static class MockTextPaint extends TextPaint {
-
- @Override
- public float getTextRunAdvances(char[] chars, int index, int count,
- int contextIndex, int contextCount, boolean isRtl, float[] advances,
- int advancesIndex) {
-
- // Conditions copy pasted from Paint
- if (chars == null) {
- throw new IllegalArgumentException("text cannot be null");
- }
-
- if ((index | count | contextIndex | contextCount | advancesIndex
- | (index - contextIndex) | (contextCount - count)
- | ((contextIndex + contextCount) - (index + count))
- | (chars.length - (contextIndex + contextCount))
- | (advances == null ? 0 :
- (advances.length - (advancesIndex + count)))) < 0) {
- throw new IndexOutOfBoundsException();
- }
-
- float res = 0.0f;
-
- if (advances != null) {
- for (int i = 0; i < count; i++) {
- float width = getCharWidth(chars[index + i]);
- advances[advancesIndex + i] = width;
- res += width;
- }
- }
-
- return res;
- }
- }
-
- private static float getCharWidth(char c) {
- switch (Character.toUpperCase(c)) {
- // Roman figures
- case 'I': return 1.0f;
- case 'V': return 5.0f;
- case 'X': return 10.0f;
- case 'L': return 50.0f;
- case 'C': return 100.0f; // equals to WIDTH
- case ' ': return 10.0f;
- case '_': return 0.0f; // 0-width character
- case SURR_FIRST: return 7.0f;
- case SURR_SECOND: return 3.0f; // Sum of SURR_FIRST-SURR_SECOND is 10
- default: return 10.0f;
- }
+ static {
+ // The test font has following coverage and width.
+ // U+0020: 10em
+ // U+002E (.): 10em
+ // U+0043 (C): 100em
+ // U+0049 (I): 1em
+ // U+004C (L): 50em
+ // U+0056 (V): 5em
+ // U+0058 (X): 10em
+ // U+005F (_): 0em
+ // U+FFFD (invalid surrogate will be replaced to this): 7em
+ // U+10331 (\uD800\uDF31): 10em
+ Context context = InstrumentationRegistry.getTargetContext();
+ sTextPaint.setTypeface(Typeface.createFromAsset(context.getAssets(),
+ "fonts/StaticLayoutLineBreakingTestFont.ttf"));
+ sTextPaint.setTextSize(1.0f); // Make 1em == 1px.
}
private static StaticLayout getStaticLayout(CharSequence source, int width) {
@@ -406,13 +376,13 @@
public void testWithSurrogate() {
layout("LX" + SURR_FIRST + SURR_SECOND, NO_BREAK);
layout("LXXXX" + SURR_FIRST + SURR_SECOND, NO_BREAK);
- // LXXXXI (91) + SURR_FIRST (7) fits. But we should not break the surrogate pair
- // Bug: surrogate pair is broken, should be 6 (breaking after the 'V')
- // Maybe not: may be ok if the second character of a pair always has a 0-width
- layout("LXXXXI" + SURR_FIRST + SURR_SECOND, new int[] {7});
+ // LXXXXI (91) + SURR_FIRST + SURR_SECOND (10). Do not break in the middle point of
+ // surrogatge pair.
+ layout("LXXXXI" + SURR_FIRST + SURR_SECOND, new int[] {6});
- // LXXXXI (95) + SURR_SECOND (3) fits, but this is not a valid surrogate pair, breaking it
- layout("LXXXXV" + SURR_SECOND + SURR_FIRST, new int[] {7});
+ // LXXXXI (91) + SURR_SECOND (replaced with REPLACEMENT CHARACTER. width is 7px) fits.
+ // Break just after invalid trailing surrogate.
+ layout("LXXXXI" + SURR_SECOND + SURR_FIRST, new int[] {7});
layout("C" + SURR_FIRST + SURR_SECOND, new int[] {1});
}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
index 2784193..c5e112b 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
@@ -33,29 +33,17 @@
$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
-LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
- -D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
-
-#################################
-include $(BUILD_SYSTEM)/configure_local_jack.mk
-#################################
-
-ifdef LOCAL_JACK_ENABLED
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
-endif
LOCAL_MIN_SDK_VERSION := 8
include $(BUILD_PACKAGE)
-ifndef LOCAL_JACK_ENABLED
$(mainDexList): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
$(hide) mkdir -p $(dir $@)
$(MAINDEXCLASSES) $< 1>$@
echo "com/android/multidexlegacytestapp/Test.class" >> $@
$(built_dex_intermediate): $(mainDexList)
-endif
## The application with a full main dex
include $(CLEAR_VARS)
@@ -76,26 +64,14 @@
$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList2)
-LOCAL_JACK_FLAGS := -D jack.dex.output.policy=multidex -D jack.preprocessor=true\
- -D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
-
-#################################
-include $(BUILD_SYSTEM)/configure_local_jack.mk
-#################################
-
-ifdef LOCAL_JACK_ENABLED
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
-endif
LOCAL_MIN_SDK_VERSION := 8
include $(BUILD_PACKAGE)
-ifndef LOCAL_JACK_ENABLED
$(mainDexList2): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
$(hide) mkdir -p $(dir $@)
$(MAINDEXCLASSES) $< 1>$@
echo "com/android/multidexlegacytestapp/Test.class" >> $@
$(built_dex_intermediate): $(mainDexList2)
-endif
\ No newline at end of file
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/test.jpp b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/test.jpp
deleted file mode 100644
index a1f5656..0000000
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/test.jpp
+++ /dev/null
@@ -1,3 +0,0 @@
-test:
- @@com.android.jack.annotations.ForceInMainDex
- class com.android.multidexlegacytestapp.Test
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
index 1c7d807..da48df9 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
@@ -32,24 +32,12 @@
$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
-LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
- -D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
-
-#################################
-include $(BUILD_SYSTEM)/configure_local_jack.mk
-#################################
-
-ifdef LOCAL_JACK_ENABLED
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
-endif
include $(BUILD_PACKAGE)
-ifndef LOCAL_JACK_ENABLED
$(mainDexList): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
$(hide) mkdir -p $(dir $@)
$(MAINDEXCLASSES) $< 1>$@
echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
$(built_dex_intermediate): $(mainDexList)
-endif
\ No newline at end of file
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/test.jpp b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/test.jpp
deleted file mode 100644
index 6d384e3..0000000
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/test.jpp
+++ /dev/null
@@ -1,3 +0,0 @@
-test:
- @@com.android.jack.annotations.ForceInMainDex
- class com.android.framework.multidexlegacyversionedtestapp.MultiDexUpdateTest
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
index b77cf31..02b3f53 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
@@ -32,24 +32,12 @@
$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
-LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
- -D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
-
-#################################
-include $(BUILD_SYSTEM)/configure_local_jack.mk
-#################################
-
-ifdef LOCAL_JACK_ENABLED
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
-endif
include $(BUILD_PACKAGE)
-ifndef LOCAL_JACK_ENABLED
$(mainDexList): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
$(hide) mkdir -p $(dir $@)
$(MAINDEXCLASSES) $< 1>$@
echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
$(built_dex_intermediate): $(mainDexList)
-endif
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/test.jpp b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/test.jpp
deleted file mode 100644
index 6d384e3..0000000
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/test.jpp
+++ /dev/null
@@ -1,3 +0,0 @@
-test:
- @@com.android.jack.annotations.ForceInMainDex
- class com.android.framework.multidexlegacyversionedtestapp.MultiDexUpdateTest
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
index 3631626..4808684 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
@@ -32,25 +32,13 @@
LOCAL_DEX_PREOPT := false
LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
-LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
- -D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
-
-#################################
-include $(BUILD_SYSTEM)/configure_local_jack.mk
-#################################
-
-ifdef LOCAL_JACK_ENABLED
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
-endif
include $(BUILD_PACKAGE)
-ifndef LOCAL_JACK_ENABLED
$(mainDexList): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
$(hide) mkdir -p $(dir $@)
$(MAINDEXCLASSES) $< 1>$@
echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
$(built_dex_intermediate): $(mainDexList)
-endif
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/test.jpp b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/test.jpp
deleted file mode 100644
index 6d384e3..0000000
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/test.jpp
+++ /dev/null
@@ -1,3 +0,0 @@
-test:
- @@com.android.jack.annotations.ForceInMainDex
- class com.android.framework.multidexlegacyversionedtestapp.MultiDexUpdateTest
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 7a2df85..9948f7e 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -64,7 +64,7 @@
<permission name="android.permission.WRITE_MEDIA_STORAGE"/>
</privapp-permissions>
- <privapp-permissions package="com.android.launcher">
+ <privapp-permissions package="com.android.launcher3">
<permission name="android.permission.BIND_APPWIDGET"/>
<permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
</privapp-permissions>
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index e3527e3..43fd270 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -658,6 +658,14 @@
* float confidence = floatDepthBuffer.get();
* </pre>
*
+ * For camera devices that support the
+ * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT DEPTH_OUTPUT}
+ * capability, DEPTH_POINT_CLOUD coordinates have units of meters, and the coordinate system is
+ * defined by the camera's pose transforms:
+ * {@link android.hardware.camera2.CameraCharacteristics#LENS_POSE_TRANSLATION} and
+ * {@link android.hardware.camera2.CameraCharacteristics#LENS_POSE_ROTATION}. That means the origin is
+ * the optical center of the camera device, and the positive Z axis points along the camera's optical axis,
+ * toward the scene.
*/
public static final int DEPTH_POINT_CLOUD = 0x101;
diff --git a/libs/protoutil/Android.mk b/libs/protoutil/Android.mk
new file mode 100644
index 0000000..a534816
--- /dev/null
+++ b/libs/protoutil/Android.mk
@@ -0,0 +1,39 @@
+#
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libprotoutil
+
+LOCAL_CFLAGS := \
+ -Wall -Werror -Wno-missing-field-initializers -Wno-unused-variable -Wunused-parameter
+
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ liblog \
+ libutils
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/include
+
+LOCAL_SRC_FILES := \
+ src/EncodedBuffer.cpp \
+ src/protobuf.cpp \
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/libs/protoutil/include/android/util/EncodedBuffer.h b/libs/protoutil/include/android/util/EncodedBuffer.h
new file mode 100644
index 0000000..cf09609
--- /dev/null
+++ b/libs/protoutil/include/android/util/EncodedBuffer.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_UTIL_ENCODED_BUFFER_H
+#define ANDROID_UTIL_ENCODED_BUFFER_H
+
+#include <stdint.h>
+#include <vector>
+
+namespace android {
+namespace util {
+
+using namespace std;
+
+/**
+ * A stream of bytes containing a read pointer and a write pointer,
+ * backed by a set of fixed-size buffers. There are write functions for the
+ * primitive types stored by protocol buffers, but none of the logic
+ * for tags, inner objects, or any of that.
+ *
+ * Terminology:
+ * *Pos: Position in the whole data set (as if it were a single buffer).
+ * *Index: Index of a buffer within the mBuffers list.
+ * *Offset: Position within a buffer.
+ */
+class EncodedBuffer
+{
+public:
+ EncodedBuffer();
+ EncodedBuffer(size_t chunkSize);
+ ~EncodedBuffer();
+
+ class Pointer {
+ public:
+ Pointer();
+ Pointer(size_t chunkSize);
+
+ size_t pos() const;
+ size_t index() const;
+ size_t offset() const;
+
+ void move(size_t amt);
+ inline void move() { move(1); };
+
+ void rewind();
+ Pointer copy() const;
+
+ private:
+ size_t mChunkSize;
+ size_t mIndex;
+ size_t mOffset;
+ };
+
+ /******************************** Write APIs ************************************************/
+
+ /**
+ * Returns the number of bytes written in the buffer
+ */
+ size_t size() const;
+
+ /**
+ * Returns the write pointer.
+ */
+ Pointer* wp();
+
+ /**
+ * Returns the current position of write pointer, if the write buffer is full, it will automatically
+ * rotate to a new buffer with given chunkSize. If NULL is returned, it means NO_MEMORY
+ */
+ uint8_t* writeBuffer();
+
+ /**
+ * Returns the writeable size in the current write buffer .
+ */
+ size_t currentToWrite();
+
+ /**
+ * Write a varint into a vector. Return the size of the varint.
+ */
+ size_t writeRawVarint(uint32_t val);
+
+ /**
+ * Write a protobuf header. Return the size of the header.
+ */
+ size_t writeHeader(uint32_t fieldId, uint8_t wireType);
+
+ /********************************* Read APIs ************************************************/
+ class iterator;
+ friend class iterator;
+ class iterator {
+ public:
+ iterator(const EncodedBuffer& buffer);
+
+ /**
+ * Returns the number of bytes written in the buffer
+ */
+ size_t size() const;
+
+ /**
+ * Returns the size of total bytes read.
+ */
+ size_t bytesRead() const;
+
+ /**
+ * Returns the read pointer.
+ */
+ Pointer* rp();
+
+ /**
+ * Returns the current position of read pointer, if NULL is returned, it reaches end of buffer.
+ */
+ uint8_t const* readBuffer();
+
+ /**
+ * Returns the readable size in the current read buffer.
+ */
+ size_t currentToRead();
+
+ /**
+ * Returns true if next bytes is available for read.
+ */
+ bool hasNext();
+
+ /**
+ * Reads the current byte and moves pointer 1 bit.
+ */
+ uint8_t next();
+
+ /**
+ * Read varint from iterator, the iterator will point to next available byte.
+ * Return the number of bytes of the varint.
+ */
+ uint32_t readRawVarint();
+
+ private:
+ const EncodedBuffer& mData;
+ Pointer mRp;
+ };
+
+ /**
+ * Returns the iterator of EncodedBuffer so it guarantees consumers won't be able to modified the buffer.
+ */
+ iterator begin() const;
+
+private:
+ size_t mChunkSize;
+ vector<uint8_t*> mBuffers;
+
+ Pointer mWp;
+
+ inline uint8_t* at(const Pointer& p) const; // helper function to get value
+};
+
+} // util
+} // android
+
+#endif // ANDROID_UTIL_ENCODED_BUFFER_H
\ No newline at end of file
diff --git a/cmds/incidentd/src/protobuf.h b/libs/protoutil/include/android/util/protobuf.h
similarity index 74%
rename from cmds/incidentd/src/protobuf.h
rename to libs/protoutil/include/android/util/protobuf.h
index 263c864..f4e8d09 100644
--- a/cmds/incidentd/src/protobuf.h
+++ b/libs/protoutil/include/android/util/protobuf.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -14,11 +14,13 @@
* limitations under the License.
*/
-#ifndef PROTOBUF_H
-#define PROTOBUF_H
+#ifndef ANDROID_UTIL_PROTOBUF_H
+#define ANDROID_UTIL_PROTOBUF_H
#include <stdint.h>
-#include <vector>
+
+namespace android {
+namespace util {
using namespace std;
@@ -50,19 +52,7 @@
*/
uint8_t* write_length_delimited_tag_header(uint8_t* buf, uint32_t fieldId, size_t size);
-/**
- * Write a varint into a vector. Return the size of the varint.
- */
-size_t write_raw_varint(vector<uint8_t>* buf, uint32_t val);
+} // util
+} // android
-/**
- * Write a protobuf header. Return the size of the header.
- */
-size_t write_header(vector<uint8_t>* buf, uint32_t fieldId, uint8_t wireType);
-
-enum {
- // IncidentProto.header
- FIELD_ID_INCIDENT_HEADER = 1
-};
-
-#endif // PROTOBUF_H
+#endif // ANDROID_UTIL_PROTOUBUF_H
diff --git a/libs/protoutil/src/EncodedBuffer.cpp b/libs/protoutil/src/EncodedBuffer.cpp
new file mode 100644
index 0000000..84dc5b6
--- /dev/null
+++ b/libs/protoutil/src/EncodedBuffer.cpp
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/util/EncodedBuffer.h>
+
+#include <stdlib.h>
+
+namespace android {
+namespace util {
+
+const size_t BUFFER_SIZE = 8 * 1024; // 8 KB
+
+EncodedBuffer::Pointer::Pointer() : Pointer(BUFFER_SIZE)
+{
+}
+
+EncodedBuffer::Pointer::Pointer(size_t chunkSize)
+ :mIndex(0),
+ mOffset(0)
+{
+ mChunkSize = chunkSize == 0 ? BUFFER_SIZE : chunkSize;
+}
+
+size_t
+EncodedBuffer::Pointer::pos() const
+{
+ return mIndex * mChunkSize + mOffset;
+}
+
+size_t
+EncodedBuffer::Pointer::index() const
+{
+ return mIndex;
+}
+
+size_t
+EncodedBuffer::Pointer::offset() const
+{
+ return mOffset;
+}
+
+void
+EncodedBuffer::Pointer::move(size_t amt)
+{
+ size_t newOffset = mOffset + amt;
+ mIndex += newOffset / mChunkSize;
+ mOffset = newOffset % mChunkSize;
+}
+
+void
+EncodedBuffer::Pointer::rewind()
+{
+ mIndex = 0;
+ mOffset = 0;
+}
+
+EncodedBuffer::Pointer
+EncodedBuffer::Pointer::copy() const
+{
+ Pointer p = Pointer(mChunkSize);
+ p.mIndex = mIndex;
+ p.mOffset = mOffset;
+ return p;
+}
+
+// ===========================================================
+EncodedBuffer::EncodedBuffer() : EncodedBuffer(0)
+{
+}
+
+EncodedBuffer::EncodedBuffer(size_t chunkSize)
+ :mBuffers()
+{
+ mChunkSize = chunkSize == 0 ? BUFFER_SIZE : chunkSize;
+ mWp = Pointer(mChunkSize);
+}
+
+EncodedBuffer::~EncodedBuffer()
+{
+ for (size_t i=0; i<mBuffers.size(); i++) {
+ uint8_t* buf = mBuffers[i];
+ free(buf);
+ }
+}
+
+inline uint8_t*
+EncodedBuffer::at(const Pointer& p) const
+{
+ return mBuffers[p.index()] + p.offset();
+}
+
+/******************************** Write APIs ************************************************/
+size_t
+EncodedBuffer::size() const
+{
+ return mWp.pos();
+}
+
+EncodedBuffer::Pointer*
+EncodedBuffer::wp()
+{
+ return &mWp;
+}
+
+uint8_t*
+EncodedBuffer::writeBuffer()
+{
+ // This prevents write pointer move too fast than allocating the buffer.
+ if (mWp.index() > mBuffers.size()) return NULL;
+ uint8_t* buf = NULL;
+ if (mWp.index() == mBuffers.size()) {
+ buf = (uint8_t*)malloc(mChunkSize);
+
+ if (buf == NULL) return NULL; // This indicates NO_MEMORY
+
+ mBuffers.push_back(buf);
+ }
+ return at(mWp);
+}
+
+size_t
+EncodedBuffer::currentToWrite()
+{
+ return mChunkSize - mWp.offset();
+}
+
+size_t
+EncodedBuffer::writeRawVarint(uint32_t val)
+{
+ size_t size = 0;
+ while (true) {
+ size++;
+ if ((val & ~0x7F) == 0) {
+ *writeBuffer() = (uint8_t) val;
+ mWp.move();
+ return size;
+ } else {
+ *writeBuffer() = (uint8_t)((val & 0x7F) | 0x80);
+ mWp.move();
+ val >>= 7;
+ }
+ }
+}
+
+size_t
+EncodedBuffer::writeHeader(uint32_t fieldId, uint8_t wireType)
+{
+ return writeRawVarint((fieldId << 3) | wireType);
+}
+
+/********************************* Read APIs ************************************************/
+EncodedBuffer::iterator
+EncodedBuffer::begin() const
+{
+ return EncodedBuffer::iterator(*this);
+}
+
+EncodedBuffer::iterator::iterator(const EncodedBuffer& buffer)
+ :mData(buffer),
+ mRp(buffer.mChunkSize)
+{
+}
+
+size_t
+EncodedBuffer::iterator::size() const
+{
+ return mData.size();
+}
+
+size_t
+EncodedBuffer::iterator::bytesRead() const
+{
+ return mRp.pos();
+}
+
+EncodedBuffer::Pointer*
+EncodedBuffer::iterator::rp()
+{
+ return &mRp;
+}
+
+uint8_t const*
+EncodedBuffer::iterator::readBuffer()
+{
+ return hasNext() ? const_cast<uint8_t const*>(mData.at(mRp)) : NULL;
+}
+
+size_t
+EncodedBuffer::iterator::currentToRead()
+{
+ return (mData.mWp.index() > mRp.index()) ?
+ mData.mChunkSize - mRp.offset() :
+ mData.mWp.offset() - mRp.offset();
+}
+
+bool
+EncodedBuffer::iterator::hasNext()
+{
+ return mRp.pos() < mData.mWp.pos();
+}
+
+uint8_t
+EncodedBuffer::iterator::next()
+{
+ uint8_t res = *(mData.at(mRp));
+ mRp.move();
+ return res;
+}
+
+uint32_t
+EncodedBuffer::iterator::readRawVarint()
+{
+ uint32_t val = 0, shift = 0;
+ while (true) {
+ uint8_t byte = next();
+ val += (byte & 0x7F) << shift;
+ if ((byte & 0x80) == 0) break;
+ shift += 7;
+ }
+ return val;
+}
+
+} // util
+} // android
diff --git a/cmds/incidentd/src/protobuf.cpp b/libs/protoutil/src/protobuf.cpp
similarity index 67%
rename from cmds/incidentd/src/protobuf.cpp
rename to libs/protoutil/src/protobuf.cpp
index 4fffec1..ec5325c 100644
--- a/cmds/incidentd/src/protobuf.cpp
+++ b/libs/protoutil/src/protobuf.cpp
@@ -14,14 +14,19 @@
* limitations under the License.
*/
-#include "protobuf.h"
+#include <android/util/protobuf.h>
-uint8_t read_wire_type(uint32_t varint)
+namespace android {
+namespace util {
+
+uint8_t
+read_wire_type(uint32_t varint)
{
return (uint8_t) (varint & 0x07);
}
-uint32_t read_field_id(uint32_t varint)
+uint32_t
+read_field_id(uint32_t varint)
{
return varint >> 3;
}
@@ -49,24 +54,5 @@
return buf;
}
-size_t
-write_raw_varint(vector<uint8_t>* buf, uint32_t val)
-{
- size_t size = 0;
- while (true) {
- size++;
- if ((val & ~0x7F) == 0) {
- buf->push_back((uint8_t) val);
- return size;
- } else {
- buf->push_back((uint8_t)((val & 0x7F) | 0x80));
- val >>= 7;
- }
- }
-}
-
-size_t
-write_header(vector<uint8_t>* buf, uint32_t fieldId, uint8_t wireType)
-{
- return write_raw_varint(buf, (fieldId << 3) | wireType);
-}
\ No newline at end of file
+} // util
+} // android
diff --git a/media/java/android/media/AmrInputStream.java b/media/java/android/media/AmrInputStream.java
index 13c3ac4..efaf224 100644
--- a/media/java/android/media/AmrInputStream.java
+++ b/media/java/android/media/AmrInputStream.java
@@ -30,7 +30,7 @@
*/
public final class AmrInputStream extends InputStream {
private final static String TAG = "AmrInputStream";
-
+
// frame is 20 msec at 8.000 khz
private final static int SAMPLES_PER_FRAME = 8000 * 20 / 1000;
@@ -140,19 +140,15 @@
}
}
- // now read encoded data from the encoder (blocking, since we just filled up the
- // encoder's input with data it should be able to output at least one buffer)
- while (true) {
- int index = mCodec.dequeueOutputBuffer(mInfo, -1);
- if (index >= 0) {
- mBufIn = mInfo.size;
- ByteBuffer out = mCodec.getOutputBuffer(index);
- out.get(mBuf, 0 /* offset */, mBufIn /* length */);
- mCodec.releaseOutputBuffer(index, false /* render */);
- if ((mInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
- mSawOutputEOS = true;
- }
- break;
+ // now read encoded data from the encoder
+ int index = mCodec.dequeueOutputBuffer(mInfo, 0);
+ if (index >= 0) {
+ mBufIn = mInfo.size;
+ ByteBuffer out = mCodec.getOutputBuffer(index);
+ out.get(mBuf, 0 /* offset */, mBufIn /* length */);
+ mCodec.releaseOutputBuffer(index, false /* render */);
+ if ((mInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+ mSawOutputEOS = true;
}
}
}
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 3b9a5de..26ead3d 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -19,12 +19,14 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
+import android.media.AudioAttributesProto;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseIntArray;
+import android.util.proto.ProtoOutputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -177,7 +179,7 @@
/**
* IMPORTANT: when adding new usage types, add them to SDK_USAGES and update SUPPRESSIBLE_USAGES
- * if applicable.
+ * if applicable, as well as audioattributes.proto.
*/
/**
@@ -850,6 +852,21 @@
}
/** @hide */
+ public void toProto(ProtoOutputStream proto) {
+ proto.write(AudioAttributesProto.USAGE, mUsage);
+ proto.write(AudioAttributesProto.CONTENT_TYPE, mContentType);
+ proto.write(AudioAttributesProto.FLAGS, mFlags);
+ // mFormattedTags is never null due to assignment in Builder or unmarshalling.
+ for (String t : mFormattedTags.split(";")) {
+ t = t.trim();
+ if (t != "") {
+ proto.write(AudioAttributesProto.TAGS, t);
+ }
+ }
+ // TODO: is the data in mBundle useful for debugging?
+ }
+
+ /** @hide */
public String usageToString() {
return usageToString(mUsage);
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 186b265..dab7632a 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -4119,7 +4119,15 @@
Log.w(TAG, "updateAudioPortCache: listAudioPatches failed");
return status;
}
- } while (patchGeneration[0] != portGeneration[0]);
+ // Loop until patch generation is the same as port generation unless audio ports
+ // and audio patches are not null.
+ } while (patchGeneration[0] != portGeneration[0]
+ && (ports == null || patches == null));
+ // If the patch generation doesn't equal port generation, return ERROR here in case
+ // of mismatch between audio ports and audio patches.
+ if (patchGeneration[0] != portGeneration[0]) {
+ return ERROR;
+ }
for (int i = 0; i < newPatches.size(); i++) {
for (int j = 0; j < newPatches.get(i).sources().length; j++) {
diff --git a/media/java/android/media/AudioPortEventHandler.java b/media/java/android/media/AudioPortEventHandler.java
index c152245..ac3904a 100644
--- a/media/java/android/media/AudioPortEventHandler.java
+++ b/media/java/android/media/AudioPortEventHandler.java
@@ -17,6 +17,7 @@
package android.media;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import java.util.ArrayList;
@@ -30,6 +31,7 @@
class AudioPortEventHandler {
private Handler mHandler;
+ private HandlerThread mHandlerThread;
private final ArrayList<AudioManager.OnAudioPortUpdateListener> mListeners =
new ArrayList<AudioManager.OnAudioPortUpdateListener>();
@@ -40,6 +42,8 @@
private static final int AUDIOPORT_EVENT_SERVICE_DIED = 3;
private static final int AUDIOPORT_EVENT_NEW_LISTENER = 4;
+ private static final long RESCHEDULE_MESSAGE_DELAY_MS = 100;
+
/**
* Accessed by native methods: JNI Callback context.
*/
@@ -51,11 +55,12 @@
if (mHandler != null) {
return;
}
- // find the looper for our new event handler
- Looper looper = Looper.getMainLooper();
+ // create a new thread for our new event handler
+ mHandlerThread = new HandlerThread(TAG);
+ mHandlerThread.start();
- if (looper != null) {
- mHandler = new Handler(looper) {
+ if (mHandlerThread.getLooper() != null) {
+ mHandler = new Handler(mHandlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
ArrayList<AudioManager.OnAudioPortUpdateListener> listeners;
@@ -86,6 +91,12 @@
if (msg.what != AUDIOPORT_EVENT_SERVICE_DIED) {
int status = AudioManager.updateAudioPortCache(ports, patches, null);
if (status != AudioManager.SUCCESS) {
+ // Since audio ports and audio patches are not null, the return
+ // value could be ERROR due to inconsistency between port generation
+ // and patch generation. In this case, we need to reschedule the
+ // message to make sure the native callback is done.
+ sendMessageDelayed(obtainMessage(msg.what, msg.obj),
+ RESCHEDULE_MESSAGE_DELAY_MS);
return;
}
}
@@ -132,6 +143,9 @@
@Override
protected void finalize() {
native_finalize();
+ if (mHandlerThread.isAlive()) {
+ mHandlerThread.quit();
+ }
}
private native void native_finalize();
@@ -168,6 +182,10 @@
Handler handler = eventHandler.handler();
if (handler != null) {
Message m = handler.obtainMessage(what, arg1, arg2, obj);
+ if (what != AUDIOPORT_EVENT_NEW_LISTENER) {
+ // Except AUDIOPORT_EVENT_NEW_LISTENER, we can only respect the last message.
+ handler.removeMessages(what);
+ }
handler.sendMessage(m);
}
}
diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java
index 4808d7a..09449a1 100644
--- a/media/java/android/media/PlayerBase.java
+++ b/media/java/android/media/PlayerBase.java
@@ -127,8 +127,9 @@
Log.e(TAG, "Error talking to audio service, STARTED state will not be tracked", e);
}
synchronized (mLock) {
+ boolean attributesChanged = (mAttributes != attr);
mAttributes = attr;
- updateAppOpsPlayAudio_sync();
+ updateAppOpsPlayAudio_sync(attributesChanged);
}
}
@@ -200,16 +201,13 @@
}
void baseSetVolume(float leftVolume, float rightVolume) {
- final boolean hasAppOpsPlayAudio;
+ final boolean isRestricted;
synchronized (mLock) {
mLeftVolume = leftVolume;
mRightVolume = rightVolume;
- hasAppOpsPlayAudio = mHasAppOpsPlayAudio;
- if (isRestricted_sync()) {
- return;
- }
+ isRestricted = isRestricted_sync();
}
- playerSetVolume(!hasAppOpsPlayAudio/*muting*/,
+ playerSetVolume(isRestricted/*muting*/,
leftVolume * mPanMultiplierL, rightVolume * mPanMultiplierR);
}
@@ -250,7 +248,7 @@
private void updateAppOpsPlayAudio() {
synchronized (mLock) {
- updateAppOpsPlayAudio_sync();
+ updateAppOpsPlayAudio_sync(false);
}
}
@@ -258,7 +256,7 @@
* To be called whenever a condition that might affect audibility of this player is updated.
* Must be called synchronized on mLock.
*/
- void updateAppOpsPlayAudio_sync() {
+ void updateAppOpsPlayAudio_sync(boolean attributesChanged) {
boolean oldHasAppOpsPlayAudio = mHasAppOpsPlayAudio;
try {
int mode = AppOpsManager.MODE_IGNORED;
@@ -275,9 +273,10 @@
// AppsOps alters a player's volume; when the restriction changes, reflect it on the actual
// volume used by the player
try {
- if (oldHasAppOpsPlayAudio != mHasAppOpsPlayAudio) {
+ if (oldHasAppOpsPlayAudio != mHasAppOpsPlayAudio ||
+ attributesChanged) {
getService().playerHasOpPlayAudio(mPlayerIId, mHasAppOpsPlayAudio);
- if (mHasAppOpsPlayAudio) {
+ if (!isRestricted_sync()) {
if (DEBUG_APP_OPS) {
Log.v(TAG, "updateAppOpsPlayAudio: unmuting player, vol=" + mLeftVolume
+ "/" + mRightVolume);
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 80fd5c0..17b2326 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -845,6 +845,33 @@
return MtpConstants.RESPONSE_OK;
}
+ private int moveObject(int handle, int newParent, String newPath) {
+ String[] whereArgs = new String[] { Integer.toString(handle) };
+
+ // do not allow renaming any of the special subdirectories
+ if (isStorageSubDirectory(newPath)) {
+ return MtpConstants.RESPONSE_OBJECT_WRITE_PROTECTED;
+ }
+
+ // update database
+ ContentValues values = new ContentValues();
+ values.put(Files.FileColumns.DATA, newPath);
+ values.put(Files.FileColumns.PARENT, newParent);
+ int updated = 0;
+ try {
+ // note - we are relying on a special case in MediaProvider.update() to update
+ // the paths for all children in the case where this is a directory.
+ updated = mMediaProvider.update(mObjectsUri, values, ID_WHERE, whereArgs);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in mMediaProvider.update", e);
+ }
+ if (updated == 0) {
+ Log.e(TAG, "Unable to update path for " + handle + " to " + newPath);
+ return MtpConstants.RESPONSE_GENERAL_ERROR;
+ }
+ return MtpConstants.RESPONSE_OK;
+ }
+
private int setObjectProperty(int handle, int property,
long intValue, String stringValue) {
switch (property) {
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index 5b874cd..7225f10 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -68,6 +68,7 @@
static jmethodID method_getObjectInfo;
static jmethodID method_getObjectFilePath;
static jmethodID method_deleteFile;
+static jmethodID method_moveObject;
static jmethodID method_getObjectReferences;
static jmethodID method_setObjectReferences;
static jmethodID method_sessionStarted;
@@ -178,6 +179,9 @@
virtual MtpProperty* getDevicePropertyDesc(MtpDeviceProperty property);
+ virtual MtpResponseCode moveObject(MtpObjectHandle handle, MtpObjectHandle newParent,
+ MtpString& newPath);
+
virtual void sessionStarted();
virtual void sessionEnded();
@@ -995,6 +999,18 @@
return result;
}
+MtpResponseCode MyMtpDatabase::moveObject(MtpObjectHandle handle, MtpObjectHandle newParent,
+ MtpString &newPath) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jstring stringValue = env->NewStringUTF((const char *) newPath);
+ MtpResponseCode result = env->CallIntMethod(mDatabase, method_moveObject,
+ (jint)handle, (jint)newParent, stringValue);
+
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ env->DeleteLocalRef(stringValue);
+ return result;
+}
+
struct PropertyTableEntry {
MtpObjectProperty property;
int type;
@@ -1360,6 +1376,11 @@
ALOGE("Can't find deleteFile");
return -1;
}
+ method_moveObject = env->GetMethodID(clazz, "moveObject", "(IILjava/lang/String;)I");
+ if (method_moveObject == NULL) {
+ ALOGE("Can't find moveObject");
+ return -1;
+ }
method_getObjectReferences = env->GetMethodID(clazz, "getObjectReferences", "(I)[I");
if (method_getObjectReferences == NULL) {
ALOGE("Can't find getObjectReferences");
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index b8b67f2..424e7b9 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -287,7 +287,7 @@
<string name="transition_animation_scale_title" msgid="387527540523595875">"ট্র্যানজিশন অ্যানিমেশন স্কেল"</string>
<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="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="app_process_limit_title" msgid="4280600650253107163">"পশ্চাদপট প্রক্রিয়ার সীমা"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 2a08ad4..63c040e 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -110,11 +110,11 @@
<string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
<string name="data_usage_uninstalled_apps" msgid="614263770923231598">"ہٹائی گئی ایپس"</string>
<string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"ہٹائی گئی ایپس اور صارفین"</string>
- <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB ٹیتھرنگ"</string>
+ <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB ٹیدرنگ"</string>
<string name="tether_settings_title_wifi" msgid="3277144155960302049">"پورٹیبل ہاٹ اسپاٹ"</string>
- <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"بلوٹوتھ ٹیتھرنگ"</string>
- <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"ٹیتھرنگ"</string>
- <string name="tether_settings_title_all" msgid="8356136101061143841">"ٹیتھرنگ و پورٹیبل ہاٹ اسپاٹ"</string>
+ <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"بلوٹوتھ ٹیدرنگ"</string>
+ <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"ٹیدرنگ"</string>
+ <string name="tether_settings_title_all" msgid="8356136101061143841">"ٹیدرنگ و پورٹیبل ہاٹ اسپاٹ"</string>
<string name="managed_user_title" msgid="8109605045406748842">"تمام کام کی ایپس"</string>
<string name="user_guest" msgid="8475274842845401871">"مہمان"</string>
<string name="unknown" msgid="1592123443519355854">"نامعلوم"</string>
@@ -168,7 +168,7 @@
<string name="development_settings_summary" msgid="1815795401632854041">"ایپ ڈویلپمنٹ کیلئے اختیارات سیٹ کریں"</string>
<string name="development_settings_not_available" msgid="4308569041701535607">"اس صارف کیلئے ڈیولپر کے اختیارات دستیاب نہیں ہیں"</string>
<string name="vpn_settings_not_available" msgid="956841430176985598">"VPN ترتیبات اس صارف کیلئے دستیاب نہیں ہیں"</string>
- <string name="tethering_settings_not_available" msgid="6765770438438291012">"ٹیتھرنگ ترتیبات اس صارف کیلئے دستیاب نہیں ہیں"</string>
+ <string name="tethering_settings_not_available" msgid="6765770438438291012">"ٹیدرنگ ترتیبات اس صارف کیلئے دستیاب نہیں ہیں"</string>
<string name="apn_settings_not_available" msgid="7873729032165324000">"رسائی کی جگہ کے نام کی ترتیبات اس صارف کیلئے دستیاب نہیں ہیں"</string>
<string name="enable_adb" msgid="7982306934419797485">"USB ڈیبگ کرنا"</string>
<string name="enable_adb_summary" msgid="4881186971746056635">"USB مربوط ہونے پر ڈيبگ کرنے کی وضع"</string>
@@ -192,7 +192,7 @@
<string name="wifi_aggressive_handover" msgid="5309131983693661320">"Wi‑Fi سے موبائل کو جارحانہ ہینڈ اوور"</string>
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"ہمیشہ Wi‑Fi روم اسکینز کی اجازت دیں"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"موبائل ڈیٹا ہمیشہ فعال رکھیں"</string>
- <string name="tethering_hardware_offload" msgid="7470077827090325814">"ہارڈویئر کی سرعت کاری میں ربط بنایا جا رہا ہے"</string>
+ <string name="tethering_hardware_offload" msgid="7470077827090325814">"ٹیدرنگ ہارڈویئر سرعت کاری"</string>
<string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"بغیر نام والے بلوٹوتھ آلات دکھائیں"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"مطلق والیوم کو غیر فعال کریں"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"ان بینڈ رنگنگ فعال کریں"</string>
@@ -225,7 +225,7 @@
<string name="allow_mock_location_summary" msgid="317615105156345626">"فرضی مقامات کی اجازت دیں"</string>
<string name="debug_view_attributes" msgid="6485448367803310384">"منظر انتساب کے معائنہ کو فعال کریں"</string>
<string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Wi‑Fi فعال ہونے پر بھی موبائل ڈیٹا کو ہمیشہ فعال رکھیں (تیزی سے نیٹ ورک سوئچ کرنے کیلئے)۔"</string>
- <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"اگر دستیاب ہو، تو ہارڈویئر کی سرعت کاری میں ربط کاری کا استعمال کریں"</string>
+ <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"اگر دستیاب ہو تو ٹیدرنگ ہارڈویئر سرعت کاری کا استعمال کریں"</string>
<string name="adb_warning_title" msgid="6234463310896563253">"USB ڈیبگ کرنے کی اجازت دیں؟"</string>
<string name="adb_warning_message" msgid="7316799925425402244">"USB ڈیبگ کرنا صرف ڈیولپمنٹ کے مقاصد کیلئے ہے۔ اپنے کمپیوٹر اور اپنے آلہ کے درمیان ڈیٹا کاپی کرنے کیلئے اسے استعمال کریں، بغیر اطلاع کے اپنے آلہ پر ایپس انسٹال کریں اور لاگ ڈیٹا پڑھیں۔"</string>
<string name="adb_keys_warning_message" msgid="5659849457135841625">"اپنے ذریعہ پہلے سے اجازت یافتہ سبھی کمپیوٹرز سے USB ڈیبگ کرنے کی رسائی کو کالعدم کریں؟"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java b/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java
index 8fc9fa6..9fbadee 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java
@@ -131,7 +131,7 @@
}
public long getTotalBytes() {
- return mStats.getCacheBytes() + mStats.getCodeBytes() + mStats.getDataBytes();
+ return mStats.getAppBytes() + mStats.getDataBytes();
}
}
}
\ No newline at end of file
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 664dcfc..12455d8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -24,7 +24,6 @@
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
-import android.net.NetworkInfo.DetailedState;
import android.net.NetworkKey;
import android.net.NetworkRequest;
import android.net.NetworkScoreManager;
@@ -36,10 +35,14 @@
import android.net.wifi.WifiNetworkScoreCache;
import android.net.wifi.WifiNetworkScoreCache.CacheListener;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
+import android.os.Process;
import android.provider.Settings;
import android.support.annotation.GuardedBy;
+import android.support.annotation.NonNull;
+import android.support.annotation.VisibleForTesting;
import android.text.format.DateUtils;
import android.util.ArraySet;
import android.util.Log;
@@ -47,8 +50,12 @@
import android.util.SparseIntArray;
import android.widget.Toast;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.R;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnDestroy;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -64,7 +71,7 @@
/**
* Tracks saved or available wifi networks and their state.
*/
-public class WifiTracker {
+public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestroy {
/**
* Default maximum age in millis of cached scored networks in
* {@link AccessPoint#mScoredNetworkCache} to be used for speed label generation.
@@ -80,7 +87,7 @@
* and used so as to assist with in-the-field WiFi connectivity debugging */
public static boolean sVerboseLogging;
- // TODO(b/36733768): Remove flag includeSaved and includePasspoints.
+ // TODO(b/36733768): Remove flag includeSaved
// TODO: Allow control of this?
// Combo scans can take 5-6s to complete - set to 10s.
@@ -96,9 +103,9 @@
private final WifiListener mListener;
private final boolean mIncludeSaved;
private final boolean mIncludeScans;
- private final boolean mIncludePasspoints;
- @VisibleForTesting final MainHandler mMainHandler;
- @VisibleForTesting final WorkHandler mWorkHandler;
+ @VisibleForTesting MainHandler mMainHandler;
+ @VisibleForTesting WorkHandler mWorkHandler;
+ private HandlerThread mWorkThread;
private WifiTrackerNetworkCallback mNetworkCallback;
@@ -142,7 +149,7 @@
private WifiInfo mLastInfo;
private final NetworkScoreManager mNetworkScoreManager;
- private final WifiNetworkScoreCache mScoreCache;
+ private WifiNetworkScoreCache mScoreCache;
private boolean mNetworkScoringUiEnabled;
private long mMaxSpeedLabelScoreCacheAge;
@@ -169,51 +176,43 @@
return filter;
}
+ /**
+ * Use the lifecycle constructor below whenever possible
+ */
+ @Deprecated
public WifiTracker(Context context, WifiListener wifiListener,
boolean includeSaved, boolean includeScans) {
- this(context, wifiListener, null, includeSaved, includeScans);
- }
-
- public WifiTracker(Context context, WifiListener wifiListener, Looper workerLooper,
- boolean includeSaved, boolean includeScans) {
- this(context, wifiListener, workerLooper, includeSaved, includeScans, false);
- }
-
- public WifiTracker(Context context, WifiListener wifiListener,
- boolean includeSaved, boolean includeScans, boolean includePasspoints) {
- this(context, wifiListener, null, includeSaved, includeScans, includePasspoints);
- }
-
- public WifiTracker(Context context, WifiListener wifiListener, Looper workerLooper,
- boolean includeSaved, boolean includeScans, boolean includePasspoints) {
- this(context, wifiListener, workerLooper, includeSaved, includeScans, includePasspoints,
+ this(context, wifiListener, includeSaved, includeScans,
context.getSystemService(WifiManager.class),
context.getSystemService(ConnectivityManager.class),
context.getSystemService(NetworkScoreManager.class),
- Looper.myLooper(), newIntentFilter());
+ newIntentFilter());
+ }
+
+ public WifiTracker(Context context, WifiListener wifiListener,
+ @NonNull Lifecycle lifecycle, boolean includeSaved, boolean includeScans) {
+ this(context, wifiListener, includeSaved, includeScans,
+ context.getSystemService(WifiManager.class),
+ context.getSystemService(ConnectivityManager.class),
+ context.getSystemService(NetworkScoreManager.class),
+ newIntentFilter());
+ lifecycle.addObserver(this);
}
@VisibleForTesting
- WifiTracker(Context context, WifiListener wifiListener, Looper workerLooper,
- boolean includeSaved, boolean includeScans, boolean includePasspoints,
- WifiManager wifiManager, ConnectivityManager connectivityManager,
- NetworkScoreManager networkScoreManager, Looper currentLooper,
- IntentFilter filter) {
+ WifiTracker(Context context, WifiListener wifiListener,
+ boolean includeSaved, boolean includeScans,
+ WifiManager wifiManager, ConnectivityManager connectivityManager,
+ NetworkScoreManager networkScoreManager,
+ IntentFilter filter) {
if (!includeSaved && !includeScans) {
throw new IllegalArgumentException("Must include either saved or scans");
}
mContext = context;
- if (currentLooper == null) {
- // When we aren't on a looper thread, default to the main.
- currentLooper = Looper.getMainLooper();
- }
- mMainHandler = new MainHandler(currentLooper);
- mWorkHandler = new WorkHandler(
- workerLooper != null ? workerLooper : currentLooper);
+ mMainHandler = new MainHandler(Looper.getMainLooper());
mWifiManager = wifiManager;
mIncludeSaved = includeSaved;
mIncludeScans = includeScans;
- mIncludePasspoints = includePasspoints;
mListener = wifiListener;
mConnectivityManager = connectivityManager;
@@ -229,7 +228,22 @@
mNetworkScoreManager = networkScoreManager;
- mScoreCache = new WifiNetworkScoreCache(context, new CacheListener(mWorkHandler) {
+ final HandlerThread workThread = new HandlerThread(TAG
+ + "{" + Integer.toHexString(System.identityHashCode(this)) + "}",
+ Process.THREAD_PRIORITY_BACKGROUND);
+ workThread.start();
+ setWorkThread(workThread);
+ }
+
+ /**
+ * Sanity warning: this wipes out mScoreCache, so use with extreme caution
+ * @param workThread substitute Handler thread, for testing purposes only
+ */
+ @VisibleForTesting
+ void setWorkThread(HandlerThread workThread) {
+ mWorkThread = workThread;
+ mWorkHandler = new WorkHandler(workThread.getLooper());
+ mScoreCache = new WifiNetworkScoreCache(mContext, new CacheListener(mWorkHandler) {
@Override
public void networkCacheUpdated(List<ScoredNetwork> networks) {
synchronized (mLock) {
@@ -244,6 +258,11 @@
});
}
+ @Override
+ public void onDestroy() {
+ mWorkThread.quit();
+ }
+
/** Synchronously update the list of access points with the latest information. */
@MainThread
public void forceUpdate() {
@@ -312,8 +331,9 @@
* <p>Registers listeners and starts scanning for wifi networks. If this is not called
* then forceUpdate() must be called to populate getAccessPoints().
*/
+ @Override
@MainThread
- public void startTracking() {
+ public void onStart() {
synchronized (mLock) {
registerScoreCache();
@@ -361,15 +381,16 @@
/**
* Stop tracking wifi networks and scores.
*
- * <p>This should always be called when done with a WifiTracker (if startTracking was called) to
+ * <p>This should always be called when done with a WifiTracker (if onStart was called) to
* ensure proper cleanup and prevent any further callbacks from occurring.
*
* <p>Calling this method will set the {@link #mStaleScanResults} bit, which prevents
* {@link WifiListener#onAccessPointsChanged()} callbacks from being invoked (until the bit
* is unset on the next SCAN_RESULTS_AVAILABLE_ACTION).
*/
+ @Override
@MainThread
- public void stopTracking() {
+ public void onStop() {
synchronized (mLock) {
if (mRegistered) {
mContext.unregisterReceiver(mReceiver);
@@ -769,9 +790,8 @@
}
public static List<AccessPoint> getCurrentAccessPoints(Context context, boolean includeSaved,
- boolean includeScans, boolean includePasspoints) {
- WifiTracker tracker = new WifiTracker(context,
- null, null, includeSaved, includeScans, includePasspoints);
+ boolean includeScans) {
+ WifiTracker tracker = new WifiTracker(context, null, includeSaved, includeScans);
tracker.forceUpdate();
tracker.copyAndNotifyListeners(false /*notifyListeners*/);
return tracker.getAccessPoints();
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTrackerFactory.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTrackerFactory.java
index 79cee04..8b5863a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTrackerFactory.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTrackerFactory.java
@@ -16,8 +16,10 @@
package com.android.settingslib.wifi;
import android.content.Context;
-import android.os.Looper;
import android.support.annotation.Keep;
+import android.support.annotation.NonNull;
+
+import com.android.settingslib.core.lifecycle.Lifecycle;
/**
* Factory method used to inject WifiTracker instances.
@@ -31,12 +33,11 @@
}
public static WifiTracker create(
- Context context, WifiTracker.WifiListener wifiListener, Looper workerLooper,
- boolean includeSaved, boolean includeScans, boolean includePasspoints) {
+ Context context, WifiTracker.WifiListener wifiListener, @NonNull Lifecycle lifecycle,
+ boolean includeSaved, boolean includeScans) {
if(sTestingWifiTracker != null) {
return sTestingWifiTracker;
}
- return new WifiTracker(
- context, wifiListener, workerLooper, includeSaved, includeScans, includePasspoints);
+ return new WifiTracker(context, wifiListener, lifecycle, includeSaved, includeScans);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wrapper/PackageManagerWrapper.java b/packages/SettingsLib/src/com/android/settingslib/wrapper/PackageManagerWrapper.java
index 4ca5bef..b1f3f3c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wrapper/PackageManagerWrapper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wrapper/PackageManagerWrapper.java
@@ -215,6 +215,13 @@
}
/**
+ * Calls {@code PackageManager.setComponentEnabledSetting}
+ */
+ public void setComponentEnabledSetting(ComponentName componentName, int newState, int flags) {
+ mPm.setComponentEnabledSetting(componentName, newState, flags);
+ }
+
+ /**
* Calls {@code PackageManager.getApplicationInfo}
*/
public ApplicationInfo getApplicationInfo(String packageName, int flags)
@@ -228,5 +235,12 @@
public CharSequence getApplicationLabel(ApplicationInfo info) {
return mPm.getApplicationLabel(info);
}
+
+ /**
+ * Calls {@code PackageManager.queryBroadcastReceivers}
+ */
+ public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags) {
+ return mPm.queryBroadcastReceivers(intent, flags);
+ }
}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/StorageStatsSourceTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/StorageStatsSourceTest.java
new file mode 100644
index 0000000..3dabe99
--- /dev/null
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/StorageStatsSourceTest.java
@@ -0,0 +1,41 @@
+/*
+ * 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.applications;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.usage.StorageStats;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class StorageStatsSourceTest {
+ @Test
+ public void AppStorageStatsImpl_totalCorrectly() {
+ StorageStats storageStats = new StorageStats();
+ storageStats.cacheBytes = 1;
+ storageStats.codeBytes = 10;
+ storageStats.dataBytes = 100;
+ StorageStatsSource.AppStorageStatsImpl stats = new StorageStatsSource.AppStorageStatsImpl(
+ storageStats);
+
+ // Note that this does not double add the cache (111).
+ assertThat(stats.getTotalBytes()).isEqualTo(110);
+ }
+}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index f25bb28..4a1d392 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -54,7 +54,6 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
-import android.os.Looper;
import android.os.SystemClock;
import android.provider.Settings;
import android.support.test.InstrumentationRegistry;
@@ -147,10 +146,7 @@
private CountDownLatch mAccessPointsChangedLatch;
private CountDownLatch mRequestScoresLatch;
private Handler mScannerHandler;
- private HandlerThread mMainThread;
private HandlerThread mWorkerThread;
- private Looper mWorkerLooper;
- private Looper mMainLooper;
private int mOriginalScoringUiSettingValue;
@@ -162,10 +158,6 @@
mWorkerThread = new HandlerThread("TestHandlerWorkerThread");
mWorkerThread.start();
- mWorkerLooper = mWorkerThread.getLooper();
- mMainThread = new HandlerThread("TestHandlerThread");
- mMainThread.start();
- mMainLooper = mMainThread.getLooper();
// Make sure the scanner doesn't try to run on the testing thread.
HandlerThread scannerThread = new HandlerThread("ScannerWorkerThread");
@@ -283,18 +275,17 @@
}
private WifiTracker createMockedWifiTracker() {
- return new WifiTracker(
+ final WifiTracker wifiTracker = new WifiTracker(
mContext,
mockWifiListener,
- mWorkerLooper,
- true,
true,
true,
mockWifiManager,
mockConnectivityManager,
mockNetworkScoreManager,
- mMainLooper,
new IntentFilter()); // empty filter to ignore system broadcasts
+ wifiTracker.setWorkThread(mWorkerThread);
+ return wifiTracker;
}
private void startTracking(WifiTracker tracker) throws InterruptedException {
@@ -302,7 +293,7 @@
mScannerHandler.post(new Runnable() {
@Override
public void run() {
- tracker.startTracking();
+ tracker.onStart();
latch.countDown();
}
});
@@ -406,7 +397,7 @@
scanResult.capabilities = "";
WifiTracker tracker = new WifiTracker(
- InstrumentationRegistry.getTargetContext(), null, mWorkerLooper, true, true);
+ InstrumentationRegistry.getTargetContext(), null, true, true);
AccessPoint result = tracker.getCachedOrCreate(scanResult, new ArrayList<AccessPoint>());
assertTrue(result.mAccessPointListener != null);
@@ -422,7 +413,7 @@
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
WifiTracker tracker = new WifiTracker(
- InstrumentationRegistry.getTargetContext(), null, mWorkerLooper, true, true);
+ InstrumentationRegistry.getTargetContext(), null, true, true);
AccessPoint result = tracker.getCachedOrCreate(configuration, new ArrayList<AccessPoint>());
assertTrue(result.mAccessPointListener != null);
@@ -452,7 +443,7 @@
.unregisterNetworkScoreCache(NetworkKey.TYPE_WIFI, scoreCache);
// Test unregister
- tracker.stopTracking();
+ tracker.onStop();
assertTrue("Latch timed out", latch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
verify(mockNetworkScoreManager)
@@ -496,7 +487,7 @@
// Start the tracker and inject the initial scan results and then stop tracking
WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
- tracker.stopTracking();
+ tracker.onStop();
mRequestedKeys.clear();
mRequestScoresLatch = new CountDownLatch(1);
@@ -515,7 +506,7 @@
// Start the tracker and inject the initial scan results and then stop tracking
WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
updateScoresAndWaitForAccessPointsChangedCallback(tracker);
- tracker.stopTracking();
+ tracker.onStop();
assertThat(mScoreCacheCaptor.getValue().getScoredNetwork(NETWORK_KEY_1)).isNotNull();
}
@@ -675,7 +666,7 @@
WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
WifiNetworkScoreCache cache = mScoreCacheCaptor.getValue();
- tracker.stopTracking();
+ tracker.onStop();
verify(mockNetworkScoreManager).unregisterNetworkScoreCache(NetworkKey.TYPE_WIFI, cache);
// Verify listener is unregistered so updating a score does not throw an error by posting
@@ -795,7 +786,7 @@
tracker.mMainHandler.sendEmptyMessage(
WifiTracker.MainHandler.MSG_WIFI_STATE_CHANGED);
- tracker.stopTracking();
+ tracker.onStop();
verify(mockWifiListener, atMost(1)).onAccessPointsChanged();
verify(mockWifiListener, atMost(1)).onConnectedChanged();
@@ -821,7 +812,7 @@
startTracking(tracker);
waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
- tracker.stopTracking();
+ tracker.onStop();
waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
startTracking(tracker);
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 6da67df..1be0645 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -193,4 +193,7 @@
<!-- Default for Settings.Secure.BACKUP_MANAGER_CONSTANTS -->
<string name="def_backup_manager_constants"></string>
+
+ <!-- Default setting for Settings.Global.MOBILE_DATA_ALWAYS_ON -->
+ <bool name="def_mobile_data_always_on">true</bool>
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index a463db6..36f9b84 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2896,7 +2896,7 @@
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 149;
+ private static final int SETTINGS_VERSION = 150;
private final int mUserId;
@@ -3470,9 +3470,25 @@
true, SettingsState.SYSTEM_PACKAGE_NAME);
}
}
-
currentVersion = 149;
}
+
+ if (currentVersion == 149) {
+ // Version 150: Set a default value for mobile data always on
+ final SettingsState globalSettings = getGlobalSettingsLocked();
+ final Setting currentSetting = globalSettings.getSettingLocked(
+ Settings.Global.MOBILE_DATA_ALWAYS_ON);
+ if (currentSetting.isNull()) {
+ globalSettings.insertSettingLocked(
+ Settings.Global.MOBILE_DATA_ALWAYS_ON,
+ getContext().getResources().getBoolean(
+ R.bool.def_mobile_data_always_on) ? "1" : "0",
+ null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+ }
+
+ currentVersion = 150;
+ }
+
// vXXX: Add new settings above this point.
if (currentVersion != newVersion) {
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index b758e7f5..eab42da 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -96,6 +96,9 @@
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
<uses-permission android:name="android.permission.CREATE_USERS" />
<uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
+ <uses-permission android:name="android.permission.ACCESS_LOWPAN_STATE"/>
+ <uses-permission android:name="android.permission.CHANGE_LOWPAN_STATE"/>
+ <uses-permission android:name="android.permission.READ_LOWPAN_CREDENTIAL"/>
<uses-permission android:name="android.permission.BLUETOOTH_STACK" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.RETRIEVE_WINDOW_TOKEN" />
diff --git a/packages/SystemUI/res/drawable/recents_low_ram_stack_button_background.xml b/packages/SystemUI/res/drawable/recents_low_ram_stack_button_background.xml
index db2eb3a..bff97f6 100644
--- a/packages/SystemUI/res/drawable/recents_low_ram_stack_button_background.xml
+++ b/packages/SystemUI/res/drawable/recents_low_ram_stack_button_background.xml
@@ -17,6 +17,6 @@
<corners android:radius="@dimen/borderless_button_radius" />
- <solid android:color="#CC000000" />
+ <solid android:color="?attr/clearAllBackgroundColor" />
</shape>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 9f44d67..aa2eee4 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -155,7 +155,7 @@
<string name="accessibility_cell_data" msgid="5326139158682385073">"موبائل ڈیٹا"</string>
<string name="accessibility_cell_data_on" msgid="5927098403452994422">"موبائل ڈیٹا آن ہے"</string>
<string name="accessibility_cell_data_off" msgid="443267573897409704">"موبائل ڈیٹا آف ہے"</string>
- <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"بلوٹوتھ ٹیتھرنگ۔"</string>
+ <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"بلوٹوتھ ٹیدرنگ۔"</string>
<string name="accessibility_airplane_mode" msgid="834748999790763092">"ہوائی جہاز وضع۔"</string>
<string name="accessibility_vpn_on" msgid="5993385083262856059">"VPN آن ہے۔"</string>
<string name="accessibility_no_sims" msgid="3957997018324995781">"کوئی SIM کارڈ نہیں ہے۔"</string>
@@ -312,7 +312,7 @@
<string name="quick_settings_connected" msgid="1722253542984847487">"مربوط"</string>
<string name="quick_settings_connected_battery_level" msgid="4136051440381328892">"منسلک ہے، بیٹری <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="quick_settings_connecting" msgid="47623027419264404">"مربوط ہو رہا ہے…"</string>
- <string name="quick_settings_tethering_label" msgid="7153452060448575549">"ٹیتھرنگ"</string>
+ <string name="quick_settings_tethering_label" msgid="7153452060448575549">"ٹیدرنگ"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"ہاٹ اسپاٹ"</string>
<string name="quick_settings_notifications_label" msgid="4818156442169154523">"اطلاعات"</string>
<string name="quick_settings_flashlight_label" msgid="2133093497691661546">"فلیش لائٹ"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 87f6306..8a1e0b9 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -422,4 +422,14 @@
increase the rate of unintentional unlocks. -->
<bool name="config_lockscreenAntiFalsingClassifierEnabled">true</bool>
+ <!-- Snooze: default notificaiton snooze time. -->
+ <integer name="config_notification_snooze_time_default">60</integer>
+
+ <!-- Snooze: List of snooze values in integer minutes. -->
+ <integer-array name="config_notification_snooze_times">
+ <item>15</item>
+ <item>30</item>
+ <item>60</item>
+ <item>120</item>
+ </integer-array>
</resources>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 2148c80..e5f8029 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -82,10 +82,10 @@
<!-- Accessibility actions for the notification menu -->
<item type="id" name="action_snooze_undo"/>
- <item type="id" name="action_snooze_15_min"/>
- <item type="id" name="action_snooze_30_min"/>
- <item type="id" name="action_snooze_1_hour"/>
- <item type="id" name="action_snooze_2_hours"/>
+ <item type="id" name="action_snooze_shorter"/>
+ <item type="id" name="action_snooze_short"/>
+ <item type="id" name="action_snooze_long"/>
+ <item type="id" name="action_snooze_longer"/>
<item type="id" name="action_snooze_assistant_suggestion_1"/>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index c5eebcc..8a8bafa 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -61,6 +61,7 @@
private AssistOrbContainer mView;
private final DeviceProvisionedController mDeviceProvisionedController;
protected final AssistUtils mAssistUtils;
+ private final boolean mShouldEnableOrb;
private IVoiceInteractionSessionShowCallback mShowCallback =
new IVoiceInteractionSessionShowCallback.Stub() {
@@ -96,6 +97,7 @@
| ActivityInfo.CONFIG_LOCALE | ActivityInfo.CONFIG_UI_MODE
| ActivityInfo.CONFIG_SCREEN_LAYOUT | ActivityInfo.CONFIG_ASSETS_PATHS);
onConfigurationChanged(context.getResources().getConfiguration());
+ mShouldEnableOrb = !ActivityManager.isLowRamDeviceStatic();
}
protected void registerVoiceInteractionSessionListener() {
@@ -179,7 +181,9 @@
private void showOrb(@NonNull ComponentName assistComponent, boolean isService) {
maybeSwapSearchIcon(assistComponent, isService);
- mView.show(true /* show */, true /* animate */);
+ if (mShouldEnableOrb) {
+ mView.show(true /* show */, true /* animate */);
+ }
}
private void startAssistInternal(Bundle args, @NonNull ComponentName assistComponent,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 16c74e3..c7edb9a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -203,10 +203,6 @@
mStackButtonShadowDistance.x, mStackButtonShadowDistance.y,
mStackButtonShadowColor);
}
- if (Recents.getConfiguration().isLowRamDevice) {
- int bgColor = Utils.getColorAttr(mContext, R.attr.clearAllBackgroundColor);
- mStackActionButton.setBackgroundColor(bgColor);
- }
}
// Let's also require dark status and nav bars if the text is dark
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java
index c45ca54..492ab44 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java
@@ -16,8 +16,13 @@
*/
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.TimeUnit;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
@@ -28,12 +33,15 @@
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Typeface;
+import android.metrics.LogMaker;
import android.os.Bundle;
+import android.provider.Settings;
import android.service.notification.SnoozeCriterion;
import android.service.notification.StatusBarNotification;
import android.text.SpannableString;
import android.text.style.StyleSpan;
import android.util.AttributeSet;
+import android.util.KeyValueListParser;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -51,11 +59,23 @@
public class NotificationSnooze extends LinearLayout
implements NotificationGuts.GutsContent, View.OnClickListener {
+ private static final String TAG = "NotificationSnooze";
/**
* If this changes more number increases, more assistant action resId's should be defined for
* accessibility purposes, see {@link #setSnoozeOptions(List)}
*/
private static final int MAX_ASSISTANT_SUGGESTIONS = 1;
+ private static final String KEY_DEFAULT_SNOOZE = "default";
+ private static final String KEY_OPTIONS = "options_array";
+ private static final LogMaker OPTIONS_OPEN_LOG =
+ new LogMaker(MetricsEvent.NOTIFICATION_SNOOZE_OPTIONS)
+ .setType(MetricsEvent.TYPE_OPEN);
+ private static final LogMaker OPTIONS_CLOSE_LOG =
+ new LogMaker(MetricsEvent.NOTIFICATION_SNOOZE_OPTIONS)
+ .setType(MetricsEvent.TYPE_CLOSE);
+ private static final LogMaker UNDO_LOG =
+ new LogMaker(MetricsEvent.NOTIFICATION_UNDO_SNOOZE)
+ .setType(MetricsEvent.TYPE_ACTION);
private NotificationGuts mGutsContainer;
private NotificationSwipeActionHelper mSnoozeListener;
private StatusBarNotification mSbn;
@@ -72,9 +92,31 @@
private boolean mSnoozing;
private boolean mExpanded;
private AnimatorSet mExpandAnimation;
+ private KeyValueListParser mParser;
+
+ private final static int[] sAccessibilityActions = {
+ R.id.action_snooze_shorter,
+ R.id.action_snooze_short,
+ R.id.action_snooze_long,
+ R.id.action_snooze_longer,
+ };
+
+ private MetricsLogger mMetricsLogger = new MetricsLogger();
public NotificationSnooze(Context context, AttributeSet attrs) {
super(context, attrs);
+ mParser = new KeyValueListParser(',');
+ }
+
+ @VisibleForTesting
+ SnoozeOption getDefaultOption()
+ {
+ return mDefaultOption;
+ }
+
+ @VisibleForTesting
+ void setKeyValueListParser(KeyValueListParser parser) {
+ mParser = parser;
}
@Override
@@ -96,7 +138,13 @@
mSnoozeOptions = getDefaultSnoozeOptions();
createOptionViews();
- setSelected(mDefaultOption);
+ setSelected(mDefaultOption, false);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ logOptionSelection(MetricsEvent.NOTIFICATION_SNOOZE_CLICKED, mDefaultOption);
}
@Override
@@ -136,7 +184,7 @@
SnoozeOption so = mSnoozeOptions.get(i);
if (so.getAccessibilityAction() != null
&& so.getAccessibilityAction().getId() == action) {
- setSelected(so);
+ setSelected(so, true);
return true;
}
}
@@ -172,17 +220,49 @@
mSbn = sbn;
}
- private ArrayList<SnoozeOption> getDefaultSnoozeOptions() {
+ @VisibleForTesting
+ ArrayList<SnoozeOption> getDefaultSnoozeOptions() {
+ final Resources resources = getContext().getResources();
ArrayList<SnoozeOption> options = new ArrayList<>();
+ try {
+ final String config = Settings.Global.getString(getContext().getContentResolver(),
+ Settings.Global.NOTIFICATION_SNOOZE_OPTIONS);
+ mParser.setString(config);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Bad snooze constants");
+ }
- options.add(createOption(15 /* minutes */, R.id.action_snooze_15_min));
- options.add(createOption(30 /* minutes */, R.id.action_snooze_30_min));
- mDefaultOption = createOption(60 /* minutes */, R.id.action_snooze_1_hour);
- options.add(mDefaultOption);
- options.add(createOption(60 * 2 /* minutes */, R.id.action_snooze_2_hours));
+ final int defaultSnooze = mParser.getInt(KEY_DEFAULT_SNOOZE,
+ resources.getInteger(R.integer.config_notification_snooze_time_default));
+ final int[] snoozeTimes = parseIntArray(KEY_OPTIONS,
+ resources.getIntArray(R.array.config_notification_snooze_times));
+
+ for (int i = 0; i < snoozeTimes.length && i < sAccessibilityActions.length; i++) {
+ int snoozeTime = snoozeTimes[i];
+ SnoozeOption option = createOption(snoozeTime, sAccessibilityActions[i]);
+ if (i == 0 || snoozeTime == defaultSnooze) {
+ mDefaultOption = option;
+ }
+ options.add(option);
+ }
return options;
}
+ @VisibleForTesting
+ int[] parseIntArray(final String key, final int[] defaultArray) {
+ final String value = mParser.getString(key, null);
+ if (value != null) {
+ try {
+ return Arrays.stream(value.split(":")).map(String::trim).mapToInt(
+ Integer::parseInt).toArray();
+ } catch (NumberFormatException e) {
+ return defaultArray;
+ }
+ } else {
+ return defaultArray;
+ }
+ }
+
private SnoozeOption createOption(int minutes, int accessibilityActionId) {
Resources res = getResources();
boolean showInHours = minutes >= 60;
@@ -268,12 +348,24 @@
mExpandAnimation.start();
}
- private void setSelected(SnoozeOption option) {
+ private void setSelected(SnoozeOption option, boolean userAction) {
mSelectedOption = option;
mSelectedOptionText.setText(option.getConfirmation());
showSnoozeOptions(false);
hideSelectedOption();
sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+ if (userAction) {
+ logOptionSelection(MetricsEvent.NOTIFICATION_SELECT_SNOOZE, option);
+ }
+ }
+
+ private void logOptionSelection(int category, SnoozeOption option) {
+ int index = mSnoozeOptions.indexOf(option);
+ long duration = TimeUnit.MINUTES.toMillis(option.getMinutesToSnoozeFor());
+ mMetricsLogger.write(new LogMaker(category)
+ .setType(MetricsEvent.TYPE_ACTION)
+ .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_INDEX, index)
+ .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS, duration));
}
@Override
@@ -284,13 +376,15 @@
final int id = v.getId();
final SnoozeOption tag = (SnoozeOption) v.getTag();
if (tag != null) {
- setSelected(tag);
+ setSelected(tag, true);
} else if (id == R.id.notification_snooze) {
// Toggle snooze options
showSnoozeOptions(!mExpanded);
+ mMetricsLogger.write(!mExpanded ? OPTIONS_OPEN_LOG : OPTIONS_CLOSE_LOG);
} else {
// Undo snooze was selected
undoSnooze(v);
+ mMetricsLogger.write(UNDO_LOG);
}
}
@@ -321,7 +415,7 @@
@Override
public View getContentView() {
// Reset the view before use
- setSelected(mDefaultOption);
+ setSelected(mDefaultOption, false);
return this;
}
@@ -343,7 +437,7 @@
return true;
} else {
// The view should actually be closed
- setSelected(mSnoozeOptions.get(0));
+ setSelected(mSnoozeOptions.get(0), false);
return false; // Return false here so that guts handles closing the view
}
}
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 274c024..54b4e35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1437,6 +1437,11 @@
animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
};
+ if (hideAnimatedList.isEmpty()) {
+ animationFinishAction.run();
+ return;
+ }
+
// let's disable our normal animations
mStackScroller.setDismissAllInProgress(true);
@@ -2992,6 +2997,9 @@
}
}
+ // TODO(b/62444020): remove when this bug is fixed
+ Log.v(TAG, "mStatusBarWindow: " + mStatusBarWindow + " canPanelBeCollapsed(): "
+ + mNotificationPanel.canPanelBeCollapsed());
if (mStatusBarWindow != null && mNotificationPanel.canPanelBeCollapsed()) {
// release focus immediately to kick off focus change transition
mStatusBarWindowManager.setStatusBarFocusable(false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
index c0a6837..0d21c4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
@@ -20,7 +20,6 @@
import android.content.Context;
import android.content.Intent;
import android.net.wifi.WifiManager.ActionListener;
-import android.os.Looper;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
@@ -59,13 +58,19 @@
private int mCurrentUser;
- public AccessPointControllerImpl(Context context, Looper bgLooper) {
+ public AccessPointControllerImpl(Context context) {
mContext = context;
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- mWifiTracker = new WifiTracker(context, this, bgLooper, false, true);
+ mWifiTracker = new WifiTracker(context, this, false, true);
mCurrentUser = ActivityManager.getCurrentUser();
}
+ @Override
+ protected void finalize() throws Throwable {
+ super.finalize();
+ mWifiTracker.onDestroy();
+ }
+
public boolean canConfigWifi() {
return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI,
new UserHandle(mCurrentUser));
@@ -81,7 +86,7 @@
if (DEBUG) Log.d(TAG, "addCallback " + callback);
mCallbacks.add(callback);
if (mCallbacks.size() == 1) {
- mWifiTracker.startTracking();
+ mWifiTracker.onStart();
}
}
@@ -91,7 +96,7 @@
if (DEBUG) Log.d(TAG, "removeCallback " + callback);
mCallbacks.remove(callback);
if (mCallbacks.isEmpty()) {
- mWifiTracker.stopTracking();
+ mWifiTracker.onStop();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 3e9d000..d24e51c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -150,7 +150,7 @@
(WifiManager) context.getSystemService(Context.WIFI_SERVICE),
SubscriptionManager.from(context), Config.readConfig(context), bgLooper,
new CallbackHandler(),
- new AccessPointControllerImpl(context, bgLooper),
+ new AccessPointControllerImpl(context),
new DataUsageController(context),
new SubscriptionDefaults(),
deviceProvisionedController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationSnoozeTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationSnoozeTest.java
new file mode 100644
index 0000000..6b31c96
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationSnoozeTest.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import android.provider.Settings;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableResources;
+import android.testing.UiThreadTest;
+import android.util.KeyValueListParser;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Matchers.isNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@UiThreadTest
+public class NotificationSnoozeTest extends SysuiTestCase {
+ private static final int RES_DEFAULT = 2;
+ private static final int[] RES_OPTIONS = {1, 2, 3};
+ private NotificationSnooze mNotificationSnooze;
+ private KeyValueListParser mMockParser;
+
+ @Before
+ public void setUp() throws Exception {
+ Settings.Global.putString(mContext.getContentResolver(),
+ Settings.Global.NOTIFICATION_SNOOZE_OPTIONS, null);
+ TestableResources resources = mContext.getOrCreateTestableResources();
+ resources.addOverride(R.integer.config_notification_snooze_time_default, RES_DEFAULT);
+ resources.addOverride(R.array.config_notification_snooze_times, RES_OPTIONS);
+ mNotificationSnooze = new NotificationSnooze(mContext, null);
+ mMockParser = mock(KeyValueListParser.class);
+ }
+
+ @Test
+ public void testParseIntArrayNull() throws Exception {
+ when(mMockParser.getString(anyString(), isNull())).thenReturn(null);
+ mNotificationSnooze.setKeyValueListParser(mMockParser);
+
+ int[] result = mNotificationSnooze.parseIntArray("foo", RES_OPTIONS);
+ assertEquals(RES_OPTIONS, result);
+ }
+
+ @Test
+ public void testParseIntArrayLeadingSep() throws Exception {
+ when(mMockParser.getString(anyString(), isNull())).thenReturn(":4:5:6");
+ mNotificationSnooze.setKeyValueListParser(mMockParser);
+
+ int[] result = mNotificationSnooze.parseIntArray("foo", RES_OPTIONS);
+ assertEquals(RES_OPTIONS, result);
+ }
+
+ @Test
+ public void testParseIntArrayEmptyItem() throws Exception {
+ when(mMockParser.getString(anyString(), isNull())).thenReturn("4::6");
+ mNotificationSnooze.setKeyValueListParser(mMockParser);
+
+ int[] result = mNotificationSnooze.parseIntArray("foo", RES_OPTIONS);
+ assertEquals(RES_OPTIONS, result);
+ }
+
+ @Test
+ public void testParseIntArrayTrailingSep() throws Exception {
+ when(mMockParser.getString(anyString(), isNull())).thenReturn("4:5:6:");
+ mNotificationSnooze.setKeyValueListParser(mMockParser);
+
+ int[] result = mNotificationSnooze.parseIntArray("foo", RES_OPTIONS);
+ assertEquals(3, result.length);
+ assertEquals(4, result[0]); // respect order
+ assertEquals(5, result[1]);
+ assertEquals(6, result[2]);
+ }
+
+ @Test
+ public void testParseIntArrayGoodData() throws Exception {
+ when(mMockParser.getString(anyString(), isNull())).thenReturn("4:5:6");
+ mNotificationSnooze.setKeyValueListParser(mMockParser);
+
+ int[] result = mNotificationSnooze.parseIntArray("foo", RES_OPTIONS);
+ assertEquals(3, result.length);
+ assertEquals(4, result[0]); // respect order
+ assertEquals(5, result[1]);
+ assertEquals(6, result[2]);
+ }
+
+ @Test
+ public void testGetOptionsWithNoConfig() throws Exception {
+ ArrayList<SnoozeOption> result = mNotificationSnooze.getDefaultSnoozeOptions();
+ assertEquals(3, result.size());
+ assertEquals(1, result.get(0).getMinutesToSnoozeFor()); // respect order
+ assertEquals(2, result.get(1).getMinutesToSnoozeFor());
+ assertEquals(3, result.get(2).getMinutesToSnoozeFor());
+ assertEquals(2, mNotificationSnooze.getDefaultOption().getMinutesToSnoozeFor());
+ }
+
+ @Test
+ public void testGetOptionsWithInvalidConfig() throws Exception {
+ Settings.Global.putString(mContext.getContentResolver(),
+ Settings.Global.NOTIFICATION_SNOOZE_OPTIONS,
+ "this is garbage");
+ ArrayList<SnoozeOption> result = mNotificationSnooze.getDefaultSnoozeOptions();
+ assertEquals(3, result.size());
+ assertEquals(1, result.get(0).getMinutesToSnoozeFor()); // respect order
+ assertEquals(2, result.get(1).getMinutesToSnoozeFor());
+ assertEquals(3, result.get(2).getMinutesToSnoozeFor());
+ assertEquals(2, mNotificationSnooze.getDefaultOption().getMinutesToSnoozeFor());
+ }
+
+ @Test
+ public void testGetOptionsWithValidDefault() throws Exception {
+ Settings.Global.putString(mContext.getContentResolver(),
+ Settings.Global.NOTIFICATION_SNOOZE_OPTIONS,
+ "default=10,options_array=4:5:6:7");
+ ArrayList<SnoozeOption> result = mNotificationSnooze.getDefaultSnoozeOptions();
+ assertNotNull(mNotificationSnooze.getDefaultOption()); // pick one
+ }
+
+ @Test
+ public void testGetOptionsWithValidConfig() throws Exception {
+ Settings.Global.putString(mContext.getContentResolver(),
+ Settings.Global.NOTIFICATION_SNOOZE_OPTIONS,
+ "default=6,options_array=4:5:6:7");
+ ArrayList<SnoozeOption> result = mNotificationSnooze.getDefaultSnoozeOptions();
+ assertEquals(4, result.size());
+ assertEquals(4, result.get(0).getMinutesToSnoozeFor()); // respect order
+ assertEquals(5, result.get(1).getMinutesToSnoozeFor());
+ assertEquals(6, result.get(2).getMinutesToSnoozeFor());
+ assertEquals(7, result.get(3).getMinutesToSnoozeFor());
+ assertEquals(6, mNotificationSnooze.getDefaultOption().getMinutesToSnoozeFor());
+ }
+
+ @Test
+ public void testGetOptionsWithLongConfig() throws Exception {
+ Settings.Global.putString(mContext.getContentResolver(),
+ Settings.Global.NOTIFICATION_SNOOZE_OPTIONS,
+ "default=6,options_array=4:5:6:7:8:9:10:11:12:13:14:15:16:17");
+ ArrayList<SnoozeOption> result = mNotificationSnooze.getDefaultSnoozeOptions();
+ assertTrue(result.size() > 3);
+ assertEquals(4, result.get(0).getMinutesToSnoozeFor()); // respect order
+ assertEquals(5, result.get(1).getMinutesToSnoozeFor());
+ assertEquals(6, result.get(2).getMinutesToSnoozeFor());
+ }
+}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 787d363..e17a6a6 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3851,7 +3851,7 @@
// Tag of a field for the length of the filter text
FIELD_AUTOFILL_FILTERTEXT_LEN = 911;
- // An autofill authentification succeeded
+ // An autofill authentication succeeded
// Package: Package of app that was autofilled
AUTOFILL_AUTHENTICATED = 912;
@@ -4462,19 +4462,19 @@
// OS: O MR
FIELD_AUTOFILL_PREVIOUS_LENGTH = 1125;
- // An autofill dataset authentification succeeded
+ // An autofill dataset authentication succeeded
// Package: Package of app that was autofilled
// OS: O MR
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
AUTOFILL_DATASET_AUTHENTICATED = 1126;
- // An autofill service provided an invalid dataset authentification
+ // An autofill service provided an invalid dataset authentication
// Package: Package of app that was autofilled
// OS: O MR
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
AUTOFILL_INVALID_DATASET_AUTHENTICATION = 1127;
- // An autofill service provided an invalid authentification extra
+ // An autofill service provided an invalid authentication extra
// Package: Package of app that was autofilled
// OS: O MR
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
@@ -4538,103 +4538,132 @@
// OS: O MR
AUTOFILL_UI_LATENCY = 1136;
+ // Action: the snooze leave-behind was shown after the user clicked the snooze icon
+ // OS: O MR
+ NOTIFICATION_SNOOZE_CLICKED = 1137;
+
+ // Action: user selected a notification snooze duration from the drop down
+ // OS: O MR
+ NOTIFICATION_SELECT_SNOOZE = 1138;
+
+ // attached to NOTIFICATION_SNOOZED and NOTIFICATION_SELECT_SNOOZE events
+ // OS: O MR
+ FIELD_NOTIFICATION_SNOOZE_DURATION_MS = 1139;
+
+ // attached to NOTIFICATION_SELECT_SNOOZE events to indicate the option selected
+ // OS: O MR
+ FIELD_NOTIFICATION_SNOOZE_INDEX = 1140;
+
+ // Action: user tapped undo on the notification snooze leave-behind
+ // OS: O MR
+ NOTIFICATION_UNDO_SNOOZE = 1141;
+
+ // Action: user togged the visibility of the notification snooze options drop down
+ // OS: O MR
+ NOTIFICATION_SNOOZE_OPTIONS = 1142;
+
// ---- End O-MR1 Constants, all O-MR1 constants go above this line ----
// OPEN: Settings > Network & Internet > Mobile network
// CATEGORY: SETTINGS
- SETTINGS_MOBILE_NETWORK_CATEGORY = 1139;
+ SETTINGS_MOBILE_NETWORK_CATEGORY = 1200;
// ACTION: Settings > Network & Internet > Mobile network > Roaming
// CATEGORY: SETTINGS
- ACTION_MOBILE_NETWORK_DATA_ROAMING_TOGGLE = 1140;
+ ACTION_MOBILE_NETWORK_DATA_ROAMING_TOGGLE = 1201;
// ACTION: Settings > Network & Internet > Mobile network > Advanced
// CATEGORY: SETTINGS
- ACTION_MOBILE_NETWORK_EXPAND_ADVANCED_FIELDS = 1141;
+ ACTION_MOBILE_NETWORK_EXPAND_ADVANCED_FIELDS = 1202;
// ACTION: Settings > Network & Internet > Mobile network > Enhanced 4G LTE Mode
// CATEGORY: SETTINGS
- ACTION_MOBILE_ENHANCED_4G_LTE_MODE_TOGGLE = 1142;
+ ACTION_MOBILE_ENHANCED_4G_LTE_MODE_TOGGLE = 1203;
// ACTION: Settings > Network & Internet > Mobile network > Preferred network type
// CATEGORY: SETTINGS
- ACTION_MOBILE_NETWORK_SELECT_PREFERRED_NETWORK = 1143;
+ ACTION_MOBILE_NETWORK_SELECT_PREFERRED_NETWORK = 1204;
// ACTION: Settings > Network & Internet > Mobile network > Preferred network type (enabled networks)
// CATEGORY: SETTINGS
- ACTION_MOBILE_NETWORK_SELECT_ENABLED_NETWORK = 1144;
+ ACTION_MOBILE_NETWORK_SELECT_ENABLED_NETWORK = 1205;
// OPEN: Settings > Network & Internet > Mobile network > Carrier
// CATEGORY: SETTINGS
- ACTION_MOBILE_NETWORK_EUICC_SETTING = 1145;
+ ACTION_MOBILE_NETWORK_EUICC_SETTING = 1206;
// OPEN: Settings > Network & Internet > Mobile network > Wi-Fi calling
// CATEGORY: SETTINGS
- ACTION_MOBILE_NETWORK_WIFI_CALLING = 1146;
+ ACTION_MOBILE_NETWORK_WIFI_CALLING = 1207;
// ACTION: Settings > Network & Internet > Mobile network > Carrier video calling
// CATEGORY: SETTINGS
- ACTION_MOBILE_NETWORK_VIDEO_CALLING_TOGGLE = 1147;
+ ACTION_MOBILE_NETWORK_VIDEO_CALLING_TOGGLE = 1208;
// ACTION: Settings > Network & Internet > Mobile network > Automatically select network
// CATEGORY: SETTINGS
- ACTION_MOBILE_NETWORK_AUTO_SELECT_NETWORK_TOGGLE = 1148;
+ ACTION_MOBILE_NETWORK_AUTO_SELECT_NETWORK_TOGGLE = 1209;
// ACTION: Settings > Network & Internet > Mobile network > Network
// CATEGORY: SETTINGS
- ACTION_MOBILE_NETWORK_MANUAL_SELECT_NETWORK = 1149;
+ ACTION_MOBILE_NETWORK_MANUAL_SELECT_NETWORK = 1210;
// FIELD - Manually selected mobile network
- FIELD_MOBILE_NETWORK = 1150;
+ FIELD_MOBILE_NETWORK = 1211;
// OPEN: Settings > Network & Internet > Mobile network > Access Point Names
// CATEGORY: SETTINGS
- ACTION_MOBILE_NETWORK_APN_SETTINGS = 1151;
+ ACTION_MOBILE_NETWORK_APN_SETTINGS = 1212;
// OPEN: Settings > Network & Internet > Mobile network > Carrier settings
// CATEGORY: SETTINGS
- ACTION_MOBILE_NETWORK_CARRIER_SETTINGS = 1152;
+ ACTION_MOBILE_NETWORK_CARRIER_SETTINGS = 1213;
// OPEN: Settings > Network & Internet > Mobile network > System select
// CATEGORY: SETTINGS
- ACTION_MOBILE_NETWORK_CDMA_SYSTEM_SELECT = 1153;
+ ACTION_MOBILE_NETWORK_CDMA_SYSTEM_SELECT = 1214;
// OPEN: Settings > Network & Internet > Mobile network > CDMA subscription
// CATEGORY: SETTINGS
- ACTION_MOBILE_NETWORK_CDMA_SUBSCRIPTION_SELECT = 1154;
+ ACTION_MOBILE_NETWORK_CDMA_SUBSCRIPTION_SELECT = 1215;
// ACTION: Settings > Network & Internet > Mobile network > Set up data service
// CATEGORY: SETTINGS
- ACTION_MOBILE_NETWORK_SET_UP_DATA_SERVICE = 1155;
+ ACTION_MOBILE_NETWORK_SET_UP_DATA_SERVICE = 1216;
// OPEN: Settings > Developer Options > Experiment dashboard
// CATEGORY: SETTINGS
- SETTINGS_FEATURE_FLAGS_DASHBOARD = 1156;
+ SETTINGS_FEATURE_FLAGS_DASHBOARD = 1217;
// OPEN: Settings > Notifications > [App] > Topic Notifications
// CATEGORY: SETTINGS
// OS: P
- NOTIFICATION_CHANNEL_GROUP = 1157;
+ NOTIFICATION_CHANNEL_GROUP = 1218;
// OPEN: Settings > Developer options > Enable > Info dialog
// CATEGORY: SETTINGS
// OS: P
- DIALOG_ENABLE_DEVELOPMENT_OPTIONS = 1158;
+ DIALOG_ENABLE_DEVELOPMENT_OPTIONS = 1219;
// OPEN: Settings > Developer options > OEM unlocking > Info dialog
// CATEGORY: SETTINGS
// OS: P
- DIALOG_ENABLE_OEM_UNLOCKING = 1159;
+ DIALOG_ENABLE_OEM_UNLOCKING = 1220;
// OPEN: Settings > Security > Nexus Imprint > [Fingerprint]
// CATEGORY: SETTINGS
// OS: P
- FINGERPRINT_AUTHENTICATE_SIDECAR = 1160;
+ FINGERPRINT_AUTHENTICATE_SIDECAR = 1221;
// OPEN: Settings > Developer options > USB debugging > Info dialog
// CATEGORY: SETTINGS
// OS: P
- DIALOG_ENABLE_ADB = 1161;
+ DIALOG_ENABLE_ADB = 1222;
+
+ // OPEN: Settings > Developer options > Revoke USB debugging authorizations > Info dialog
+ // CATEGORY: SETTINGS
+ // OS: P
+ DIALOG_CLEAR_ADB_KEYS = 1223;
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index 28bf856..54eba2b 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -315,6 +315,27 @@
// Pno scan metrics
optional PnoScanMetrics pno_scan_metrics = 76;
+
+ // Histogram of "Connect to Network" notifications.
+ // The notification Action should be unset.
+ repeated ConnectToNetworkNotificationAndActionCount connect_to_network_notification_count = 77;
+
+ // Histogram of "Connect to Network" notification user actions.
+ repeated ConnectToNetworkNotificationAndActionCount connect_to_network_notification_action_count = 78;
+
+ // The number of SSIDs blacklisted from recommendation by the open network
+ // notification recommender
+ optional int32 open_network_recommender_blacklist_size = 79;
+
+ // Is the available network notification feature turned on
+ optional bool is_wifi_networks_available_notification_on = 80;
+
+ // Count of recommendation updates made by the open network notification
+ // recommender
+ optional int32 num_open_network_recommendation_updates = 81;
+
+ // Count of connection attempts that were initiated unsuccessfully
+ optional int32 num_open_network_connect_message_failed_to_send = 82;
}
// Information that gets logged for every WiFi connection.
@@ -950,3 +971,68 @@
// Total number of pno scans that found any network
optional int32 num_pno_found_network_events = 5;
}
+
+// Number of occurrences for a particular "Connect to Network" Notification or
+// notification Action.
+message ConnectToNetworkNotificationAndActionCount {
+
+ // "Connect to Network" notifications
+ enum Notification {
+
+ // Default
+ NOTIFICATION_UNKNOWN = 0;
+
+ // Initial notification with a recommended network.
+ NOTIFICATION_RECOMMEND_NETWORK = 1;
+
+ // Notification when connecting to the recommended network.
+ NOTIFICATION_CONNECTING_TO_NETWORK = 2;
+
+ // Notification when successfully connected to the network.
+ NOTIFICATION_CONNECTED_TO_NETWORK = 3;
+
+ // Notification when failed to connect to network.
+ NOTIFICATION_FAILED_TO_CONNECT = 4;
+ }
+
+ // "Connect to Network" notification actions
+ enum Action {
+
+ // Default
+ ACTION_UNKNOWN = 0;
+
+ // User dismissed the "Connect to Network" notification.
+ ACTION_USER_DISMISSED_NOTIFICATION = 1;
+
+ // User tapped action button to connect to recommended network.
+ ACTION_CONNECT_TO_NETWORK = 2;
+
+ // User tapped action button to open Wi-Fi Settings.
+ ACTION_PICK_WIFI_NETWORK = 3;
+
+ // User tapped "Failed to connect" notification to open Wi-Fi Settings.
+ ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE = 4;
+ }
+
+ // Recommenders of the "Connect to Network" notification
+ enum Recommender {
+
+ // Default.
+ RECOMMENDER_UNKNOWN = 0;
+
+ // Open Network Available recommender.
+ RECOMMENDER_OPEN = 1;
+ }
+
+ // Notification Type.
+ optional Notification notification = 1;
+
+ // Action Type.
+ optional Action action = 2;
+
+ // Recommender Type.
+ optional Recommender recommender = 3;
+
+ // Occurrences of this action.
+ optional int32 count = 4;
+}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 2f31fc3..f4dbb5a 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1987,7 +1987,7 @@
if (uri == null) {
return;
}
- String pkgName = uri.getSchemeSpecificPart();
+ final String pkgName = uri.getSchemeSpecificPart();
if (pkgName != null) {
pkgList = new String[] { pkgName };
}
@@ -1995,7 +1995,7 @@
// At package-changed we only care about looking at new transport states
if (changed) {
- String[] components =
+ final String[] components =
intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
if (MORE_DEBUG) {
@@ -2005,7 +2005,8 @@
}
}
- mTransportManager.onPackageChanged(pkgName, components);
+ mBackupHandler.post(
+ () -> mTransportManager.onPackageChanged(pkgName, components));
return; // nothing more to do in the PACKAGE_CHANGED case
}
@@ -2037,7 +2038,7 @@
}
// If they're full-backup candidates, add them there instead
final long now = System.currentTimeMillis();
- for (String packageName : pkgList) {
+ for (final String packageName : pkgList) {
try {
PackageInfo app = mPackageManager.getPackageInfo(packageName, 0);
if (appGetsFullBackup(app)
@@ -2054,7 +2055,8 @@
writeFullBackupScheduleAsync();
}
- mTransportManager.onPackageAdded(packageName);
+ mBackupHandler.post(
+ () -> mTransportManager.onPackageAdded(packageName));
} catch (NameNotFoundException e) {
// doesn't really exist; ignore it
@@ -2078,8 +2080,9 @@
removePackageParticipantsLocked(pkgList, uid);
}
}
- for (String pkgName : pkgList) {
- mTransportManager.onPackageRemoved(pkgName);
+ for (final String pkgName : pkgList) {
+ mBackupHandler.post(
+ () -> mTransportManager.onPackageRemoved(pkgName));
}
}
}
diff --git a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
index 8b4cc7f..14a008e 100644
--- a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
@@ -1188,7 +1188,7 @@
if (uri == null) {
return;
}
- String pkgName = uri.getSchemeSpecificPart();
+ final String pkgName = uri.getSchemeSpecificPart();
if (pkgName != null) {
pkgList = new String[]{pkgName};
}
@@ -1196,7 +1196,7 @@
// At package-changed we only care about looking at new transport states
if (changed) {
- String[] components =
+ final String[] components =
intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
if (MORE_DEBUG) {
@@ -1206,7 +1206,8 @@
}
}
- mTransportManager.onPackageChanged(pkgName, components);
+ mBackupHandler.post(
+ () -> mTransportManager.onPackageChanged(pkgName, components));
return; // nothing more to do in the PACKAGE_CHANGED case
}
@@ -1238,7 +1239,7 @@
}
// If they're full-backup candidates, add them there instead
final long now = System.currentTimeMillis();
- for (String packageName : pkgList) {
+ for (final String packageName : pkgList) {
try {
PackageInfo app = mPackageManager.getPackageInfo(packageName, 0);
if (AppBackupUtils.appGetsFullBackup(app)
@@ -1256,7 +1257,8 @@
writeFullBackupScheduleAsync();
}
- mTransportManager.onPackageAdded(packageName);
+ mBackupHandler.post(
+ () -> mTransportManager.onPackageAdded(packageName));
} catch (NameNotFoundException e) {
// doesn't really exist; ignore it
@@ -1280,8 +1282,9 @@
removePackageParticipantsLocked(pkgList, uid);
}
}
- for (String pkgName : pkgList) {
- mTransportManager.onPackageRemoved(pkgName);
+ for (final String pkgName : pkgList) {
+ mBackupHandler.post(
+ () -> mTransportManager.onPackageRemoved(pkgName));
}
}
}
diff --git a/services/backup/java/com/android/server/backup/TransportManager.java b/services/backup/java/com/android/server/backup/TransportManager.java
index 9aae384..7a0173f 100644
--- a/services/backup/java/com/android/server/backup/TransportManager.java
+++ b/services/backup/java/com/android/server/backup/TransportManager.java
@@ -341,9 +341,9 @@
private class TransportConnection implements ServiceConnection {
// Hold mTransportsLock to access these fields so as to provide a consistent view of them.
- private IBackupTransport mBinder;
+ private volatile IBackupTransport mBinder;
private final List<TransportReadyCallback> mListeners = new ArrayList<>();
- private String mTransportName;
+ private volatile String mTransportName;
private final ComponentName mTransportComponent;
@@ -426,25 +426,24 @@
+ rebindTimeout + "ms");
}
+ // Intentionally not synchronized -- the variable is volatile and changes to its value
+ // are inside synchronized blocks, providing a memory sync barrier; and this method
+ // does not touch any other state protected by that lock.
private IBackupTransport getBinder() {
- synchronized (mTransportLock) {
- return mBinder;
- }
+ return mBinder;
}
+ // Intentionally not synchronized; same as getBinder()
private String getName() {
- synchronized (mTransportLock) {
- return mTransportName;
- }
+ return mTransportName;
}
+ // Intentionally not synchronized; same as getBinder()
private void bindIfUnbound() {
- synchronized (mTransportLock) {
- if (mBinder == null) {
- Slog.d(TAG,
- "Rebinding to transport " + mTransportComponent.flattenToShortString());
- bindToTransport(mTransportComponent, this);
- }
+ if (mBinder == null) {
+ Slog.d(TAG,
+ "Rebinding to transport " + mTransportComponent.flattenToShortString());
+ bindToTransport(mTransportComponent, this);
}
}
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 8adc259..ba3afc3 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -1980,8 +1980,12 @@
final String[] domainStrs = domains == null ? new String[0] : domains.split(" ");
final int[] params = { sampleValidity, successThreshold, minSamples, maxSamples };
+ final boolean useTls = false;
+ final String tlsHostname = "";
+ final String[] tlsFingerprints = new String[0];
try {
- mNetdService.setResolverConfiguration(netId, servers, domainStrs, params);
+ mNetdService.setResolverConfiguration(netId, servers, domainStrs, params,
+ useTls, tlsHostname, tlsFingerprints);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java
index 39aed7c..effb86c 100644
--- a/services/core/java/com/android/server/am/ProcessStatsService.java
+++ b/services/core/java/com/android/server/am/ProcessStatsService.java
@@ -23,11 +23,14 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.service.procstats.ProcessStatsProto;
+import android.service.procstats.ProcessStatsServiceDumpProto;
import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.procstats.DumpUtils;
@@ -622,13 +625,17 @@
long ident = Binder.clearCallingIdentity();
try {
- dumpInner(fd, pw, args);
+ if (args.length > 0 && "--proto".equals(args[0])) {
+ dumpProto(fd);
+ } else {
+ dumpInner(pw, args);
+ }
} finally {
Binder.restoreCallingIdentity(ident);
}
}
- private void dumpInner(FileDescriptor fd, PrintWriter pw, String[] args) {
+ private void dumpInner(PrintWriter pw, String[] args) {
final long now = SystemClock.uptimeMillis();
boolean isCheckin = false;
@@ -1038,4 +1045,44 @@
}
}
}
+
+ private void dumpAggregatedStats(ProtoOutputStream proto, int aggregateHours, long now) {
+ ParcelFileDescriptor pfd = getStatsOverTime(aggregateHours*60*60*1000
+ - (ProcessStats.COMMIT_PERIOD/2));
+ if (pfd == null) {
+ return;
+ }
+ ProcessStats stats = new ProcessStats(false);
+ InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+ stats.read(stream);
+ if (stats.mReadError != null) {
+ return;
+ }
+ stats.toProto(proto, now);
+ }
+
+ private void dumpProto(FileDescriptor fd) {
+ final ProtoOutputStream proto = new ProtoOutputStream(fd);
+
+ // dump current procstats
+ long nowToken = proto.start(ProcessStatsServiceDumpProto.PROCSTATS_NOW);
+ long now;
+ synchronized (mAm) {
+ now = SystemClock.uptimeMillis();
+ mProcessStats.toProto(proto, now);
+ }
+ proto.end(nowToken);
+
+ // aggregated over last 3 hours procstats
+ long tokenOf3Hrs = proto.start(ProcessStatsServiceDumpProto.PROCSTATS_OVER_3HRS);
+ dumpAggregatedStats(proto, 3, now);
+ proto.end(tokenOf3Hrs);
+
+ // aggregated over last 24 hours procstats
+ long tokenOf24Hrs = proto.start(ProcessStatsServiceDumpProto.PROCSTATS_OVER_24HRS);
+ dumpAggregatedStats(proto, 24, now);
+ proto.end(tokenOf24Hrs);
+
+ proto.flush();
+ }
}
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 027dc08..ac85e6b 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -517,11 +517,14 @@
} catch (PackageManager.NameNotFoundException e) {
}
}
- if (localForegroundNoti.getSmallIcon() == null) {
+ if (localForegroundNoti.getSmallIcon() == null
+ || nm.getNotificationChannel(localPackageName, appUid,
+ localForegroundNoti.getChannelId()) == null) {
// Notifications whose icon is 0 are defined to not show
// a notification, silently ignoring it. We don't want to
// just ignore it, we want to prevent the service from
// being foreground.
+ // Also every notification needs a channel.
throw new RuntimeException("invalid service notification: "
+ foregroundNoti);
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 36f6b11..055c9f6 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -115,7 +115,18 @@
class UserController implements Handler.Callback {
private static final String TAG = TAG_WITH_CLASS_NAME ? "UserController" : TAG_AM;
- // Maximum number of users we allow to be running at a time.
+ /**
+ * Maximum number of users we allow to be running at a time, including the system user and
+ * its profiles.
+ * Note changing this to 2 is not recommended, since that would mean, if the user uses
+ * work profile and then switch to a secondary user, then the work profile user would be killed,
+ * which should work fine, but aggressively killing the work profile user that has just been
+ * running could cause data loss. (Even without work profile, witching from secondary user A
+ * to secondary user B would cause similar issues on user B.)
+ *
+ * TODO: Consider adding or replacing with "MAX_RUNNING_*SECONDARY*_USERS", which is the max
+ * number of running *secondary, switchable* users.
+ */
static final int MAX_RUNNING_USERS = 3;
// Amount of time we wait for observers to handle a user switch before
diff --git a/services/core/java/com/android/server/audio/AudioEventLogger.java b/services/core/java/com/android/server/audio/AudioEventLogger.java
index c96138f..a2c0f76 100644
--- a/services/core/java/com/android/server/audio/AudioEventLogger.java
+++ b/services/core/java/com/android/server/audio/AudioEventLogger.java
@@ -16,6 +16,8 @@
package com.android.server.audio;
+import android.util.Log;
+
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
@@ -47,6 +49,22 @@
}
/**
+ * Causes the string message for the event to appear in the verbose logcat.
+ * Here is an example of how to create a new event (a StringEvent), adding it to the logger
+ * (an instance of AudioEventLogger) while also making it show in the verbose logcat:
+ * <pre>
+ * myLogger.log(
+ * (new StringEvent("something for logcat and logger")).printLog(MyClass.TAG) );
+ * </pre>
+ * @param tag the tag for the android.util.Log.v
+ * @return the same instance of the event
+ */
+ public Event printLog(String tag) {
+ Log.v(tag, eventToString());
+ return this;
+ }
+
+ /**
* Convert event to String.
* This method is only called when the logger history is about to the dumped,
* so this method is where expensive String conversions should be made, not when the Event
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 3c1f2d4..5eb2a8d 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -751,6 +751,9 @@
// relies on audio policy having correct ranges for volume indexes.
mSafeUsbMediaVolumeIndex = getSafeUsbMediaVolumeIndex();
+ mPlaybackMonitor =
+ new PlaybackActivityMonitor(context, MAX_STREAM_VOLUME[AudioSystem.STREAM_ALARM]);
+
mMediaFocusControl = new MediaFocusControl(mContext, mPlaybackMonitor);
mRecordMonitor = new RecordingActivityMonitor(mContext);
@@ -2546,13 +2549,15 @@
}
}
int status = AudioSystem.AUDIO_STATUS_OK;
+ int actualMode;
do {
+ actualMode = mode;
if (mode == AudioSystem.MODE_NORMAL) {
// get new mode from client at top the list if any
if (!mSetModeDeathHandlers.isEmpty()) {
hdlr = mSetModeDeathHandlers.get(0);
cb = hdlr.getBinder();
- mode = hdlr.getMode();
+ actualMode = hdlr.getMode();
if (DEBUG_MODE) {
Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
+ hdlr.mPid);
@@ -2576,12 +2581,11 @@
hdlr.setMode(mode);
}
- if (mode != mMode) {
- status = AudioSystem.setPhoneState(mode);
+ if (actualMode != mMode) {
+ status = AudioSystem.setPhoneState(actualMode);
if (status == AudioSystem.AUDIO_STATUS_OK) {
- if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + mode); }
- mMode = mode;
- mModeLogger.log(new PhoneStateEvent(caller, pid, mode));
+ if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + actualMode); }
+ mMode = actualMode;
} else {
if (hdlr != null) {
mSetModeDeathHandlers.remove(hdlr);
@@ -2597,13 +2601,16 @@
} while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
if (status == AudioSystem.AUDIO_STATUS_OK) {
- if (mode != AudioSystem.MODE_NORMAL) {
+ if (actualMode != AudioSystem.MODE_NORMAL) {
if (mSetModeDeathHandlers.isEmpty()) {
Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
} else {
newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
}
}
+ // Note: newModeOwnerPid is always 0 when actualMode is MODE_NORMAL
+ mModeLogger.log(
+ new PhoneStateEvent(caller, pid, mode, newModeOwnerPid, actualMode));
int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
int device = getDeviceForStream(streamType);
int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
@@ -4154,7 +4161,8 @@
newDevice, AudioSystem.getOutputDeviceName(newDevice)));
}
synchronized (mConnectedDevices) {
- if ((newDevice & DEVICE_MEDIA_UNMUTED_ON_PLUG) != 0
+ if (mNm.getZenMode() != Settings.Global.ZEN_MODE_NO_INTERRUPTIONS
+ && (newDevice & DEVICE_MEDIA_UNMUTED_ON_PLUG) != 0
&& mStreamStates[AudioSystem.STREAM_MUSIC].mIsMuted
&& mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(newDevice) != 0
&& (newDevice & AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC)) != 0)
@@ -6972,7 +6980,7 @@
//======================
// Audio playback notification
//======================
- private final PlaybackActivityMonitor mPlaybackMonitor = new PlaybackActivityMonitor();
+ private final PlaybackActivityMonitor mPlaybackMonitor;
public void registerPlaybackCallback(IPlaybackConfigDispatcher pcdb) {
final boolean isPrivileged =
diff --git a/services/core/java/com/android/server/audio/AudioServiceEvents.java b/services/core/java/com/android/server/audio/AudioServiceEvents.java
index 634c8c2..9d9e35b 100644
--- a/services/core/java/com/android/server/audio/AudioServiceEvents.java
+++ b/services/core/java/com/android/server/audio/AudioServiceEvents.java
@@ -26,20 +26,27 @@
final static class PhoneStateEvent extends AudioEventLogger.Event {
final String mPackage;
- final int mPid;
- final int mMode;
+ final int mOwnerPid;
+ final int mRequesterPid;
+ final int mRequestedMode;
+ final int mActualMode;
- PhoneStateEvent(String callingPackage, int pid, int mode) {
+ PhoneStateEvent(String callingPackage, int requesterPid, int requestedMode,
+ int ownerPid, int actualMode) {
mPackage = callingPackage;
- mPid = pid;
- mMode = mode;
+ mRequesterPid = requesterPid;
+ mRequestedMode = requestedMode;
+ mOwnerPid = ownerPid;
+ mActualMode = actualMode;
}
@Override
public String eventToString() {
- return new StringBuilder("setMode(").append(AudioSystem.modeToString(mMode))
+ return new StringBuilder("setMode(").append(AudioSystem.modeToString(mRequestedMode))
.append(") from package=").append(mPackage)
- .append(" pid=").append(mPid).toString();
+ .append(" pid=").append(mRequesterPid)
+ .append(" selected mode=").append(AudioSystem.modeToString(mActualMode))
+ .append(" by pid=").append(mOwnerPid).toString();
}
}
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index d1a37af..6506cf7 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -17,6 +17,8 @@
package com.android.server.audio;
import android.annotation.NonNull;
+import android.content.Context;
+import android.content.pm.PackageManager;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.AudioPlaybackConfiguration;
@@ -90,7 +92,14 @@
private final HashMap<Integer, AudioPlaybackConfiguration> mPlayers =
new HashMap<Integer, AudioPlaybackConfiguration>();
- PlaybackActivityMonitor() {
+ private final Context mContext;
+ private int mSavedAlarmVolume = -1;
+ private final int mMaxAlarmVolume;
+ private int mPrivilegedAlarmActiveCount = 0;
+
+ PlaybackActivityMonitor(Context context, int maxAlarmVolume) {
+ mContext = context;
+ mMaxAlarmVolume = maxAlarmVolume;
PlayMonitorClient.sListenerDeathMonitor = this;
AudioPlaybackConfiguration.sPlayerDeathMonitor = this;
}
@@ -105,7 +114,7 @@
if (index >= 0) {
if (!disable) {
if (DEBUG) { // hidden behind DEBUG, too noisy otherwise
- mEventLogger.log(new AudioEventLogger.StringEvent("unbanning uid:" + uid));
+ sEventLogger.log(new AudioEventLogger.StringEvent("unbanning uid:" + uid));
}
mBannedUids.remove(index);
// nothing else to do, future playback requests from this uid are ok
@@ -116,7 +125,7 @@
checkBanPlayer(apc, uid);
}
if (DEBUG) { // hidden behind DEBUG, too noisy otherwise
- mEventLogger.log(new AudioEventLogger.StringEvent("banning uid:" + uid));
+ sEventLogger.log(new AudioEventLogger.StringEvent("banning uid:" + uid));
}
mBannedUids.add(new Integer(uid));
} // no else to handle, uid already not in list, so enabling again is no-op
@@ -151,7 +160,7 @@
new AudioPlaybackConfiguration(pic, newPiid,
Binder.getCallingUid(), Binder.getCallingPid());
apc.init();
- mEventLogger.log(new NewPlayerEvent(apc));
+ sEventLogger.log(new NewPlayerEvent(apc));
synchronized(mPlayerLock) {
mPlayers.put(newPiid, apc);
}
@@ -163,7 +172,7 @@
synchronized(mPlayerLock) {
final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
if (checkConfigurationCaller(piid, apc, binderUid)) {
- mEventLogger.log(new AudioAttrEvent(piid, attr));
+ sEventLogger.log(new AudioAttrEvent(piid, attr));
change = apc.handleAudioAttributesEvent(attr);
} else {
Log.e(TAG, "Error updating audio attributes");
@@ -175,6 +184,38 @@
}
}
+ private void checkVolumeForPrivilegedAlarm(AudioPlaybackConfiguration apc, int event) {
+ if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED ||
+ apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
+ if ((apc.getAudioAttributes().getAllFlags() &
+ AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0 &&
+ apc.getAudioAttributes().getUsage() == AudioAttributes.USAGE_ALARM &&
+ mContext.checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE,
+ apc.getClientPid(), apc.getClientUid()) ==
+ PackageManager.PERMISSION_GRANTED) {
+ if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED &&
+ apc.getPlayerState() != AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
+ if (mPrivilegedAlarmActiveCount++ == 0) {
+ mSavedAlarmVolume = AudioSystem.getStreamVolumeIndex(
+ AudioSystem.STREAM_ALARM, AudioSystem.DEVICE_OUT_SPEAKER);
+ AudioSystem.setStreamVolumeIndex(AudioSystem.STREAM_ALARM,
+ mMaxAlarmVolume, AudioSystem.DEVICE_OUT_SPEAKER);
+ }
+ } else if (event != AudioPlaybackConfiguration.PLAYER_STATE_STARTED &&
+ apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
+ if (--mPrivilegedAlarmActiveCount == 0) {
+ if (AudioSystem.getStreamVolumeIndex(
+ AudioSystem.STREAM_ALARM, AudioSystem.DEVICE_OUT_SPEAKER) ==
+ mMaxAlarmVolume) {
+ AudioSystem.setStreamVolumeIndex(AudioSystem.STREAM_ALARM,
+ mSavedAlarmVolume, AudioSystem.DEVICE_OUT_SPEAKER);
+ }
+ }
+ }
+ }
+ }
+ }
+
public void playerEvent(int piid, int event, int binderUid) {
if (DEBUG) { Log.v(TAG, String.format("playerEvent(piid=%d, event=%d)", piid, event)); }
final boolean change;
@@ -183,12 +224,12 @@
if (apc == null) {
return;
}
- mEventLogger.log(new PlayerEvent(piid, event));
+ sEventLogger.log(new PlayerEvent(piid, event));
if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
for (Integer uidInteger: mBannedUids) {
if (checkBanPlayer(apc, uidInteger.intValue())) {
// player was banned, do not update its state
- mEventLogger.log(new AudioEventLogger.StringEvent(
+ sEventLogger.log(new AudioEventLogger.StringEvent(
"not starting piid:" + piid + " ,is banned"));
return;
}
@@ -200,6 +241,7 @@
}
if (checkConfigurationCaller(piid, apc, binderUid)) {
//TODO add generation counter to only update to the latest state
+ checkVolumeForPrivilegedAlarm(apc, event);
change = apc.handleStateEvent(event);
} else {
Log.e(TAG, "Error handling event " + event);
@@ -216,7 +258,7 @@
public void playerHasOpPlayAudio(int piid, boolean hasOpPlayAudio, int binderUid) {
// no check on UID yet because this is only for logging at the moment
- mEventLogger.log(new PlayerOpPlayAudioEvent(piid, hasOpPlayAudio, binderUid));
+ sEventLogger.log(new PlayerOpPlayAudioEvent(piid, hasOpPlayAudio, binderUid));
}
public void releasePlayer(int piid, int binderUid) {
@@ -224,10 +266,11 @@
synchronized(mPlayerLock) {
final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
if (checkConfigurationCaller(piid, apc, binderUid)) {
- mEventLogger.log(new AudioEventLogger.StringEvent(
+ sEventLogger.log(new AudioEventLogger.StringEvent(
"releasing player piid:" + piid));
mPlayers.remove(new Integer(piid));
mDuckingManager.removeReleased(apc);
+ checkVolumeForPrivilegedAlarm(apc, AudioPlaybackConfiguration.PLAYER_STATE_RELEASED);
apc.handleStateEvent(AudioPlaybackConfiguration.PLAYER_STATE_RELEASED);
}
}
@@ -278,7 +321,7 @@
}
pw.println("\n");
// log
- mEventLogger.dump(pw);
+ sEventLogger.dump(pw);
}
}
@@ -456,7 +499,8 @@
}
if (mute) {
try {
- Log.v(TAG, "call: muting player" + piid + " uid:" + apc.getClientUid());
+ sEventLogger.log((new AudioEventLogger.StringEvent("call: muting piid:"
+ + piid + " uid:" + apc.getClientUid())).printLog(TAG));
apc.getPlayerProxy().setVolume(0.0f);
mMutedPlayers.add(new Integer(piid));
} catch (Exception e) {
@@ -480,7 +524,8 @@
final AudioPlaybackConfiguration apc = mPlayers.get(piid);
if (apc != null) {
try {
- Log.v(TAG, "call: unmuting player" + piid + " uid:" + apc.getClientUid());
+ sEventLogger.log(new AudioEventLogger.StringEvent("call: unmuting piid:"
+ + piid).printLog(TAG));
apc.getPlayerProxy().setVolume(1.0f);
} catch (Exception e) {
Log.e(TAG, "call: error unmuting player " + piid + " uid:"
@@ -669,8 +714,7 @@
return;
}
try {
- Log.v(TAG, "ducking (skipRamp=" + skipRamp + ") player piid:"
- + apc.getPlayerInterfaceId() + " uid:" + mUid);
+ sEventLogger.log((new DuckEvent(apc, skipRamp)).printLog(TAG));
apc.getPlayerProxy().applyVolumeShaper(
DUCK_VSHAPE,
skipRamp ? PLAY_SKIP_RAMP : PLAY_CREATE_IF_NEEDED);
@@ -685,7 +729,8 @@
final AudioPlaybackConfiguration apc = players.get(piid);
if (apc != null) {
try {
- Log.v(TAG, "unducking player " + piid + " uid:" + mUid);
+ sEventLogger.log((new AudioEventLogger.StringEvent("unducking piid:"
+ + piid)).printLog(TAG));
apc.getPlayerProxy().applyVolumeShaper(
DUCK_ID,
VolumeShaper.Operation.REVERSE);
@@ -772,7 +817,28 @@
}
}
- private final static class AudioAttrEvent extends AudioEventLogger.Event {
+ private static final class DuckEvent extends AudioEventLogger.Event {
+ private final int mPlayerIId;
+ private final boolean mSkipRamp;
+ private final int mClientUid;
+ private final int mClientPid;
+
+ DuckEvent(@NonNull AudioPlaybackConfiguration apc, boolean skipRamp) {
+ mPlayerIId = apc.getPlayerInterfaceId();
+ mSkipRamp = skipRamp;
+ mClientUid = apc.getClientUid();
+ mClientPid = apc.getClientPid();
+ }
+
+ @Override
+ public String eventToString() {
+ return new StringBuilder("ducking player piid:").append(mPlayerIId)
+ .append(" uid/pid:").append(mClientUid).append("/").append(mClientPid)
+ .append(" skip ramp:").append(mSkipRamp).toString();
+ }
+ }
+
+ private static final class AudioAttrEvent extends AudioEventLogger.Event {
private final int mPlayerIId;
private final AudioAttributes mPlayerAttr;
@@ -787,6 +853,6 @@
}
}
- private final AudioEventLogger mEventLogger = new AudioEventLogger(100,
+ private static final AudioEventLogger sEventLogger = new AudioEventLogger(100,
"playback activity as reported through PlayerBase");
}
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index ac80794..78aa2f9 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -795,18 +795,22 @@
* @param uid Uid to check against for removal of a job.
*
*/
- public void cancelJobsForUid(int uid, String reason) {
+ public boolean cancelJobsForUid(int uid, String reason) {
if (uid == Process.SYSTEM_UID) {
Slog.wtfStack(TAG, "Can't cancel all jobs for system uid");
- return;
+ return false;
}
+
+ boolean jobsCanceled = false;
synchronized (mLock) {
final List<JobStatus> jobsForUid = mJobs.getJobsByUid(uid);
for (int i=0; i<jobsForUid.size(); i++) {
JobStatus toRemove = jobsForUid.get(i);
cancelJobImplLocked(toRemove, null, reason);
+ jobsCanceled = true;
}
}
+ return jobsCanceled;
}
/**
@@ -816,13 +820,14 @@
* @param uid Uid of the calling client.
* @param jobId Id of the job, provided at schedule-time.
*/
- public void cancelJob(int uid, int jobId) {
+ public boolean cancelJob(int uid, int jobId) {
JobStatus toCancel;
synchronized (mLock) {
toCancel = mJobs.getJobByUidAndJobId(uid, jobId);
if (toCancel != null) {
cancelJobImplLocked(toCancel, null, "cancel() called by app");
}
+ return (toCancel != null);
}
}
@@ -2147,6 +2152,39 @@
return 0;
}
+ // Shell command infrastructure: cancel a scheduled job
+ int executeCancelCommand(PrintWriter pw, String pkgName, int userId,
+ boolean hasJobId, int jobId) {
+ if (DEBUG) {
+ Slog.v(TAG, "executeCancelCommand(): " + pkgName + "/" + userId + " " + jobId);
+ }
+
+ int pkgUid = -1;
+ try {
+ IPackageManager pm = AppGlobals.getPackageManager();
+ pkgUid = pm.getPackageUid(pkgName, 0, userId);
+ } catch (RemoteException e) { /* can't happen */ }
+
+ if (pkgUid < 0) {
+ pw.println("Package " + pkgName + " not found.");
+ return JobSchedulerShellCommand.CMD_ERR_NO_PACKAGE;
+ }
+
+ if (!hasJobId) {
+ pw.println("Canceling all jobs for " + pkgName + " in user " + userId);
+ if (!cancelJobsForUid(pkgUid, "cancel shell command for package")) {
+ pw.println("No matching jobs found.");
+ }
+ } else {
+ pw.println("Canceling job " + pkgName + "/#" + jobId + " in user " + userId);
+ if (!cancelJob(pkgUid, jobId)) {
+ pw.println("No matching job found.");
+ }
+ }
+
+ return 0;
+ }
+
void setMonitorBattery(boolean enabled) {
synchronized (mLock) {
if (mBatteryController != null) {
diff --git a/services/core/java/com/android/server/job/JobSchedulerShellCommand.java b/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
index a53c088..d630aab 100644
--- a/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
+++ b/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
@@ -48,6 +48,8 @@
return runJob(pw);
case "timeout":
return timeout(pw);
+ case "cancel":
+ return cancelJob(pw);
case "monitor-battery":
return monitorBattery(pw);
case "get-battery-seq":
@@ -205,6 +207,42 @@
}
}
+ private int cancelJob(PrintWriter pw) throws Exception {
+ checkPermission("cancel jobs");
+
+ int userId = UserHandle.USER_SYSTEM;
+
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case "-u":
+ case "--user":
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ break;
+
+ default:
+ pw.println("Error: unknown option '" + opt + "'");
+ return -1;
+ }
+ }
+
+ if (userId < 0) {
+ pw.println("Error: must specify a concrete user ID");
+ return -1;
+ }
+
+ final String pkgName = getNextArg();
+ final String jobIdStr = getNextArg();
+ final int jobId = jobIdStr != null ? Integer.parseInt(jobIdStr) : -1;
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return mInternal.executeCancelCommand(pw, pkgName, userId, jobIdStr != null, jobId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
private int monitorBattery(PrintWriter pw) throws Exception {
checkPermission("change battery monitoring");
String opt = getNextArgRequired();
@@ -315,6 +353,12 @@
pw.println(" Options:");
pw.println(" -u or --user: specify which user's job is to be run; the default is");
pw.println(" all users");
+ pw.println(" cancel [-u | --user USER_ID] PACKAGE [JOB_ID]");
+ pw.println(" Cancel a scheduled job. If a job ID is not supplied, all jobs scheduled");
+ pw.println(" by that package will be canceled. USE WITH CAUTION.");
+ pw.println(" Options:");
+ pw.println(" -u or --user: specify which user's job is to be run; the default is");
+ pw.println(" the primary or system user");
pw.println(" monitor-battery [on|off]");
pw.println(" Control monitoring of all battery changes. Off by default. Turning");
pw.println(" on makes get-battery-seq useful.");
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 90dab2c..b4056b3 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -331,7 +331,6 @@
private static final int MSG_UPDATE_INTERFACE_QUOTA = 10;
private static final int MSG_REMOVE_INTERFACE_QUOTA = 11;
private static final int MSG_POLICIES_CHANGED = 13;
- private static final int MSG_SET_FIREWALL_RULES = 14;
private static final int MSG_RESET_FIREWALL_RULES_BY_UID = 15;
private static final int UID_MSG_STATE_CHANGED = 100;
@@ -3138,9 +3137,9 @@
uidRules.put(mUidState.keyAt(i), FIREWALL_RULE_ALLOW);
}
}
- setUidFirewallRulesAsync(chain, uidRules, CHAIN_TOGGLE_ENABLE);
+ setUidFirewallRulesUL(chain, uidRules, CHAIN_TOGGLE_ENABLE);
} else {
- setUidFirewallRulesAsync(chain, null, CHAIN_TOGGLE_DISABLE);
+ setUidFirewallRulesUL(chain, null, CHAIN_TOGGLE_DISABLE);
}
}
@@ -3207,7 +3206,7 @@
}
}
- setUidFirewallRulesAsync(FIREWALL_CHAIN_STANDBY, uidRules, CHAIN_TOGGLE_NONE);
+ setUidFirewallRulesUL(FIREWALL_CHAIN_STANDBY, uidRules, CHAIN_TOGGLE_NONE);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
}
@@ -3906,18 +3905,6 @@
removeInterfaceQuota((String) msg.obj);
return true;
}
- case MSG_SET_FIREWALL_RULES: {
- final int chain = msg.arg1;
- final int toggle = msg.arg2;
- final SparseIntArray uidRules = (SparseIntArray) msg.obj;
- if (uidRules != null) {
- setUidFirewallRules(chain, uidRules);
- }
- if (toggle != CHAIN_TOGGLE_NONE) {
- enableFirewallChainUL(chain, toggle == CHAIN_TOGGLE_ENABLE);
- }
- return true;
- }
case MSG_RESET_FIREWALL_RULES_BY_UID: {
resetUidFirewallRules(msg.arg1);
return true;
@@ -4063,15 +4050,20 @@
/**
* Calls {@link #setUidFirewallRules(int, SparseIntArray)} and
- * {@link #enableFirewallChainUL(int, boolean)} asynchronously.
+ * {@link #enableFirewallChainUL(int, boolean)} synchronously.
*
* @param chain firewall chain.
* @param uidRules new UID rules; if {@code null}, only toggles chain state.
* @param toggle whether the chain should be enabled, disabled, or not changed.
*/
- private void setUidFirewallRulesAsync(int chain, @Nullable SparseIntArray uidRules,
+ private void setUidFirewallRulesUL(int chain, @Nullable SparseIntArray uidRules,
@ChainToggleType int toggle) {
- mHandler.obtainMessage(MSG_SET_FIREWALL_RULES, chain, toggle, uidRules).sendToTarget();
+ if (uidRules != null) {
+ setUidFirewallRulesUL(chain, uidRules);
+ }
+ if (toggle != CHAIN_TOGGLE_NONE) {
+ enableFirewallChainUL(chain, toggle == CHAIN_TOGGLE_ENABLE);
+ }
}
/**
@@ -4079,7 +4071,7 @@
* here to netd. It will clean up dead rules and make sure the target chain only contains rules
* specified here.
*/
- private void setUidFirewallRules(int chain, SparseIntArray uidRules) {
+ private void setUidFirewallRulesUL(int chain, SparseIntArray uidRules) {
try {
int size = uidRules.size();
int[] uids = new int[size];
diff --git a/services/core/java/com/android/server/notification/NotificationManagerInternal.java b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
index 4923b06..f1476b3 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerInternal.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
@@ -17,8 +17,10 @@
package com.android.server.notification;
import android.app.Notification;
+import android.app.NotificationChannel;
public interface NotificationManagerInternal {
+ NotificationChannel getNotificationChannel(String pkg, int uid, String channelId);
void enqueueNotification(String pkg, String basePkg, int callingUid, int callingPid,
String tag, int id, Notification notification, int userId);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 6e84dd2..4cb5d0f 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -3286,6 +3286,10 @@
long conditionsToken = proto.start(NotificationServiceDumpProto.CONDITION_PROVIDERS);
mConditionProviders.dump(proto, filter);
proto.end(conditionsToken);
+
+ long rankingToken = proto.start(NotificationServiceDumpProto.RANKING_CONFIG);
+ mRankingHelper.dump(proto, filter);
+ proto.end(rankingToken);
}
proto.flush();
@@ -3441,6 +3445,12 @@
*/
private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
@Override
+ public NotificationChannel getNotificationChannel(String pkg, int uid, String
+ channelId) {
+ return mRankingHelper.getNotificationChannel(pkg, uid, channelId, false);
+ }
+
+ @Override
public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
String tag, int id, Notification notification, int userId) {
enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
@@ -3807,6 +3817,8 @@
MetricsLogger.action(r.getLogMaker()
.setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
.setType(MetricsEvent.TYPE_CLOSE)
+ .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS,
+ mDuration)
.addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
mSnoozeCriterionId == null ? 0 : 1));
boolean wasPosted = removeFromNotificationListsLocked(r);
@@ -5828,10 +5840,9 @@
final DumpFilter filter = new DumpFilter();
for (int ai = 0; ai < args.length; ai++) {
final String a = args[ai];
- if ("--proto".equals(args[0])) {
+ if ("--proto".equals(a)) {
filter.proto = true;
- }
- if ("--noredact".equals(a) || "--reveal".equals(a)) {
+ } else if ("--noredact".equals(a) || "--reveal".equals(a)) {
filter.redact = false;
} else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
if (ai < args.length-1) {
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index fea2464..8783f47 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -36,10 +36,13 @@
import android.os.UserHandle;
import android.provider.Settings.Secure;
import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.RankingHelperProto;
+import android.service.notification.RankingHelperProto.RecordProto;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Slog;
import android.util.SparseBooleanArray;
+import android.util.proto.ProtoOutputStream;
import org.json.JSONArray;
import org.json.JSONException;
@@ -915,8 +918,7 @@
pw.print(" ");
pw.println(mSignalExtractors[i]);
}
- }
- if (filter == null) {
+
pw.print(prefix);
pw.println("per-package config:");
}
@@ -928,6 +930,52 @@
dumpRecords(pw, prefix, filter, mRestoredWithoutUids);
}
+ public void dump(ProtoOutputStream proto, NotificationManagerService.DumpFilter filter) {
+ final int N = mSignalExtractors.length;
+ for (int i = 0; i < N; i++) {
+ proto.write(RankingHelperProto.NOTIFICATION_SIGNAL_EXTRACTORS,
+ mSignalExtractors[i].getClass().getSimpleName());
+ }
+ synchronized (mRecords) {
+ dumpRecords(proto, RankingHelperProto.RECORDS, filter, mRecords);
+ }
+ dumpRecords(proto, RankingHelperProto.RECORDS_RESTORED_WITHOUT_UID, filter,
+ mRestoredWithoutUids);
+ }
+
+ private static void dumpRecords(ProtoOutputStream proto, long fieldId,
+ NotificationManagerService.DumpFilter filter, ArrayMap<String, Record> records) {
+ final int N = records.size();
+ long fToken;
+ for (int i = 0; i < N; i++) {
+ final Record r = records.valueAt(i);
+ if (filter == null || filter.matches(r.pkg)) {
+ fToken = proto.start(fieldId);
+
+ proto.write(RecordProto.PACKAGE, r.pkg);
+ proto.write(RecordProto.UID, r.uid);
+ proto.write(RecordProto.IMPORTANCE, r.importance);
+ proto.write(RecordProto.PRIORITY, r.priority);
+ proto.write(RecordProto.VISIBILITY, r.visibility);
+ proto.write(RecordProto.SHOW_BADGE, r.showBadge);
+
+ long token;
+ for (NotificationChannel channel : r.channels.values()) {
+ token = proto.start(RecordProto.CHANNELS);
+ channel.toProto(proto);
+ proto.end(token);
+ }
+ for (NotificationChannelGroup group : r.groups.values()) {
+ token = proto.start(RecordProto.CHANNEL_GROUPS);
+ group.toProto(proto);
+ proto.end(token);
+ }
+
+ proto.end(fToken);
+ }
+ }
+ }
+
private static void dumpRecords(PrintWriter pw, String prefix,
NotificationManagerService.DumpFilter filter, ArrayMap<String, Record> records) {
final int N = records.size();
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 6f70f4c..9309f18 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -1186,9 +1186,7 @@
final int size = shortcuts.size();
for (int i = 0; i < size; i++) {
final ShortcutInfo si = shortcuts.valueAt(i);
- pw.print(prefix);
- pw.print(" ");
- pw.println(si.toInsecureString());
+ pw.println(si.toDumpString(prefix + " "));
if (si.getBitmapPath() != null) {
final long len = new File(si.getBitmapPath()).length();
pw.print(prefix);
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 1a62662..05fd248 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -30,8 +30,12 @@
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.KernelWakelockReader;
+import com.android.internal.os.KernelWakelockStats;
import com.android.server.SystemService;
+import java.util.Map;
+
/**
* Helper service for statsd (the native stats management service in cmds/statsd/).
* Used for registering and receiving alarms on behalf of statsd.
@@ -157,7 +161,44 @@
}
}
- @Override
+ // These values must be kept in sync with cmd/statsd/StatsPuller.h.
+ // TODO: pull the constant from stats_events.proto instead
+ private static final int PULL_CODE_KERNEL_WAKELOCKS = 20;
+
+ private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader();
+ private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats();
+
+ @Override // Binder call
+ public String pullData(int pullCode) {
+ enforceCallingPermission();
+ if (DEBUG) Slog.d(TAG, "Fetching " + pullCode);
+
+ StringBuilder s = new StringBuilder(); // TODO: use and return a Parcel instead of a string
+ switch (pullCode) {
+ case PULL_CODE_KERNEL_WAKELOCKS:
+ final KernelWakelockStats wakelockStats =
+ mKernelWakelockReader.readKernelWakelockStats(mTmpWakelockStats);
+
+ for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) {
+ String name = ent.getKey();
+ KernelWakelockStats.Entry kws = ent.getValue();
+ s.append("Wakelock ")
+ .append(name)
+ .append(", time=")
+ .append(kws.mTotalTime)
+ .append(", count=")
+ .append(kws.mCount)
+ .append('\n');
+ }
+ break;
+ default:
+ Slog.w(TAG, "No such pollable data as " + pullCode);
+ return null;
+ }
+ return s.toString();
+ }
+
+ @Override // Binder call
public void statsdReady() {
enforceCallingPermission();
if (DEBUG) Slog.d(TAG, "learned that statsdReady");
diff --git a/services/core/java/com/android/server/vr/Vr2dDisplay.java b/services/core/java/com/android/server/vr/Vr2dDisplay.java
index 8f50a39..5721415 100644
--- a/services/core/java/com/android/server/vr/Vr2dDisplay.java
+++ b/services/core/java/com/android/server/vr/Vr2dDisplay.java
@@ -294,6 +294,8 @@
int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH;
flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT;
+ flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
+ flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
mVirtualDisplay = mDisplayManager.createVirtualDisplay(null /* projection */,
DISPLAY_NAME, mVirtualDisplayWidth, mVirtualDisplayHeight, mVirtualDisplayDpi,
null /* surface */, flags, null /* callback */, null /* handler */,
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 91cce31..bdf46c7 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -18,6 +18,7 @@
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 4308ff9..6527883 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -923,7 +923,9 @@
void resetAnimationBackgroundAnimator() {
mAnimationBackgroundAnimator = null;
- mAnimationBackgroundSurface.hide();
+ if (mAnimationBackgroundSurface != null) {
+ mAnimationBackgroundSurface.hide();
+ }
}
void setAnimationBackground(WindowStateAnimator winAnimator, int color) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 6c859f7..7830623 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -5350,7 +5350,7 @@
}
}
- private void forceWipeUser(int userId) {
+ private void forceWipeUser(int userId, String wipeReasonForUser) {
try {
IActivityManager am = mInjector.getIActivityManager();
if (am.getCurrentUser().id == userId) {
@@ -5361,7 +5361,7 @@
if (!userRemoved) {
Slog.w(LOG_TAG, "Couldn't remove user " + userId);
} else if (isManagedProfile(userId)) {
- sendWipeProfileNotification();
+ sendWipeProfileNotification(wipeReasonForUser);
}
} catch (RemoteException re) {
// Shouldn't happen
@@ -5369,23 +5369,26 @@
}
@Override
- public void wipeData(int flags) {
+ public void wipeDataWithReason(int flags, String wipeReasonForUser) {
if (!mHasFeature) {
return;
}
+ Preconditions.checkStringNotEmpty(wipeReasonForUser, "wipeReasonForUser is null or empty");
enforceFullCrossUsersPermission(mInjector.userHandleGetCallingUserId());
final ActiveAdmin admin;
synchronized (this) {
admin = getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_WIPE_DATA);
}
- String reason = "DevicePolicyManager.wipeData() from "
+ String internalReason = "DevicePolicyManager.wipeDataWithReason() from "
+ admin.info.getComponent().flattenToShortString();
wipeDataNoLock(
- admin.info.getComponent(), flags, reason, admin.getUserHandle().getIdentifier());
+ admin.info.getComponent(), flags, internalReason, wipeReasonForUser,
+ admin.getUserHandle().getIdentifier());
}
- private void wipeDataNoLock(ComponentName admin, int flags, String reason, int userId) {
+ private void wipeDataNoLock(ComponentName admin, int flags, String internalReason,
+ String wipeReasonForUser, int userId) {
wtfIfInLock();
long ident = mInjector.binderClearCallingIdentity();
@@ -5420,25 +5423,26 @@
// (rather than system), we should probably trigger factory reset. Current code just
// removes that user (but still clears FRP...)
if (userId == UserHandle.USER_SYSTEM) {
- forceWipeDeviceNoLock(/*wipeExtRequested=*/ (flags & WIPE_EXTERNAL_STORAGE) != 0,
- reason, /*wipeEuicc=*/ (flags & WIPE_EUICC) != 0);
+ forceWipeDeviceNoLock(/*wipeExtRequested=*/ (
+ flags & WIPE_EXTERNAL_STORAGE) != 0,
+ internalReason,
+ /*wipeEuicc=*/ (flags & WIPE_EUICC) != 0);
} else {
- forceWipeUser(userId);
+ forceWipeUser(userId, wipeReasonForUser);
}
} finally {
mInjector.binderRestoreCallingIdentity(ident);
}
}
- private void sendWipeProfileNotification() {
- String contentText = mContext.getString(R.string.work_profile_deleted_description_dpm_wipe);
+ private void sendWipeProfileNotification(String wipeReasonForUser) {
Notification notification =
new Notification.Builder(mContext, SystemNotificationChannels.DEVICE_ADMIN)
.setSmallIcon(android.R.drawable.stat_sys_warning)
.setContentTitle(mContext.getString(R.string.work_profile_deleted))
- .setContentText(contentText)
+ .setContentText(wipeReasonForUser)
.setColor(mContext.getColor(R.color.system_notification_accent_color))
- .setStyle(new Notification.BigTextStyle().bigText(contentText))
+ .setStyle(new Notification.BigTextStyle().bigText(wipeReasonForUser))
.build();
mInjector.getNotificationManager().notify(SystemMessage.NOTE_PROFILE_WIPED, notification);
}
@@ -5610,9 +5614,12 @@
// able to do so).
// IMPORTANT: Call without holding the lock to prevent deadlock.
try {
+ String wipeReasonForUser = mContext.getString(
+ R.string.work_profile_deleted_reason_maximum_password_failure);
wipeDataNoLock(strictestAdmin.info.getComponent(),
/*flags=*/ 0,
/*reason=*/ "reportFailedPasswordAttempt()",
+ wipeReasonForUser,
userId);
} catch (SecurityException e) {
Slog.w(LOG_TAG, "Failed to wipe user " + userId
@@ -5621,7 +5628,8 @@
}
if (mInjector.securityLogIsLoggingEnabled()) {
- SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT, /*result*/ 0,
+ SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT,
+ /*result*/ 0,
/*method strength*/ 1);
}
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index d7ec7b6..92cbd3d 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -668,9 +668,11 @@
traceEnd();
// Tracks whether the updatable WebView is in a ready state and watches for update installs.
- traceBeginAndSlog("StartWebViewUpdateService");
- mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class);
- traceEnd();
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) {
+ traceBeginAndSlog("StartWebViewUpdateService");
+ mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class);
+ traceEnd();
+ }
}
/**
@@ -1091,6 +1093,14 @@
traceBeginAndSlog("StartWifiRtt");
mSystemServiceManager.startService("com.android.server.wifi.RttService");
traceEnd();
+
+ if (context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_WIFI_RTT)) {
+ traceBeginAndSlog("StartRttService");
+ mSystemServiceManager.startService(
+ "com.android.server.wifi.rtt.RttService");
+ traceEnd();
+ }
}
if (context.getPackageManager().hasSystemFeature(
@@ -1098,8 +1108,6 @@
traceBeginAndSlog("StartWifiAware");
mSystemServiceManager.startService(WIFI_AWARE_SERVICE_CLASS);
traceEnd();
- } else {
- Slog.i(TAG, "No Wi-Fi Aware Service (Aware support Not Present)");
}
if (context.getPackageManager().hasSystemFeature(
@@ -1687,10 +1695,10 @@
traceEnd();
// No dependency on Webview preparation in system server. But this should
- // be completed before allowring 3rd party
+ // be completed before allowing 3rd party
final String WEBVIEW_PREPARATION = "WebViewFactoryPreparation";
Future<?> webviewPrep = null;
- if (!mOnlyCore) {
+ if (!mOnlyCore && mWebViewUpdateService != null) {
webviewPrep = SystemServerInitThreadPool.get().submit(() -> {
Slog.i(TAG, WEBVIEW_PREPARATION);
TimingsTraceLog traceLog = new TimingsTraceLog(
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 87b0db8..a8bf8f1 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -3421,6 +3421,9 @@
// Even if the caller is the managed profile, the current user is the user 0
when(getServices().iactivityManager.getCurrentUser())
.thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
+ // Get mock reason string since we throw an IAE with empty string input.
+ when(mContext.getResources().getString(R.string.work_profile_deleted_description_dpm_wipe)).
+ thenReturn("Just a test string.");
dpm.wipeData(0);
verify(getServices().userManagerInternal).removeUserEvenWhenDisallowed(
@@ -3440,6 +3443,9 @@
UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
UserHandle.of(MANAGED_PROFILE_USER_ID)))
.thenReturn(UserManager.RESTRICTION_SOURCE_SYSTEM);
+ when(mContext.getResources().getString(R.string.work_profile_deleted_description_dpm_wipe)).
+ thenReturn("Just a test string.");
+
mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
// The PO is not allowed to remove the profile if the user restriction was set on the
// profile by the system
@@ -3453,6 +3459,8 @@
UserManager.DISALLOW_FACTORY_RESET,
UserHandle.SYSTEM))
.thenReturn(UserManager.RESTRICTION_SOURCE_DEVICE_OWNER);
+ when(mContext.getResources().getString(R.string.work_profile_deleted_description_dpm_wipe)).
+ thenReturn("Just a test string.");
dpm.wipeData(0);
verify(getServices().recoverySystem).rebootWipeUserData(
@@ -3466,6 +3474,8 @@
UserManager.DISALLOW_FACTORY_RESET,
UserHandle.SYSTEM))
.thenReturn(UserManager.RESTRICTION_SOURCE_DEVICE_OWNER);
+ when(mContext.getResources().getString(R.string.work_profile_deleted_description_dpm_wipe)).
+ thenReturn("Just a test string.");
dpm.wipeData(WIPE_EUICC);
verify(getServices().recoverySystem).rebootWipeUserData(
@@ -3479,6 +3489,8 @@
UserManager.DISALLOW_FACTORY_RESET,
UserHandle.SYSTEM))
.thenReturn(UserManager.RESTRICTION_SOURCE_SYSTEM);
+ when(mContext.getResources().getString(R.string.work_profile_deleted_description_dpm_wipe)).
+ thenReturn("Just a test string.");
// The DO is not allowed to wipe the device if the user restriction was set
// by the system
assertExpectException(SecurityException.class, /* messageRegex= */ null,
diff --git a/telephony/java/android/telephony/MbmsDownloadSession.java b/telephony/java/android/telephony/MbmsDownloadSession.java
index ebac041..764b7b2 100644
--- a/telephony/java/android/telephony/MbmsDownloadSession.java
+++ b/telephony/java/android/telephony/MbmsDownloadSession.java
@@ -522,8 +522,7 @@
* @param handler The {@link Handler} on which calls to {@code callback} should be enqueued on.
*/
public void registerStateCallback(@NonNull DownloadRequest request,
- @NonNull DownloadStateCallback callback,
- @NonNull Handler handler) {
+ @NonNull DownloadStateCallback callback, @NonNull Handler handler) {
IMbmsDownloadService downloadService = mService.get();
if (downloadService == null) {
throw new IllegalStateException("Middleware not yet bound");
@@ -533,7 +532,8 @@
new InternalDownloadStateCallback(callback, handler);
try {
- int result = downloadService.registerStateCallback(request, internalCallback);
+ int result = downloadService.registerStateCallback(request, internalCallback,
+ callback.getCallbackFilterFlags());
if (result != MbmsErrors.SUCCESS) {
if (result == MbmsErrors.DownloadErrors.ERROR_UNKNOWN_DOWNLOAD_REQUEST) {
throw new IllegalArgumentException("Unknown download request.");
diff --git a/telephony/java/android/telephony/mbms/DownloadStateCallback.java b/telephony/java/android/telephony/mbms/DownloadStateCallback.java
index 86920bd..892fbf0 100644
--- a/telephony/java/android/telephony/mbms/DownloadStateCallback.java
+++ b/telephony/java/android/telephony/mbms/DownloadStateCallback.java
@@ -16,8 +16,12 @@
package android.telephony.mbms;
+import android.annotation.IntDef;
import android.telephony.MbmsDownloadSession;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* A optional listener class used by download clients to track progress. Apps should extend this
* class and pass an instance into
@@ -29,6 +33,71 @@
public class DownloadStateCallback {
/**
+ * Bitmask flags used for filtering out callback methods. Used when constructing the
+ * DownloadStateCallback as an optional parameter.
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({ALL_UPDATES, PROGRESS_UPDATES, STATE_UPDATES})
+ public @interface FilterFlag {}
+
+ /**
+ * Receive all callbacks.
+ * Default value.
+ */
+ public static final int ALL_UPDATES = 0x00;
+ /**
+ * Receive callbacks for {@link #onProgressUpdated}.
+ */
+ public static final int PROGRESS_UPDATES = 0x01;
+ /**
+ * Receive callbacks for {@link #onStateUpdated}.
+ */
+ public static final int STATE_UPDATES = 0x02;
+
+ private final int mCallbackFilterFlags;
+
+ /**
+ * Creates a DownloadStateCallback that will receive all callbacks.
+ */
+ public DownloadStateCallback() {
+ mCallbackFilterFlags = ALL_UPDATES;
+ }
+
+ /**
+ * Creates a DownloadStateCallback that will only receive callbacks for the methods specified
+ * via the filterFlags parameter.
+ * @param filterFlags A bitmask of filter flags that will specify which callback this instance
+ * is interested in.
+ */
+ public DownloadStateCallback(int filterFlags) {
+ mCallbackFilterFlags = filterFlags;
+ }
+
+ /**
+ * Return the currently set filter flags.
+ * @return An integer containing the bitmask of flags that this instance is interested in.
+ * @hide
+ */
+ public int getCallbackFilterFlags() {
+ return mCallbackFilterFlags;
+ }
+
+ /**
+ * Returns true if a filter flag is set for a particular callback method. If the flag is set,
+ * the callback will be delivered to the listening process.
+ * @param flag A filter flag specifying whether or not a callback method is registered to
+ * receive callbacks.
+ * @return true if registered to receive callbacks in the listening process, false if not.
+ */
+ public final boolean isFilterFlagSet(@FilterFlag int flag) {
+ if (mCallbackFilterFlags == ALL_UPDATES) {
+ return true;
+ }
+ return (mCallbackFilterFlags & flag) > 0;
+ }
+
+ /**
* Called when the middleware wants to report progress for a file in a {@link DownloadRequest}.
*
* @param request a {@link DownloadRequest}, indicating which download is being referenced.
diff --git a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
index 61415b5..fe27537 100644
--- a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
+++ b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
@@ -165,6 +165,12 @@
Log.w(LOG_TAG, "Download result did not include a result code. Ignoring.");
return false;
}
+ // We do not need to verify below extras if the result is not success.
+ if (MbmsDownloadSession.RESULT_SUCCESSFUL !=
+ intent.getIntExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_RESULT,
+ MbmsDownloadSession.RESULT_CANCELLED)) {
+ return true;
+ }
if (!intent.hasExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST)) {
Log.w(LOG_TAG, "Download result did not include the associated request. Ignoring.");
return false;
diff --git a/telephony/java/android/telephony/mbms/ServiceInfo.java b/telephony/java/android/telephony/mbms/ServiceInfo.java
index 9a01ed0..8529f52 100644
--- a/telephony/java/android/telephony/mbms/ServiceInfo.java
+++ b/telephony/java/android/telephony/mbms/ServiceInfo.java
@@ -23,6 +23,7 @@
import android.text.TextUtils;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
@@ -62,12 +63,6 @@
throw new RuntimeException("bad locales length " + newLocales.size());
}
- for (Locale l : newLocales) {
- if (!newNames.containsKey(l)) {
- throw new IllegalArgumentException("A name must be provided for each locale");
- }
- }
-
names = new HashMap(newNames.size());
names.putAll(newNames);
className = newClassName;
@@ -127,7 +122,7 @@
* Get the user-displayable name for this cell-broadcast service corresponding to the
* provided {@link Locale}.
* @param locale The {@link Locale} in which you want the name of the service. This must be a
- * value from the list returned by {@link #getLocales()} -- an
+ * value from the set returned by {@link #getNamedContentLocales()} -- an
* {@link java.util.NoSuchElementException} may be thrown otherwise.
* @return The {@link CharSequence} providing the name of the service in the given
* {@link Locale}
@@ -140,6 +135,17 @@
}
/**
+ * Return an unmodifiable set of the current {@link Locale}s that have a user-displayable name
+ * associated with them. The user-displayable name associated with any {@link Locale} in this
+ * set can be retrieved with {@link #getNameForLocale(Locale)}.
+ * @return An unmodifiable set of {@link Locale} objects corresponding to a user-displayable
+ * content name in that locale.
+ */
+ public @NonNull Set<Locale> getNamedContentLocales() {
+ return Collections.unmodifiableSet(names.keySet());
+ }
+
+ /**
* The class name for this service - used to categorize and filter
*/
public String getServiceClassName() {
diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl
index ed5e826..cb93542 100755
--- a/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl
+++ b/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl
@@ -36,7 +36,8 @@
int download(in DownloadRequest downloadRequest);
- int registerStateCallback(in DownloadRequest downloadRequest, IDownloadStateCallback listener);
+ int registerStateCallback(in DownloadRequest downloadRequest, IDownloadStateCallback listener,
+ int flags);
int unregisterStateCallback(in DownloadRequest downloadRequest,
IDownloadStateCallback listener);
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
index d845a57..2f85a1d 100644
--- a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
@@ -46,6 +46,47 @@
private final Map<IBinder, DownloadStateCallback> mDownloadCallbackBinderMap = new HashMap<>();
private final Map<IBinder, DeathRecipient> mDownloadCallbackDeathRecipients = new HashMap<>();
+
+ // Filters the DownloadStateCallbacks by its configuration from the app.
+ private abstract static class FilteredDownloadStateCallback extends DownloadStateCallback {
+
+ private final IDownloadStateCallback mCallback;
+ public FilteredDownloadStateCallback(IDownloadStateCallback callback, int callbackFlags) {
+ super(callbackFlags);
+ mCallback = callback;
+ }
+
+ @Override
+ public void onProgressUpdated(DownloadRequest request, FileInfo fileInfo,
+ int currentDownloadSize, int fullDownloadSize, int currentDecodedSize,
+ int fullDecodedSize) {
+ if (!isFilterFlagSet(PROGRESS_UPDATES)) {
+ return;
+ }
+ try {
+ mCallback.onProgressUpdated(request, fileInfo, currentDownloadSize,
+ fullDownloadSize, currentDecodedSize, fullDecodedSize);
+ } catch (RemoteException e) {
+ onRemoteException(e);
+ }
+ }
+
+ @Override
+ public void onStateUpdated(DownloadRequest request, FileInfo fileInfo,
+ @MbmsDownloadSession.DownloadStatus int state) {
+ if (!isFilterFlagSet(STATE_UPDATES)) {
+ return;
+ }
+ try {
+ mCallback.onStateUpdated(request, fileInfo, state);
+ } catch (RemoteException e) {
+ onRemoteException(e);
+ }
+ }
+
+ protected abstract void onRemoteException(RemoteException e);
+ }
+
/**
* Initialize the download service for this app and subId, registering the listener.
*
@@ -196,9 +237,8 @@
* @hide
*/
@Override
- public final int registerStateCallback(
- final DownloadRequest downloadRequest, final IDownloadStateCallback callback)
- throws RemoteException {
+ public final int registerStateCallback(final DownloadRequest downloadRequest,
+ final IDownloadStateCallback callback, int flags) throws RemoteException {
final int uid = Binder.getCallingUid();
DeathRecipient deathRecipient = new DeathRecipient() {
@Override
@@ -211,28 +251,10 @@
mDownloadCallbackDeathRecipients.put(callback.asBinder(), deathRecipient);
callback.asBinder().linkToDeath(deathRecipient, 0);
- DownloadStateCallback exposedCallback = new DownloadStateCallback() {
+ DownloadStateCallback exposedCallback = new FilteredDownloadStateCallback(callback, flags) {
@Override
- public void onProgressUpdated(DownloadRequest request, FileInfo fileInfo, int
- currentDownloadSize, int fullDownloadSize, int currentDecodedSize, int
- fullDecodedSize) {
- try {
- callback.onProgressUpdated(request, fileInfo, currentDownloadSize,
- fullDownloadSize,
- currentDecodedSize, fullDecodedSize);
- } catch (RemoteException e) {
- onAppCallbackDied(uid, downloadRequest.getSubscriptionId());
- }
- }
-
- @Override
- public void onStateUpdated(DownloadRequest request, FileInfo fileInfo,
- @MbmsDownloadSession.DownloadStatus int state) {
- try {
- callback.onStateUpdated(request, fileInfo, state);
- } catch (RemoteException e) {
- onAppCallbackDied(uid, downloadRequest.getSubscriptionId());
- }
+ protected void onRemoteException(RemoteException e) {
+ onAppCallbackDied(uid, downloadRequest.getSubscriptionId());
}
};
diff --git a/telephony/java/android/telephony/mbms/vendor/VendorUtils.java b/telephony/java/android/telephony/mbms/vendor/VendorUtils.java
index 8fb27b2..a43f122 100644
--- a/telephony/java/android/telephony/mbms/vendor/VendorUtils.java
+++ b/telephony/java/android/telephony/mbms/vendor/VendorUtils.java
@@ -38,8 +38,9 @@
/**
* The MBMS middleware should send this when a download of single file has completed or
- * failed. Mandatory extras are
+ * failed. The only mandatory extra is
* {@link MbmsDownloadSession#EXTRA_MBMS_DOWNLOAD_RESULT}
+ * and the following are required when the download has completed:
* {@link MbmsDownloadSession#EXTRA_MBMS_FILE_INFO}
* {@link MbmsDownloadSession#EXTRA_MBMS_DOWNLOAD_REQUEST}
* {@link #EXTRA_TEMP_LIST}
diff --git a/tests/Compatibility/Android.mk b/tests/Compatibility/Android.mk
index feeae02..82e2126 100644
--- a/tests/Compatibility/Android.mk
+++ b/tests/Compatibility/Android.mk
@@ -17,9 +17,7 @@
# We only want this apk build for tests.
LOCAL_MODULE_TAGS := tests
-
-LOCAL_JAVA_LIBRARIES := legacy-android-test
-LOCAL_STATIC_JAVA_LIBRARIES := junit
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
# Include all test java files.
LOCAL_SRC_FILES := \
$(call all-java-files-under, src)
diff --git a/tests/Compatibility/AndroidManifest.xml b/tests/Compatibility/AndroidManifest.xml
index 7017431..5d1317e 100644
--- a/tests/Compatibility/AndroidManifest.xml
+++ b/tests/Compatibility/AndroidManifest.xml
@@ -15,12 +15,12 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.compatibilitytest" >
+ package="com.android.compatibilitytest"
+ android:sharedUserId="android.uid.system">
<uses-sdk android:minSdkVersion="21"
android:targetSdkVersion="21" />
- <application >
- <uses-library android:name="android.test.runner" />
- </application>
+ <application />
+ <uses-permission android:name="android.permission.READ_LOGS" />
<uses-permission android:name="android.permission.REAL_GET_TASKS" />
<instrumentation
android:name=".AppCompatibilityRunner"
diff --git a/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java b/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java
index f81b001..a5261d0 100644
--- a/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java
+++ b/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java
@@ -17,62 +17,91 @@
package com.android.compatibilitytest;
import android.app.ActivityManager;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.IActivityController;
+import android.app.IActivityManager;
+import android.app.Instrumentation;
import android.app.UiAutomation;
import android.app.UiModeManager;
-import android.app.ActivityManager.ProcessErrorStateInfo;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.os.Bundle;
-import android.test.InstrumentationTestCase;
+import android.os.DropBoxManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
import android.util.Log;
-import junit.framework.Assert;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
/**
* Application Compatibility Test that launches an application and detects
* crashes.
*/
-public class AppCompatibility extends InstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class AppCompatibility {
private static final String TAG = AppCompatibility.class.getSimpleName();
private static final String PACKAGE_TO_LAUNCH = "package_to_launch";
private static final String APP_LAUNCH_TIMEOUT_MSECS = "app_launch_timeout_ms";
private static final String WORKSPACE_LAUNCH_TIMEOUT_MSECS = "workspace_launch_timeout_ms";
+ private static final Set<String> DROPBOX_TAGS = new HashSet<>();
+ static {
+ DROPBOX_TAGS.add("SYSTEM_TOMBSTONE");
+ DROPBOX_TAGS.add("system_app_anr");
+ DROPBOX_TAGS.add("system_app_native_crash");
+ DROPBOX_TAGS.add("system_app_crash");
+ DROPBOX_TAGS.add("data_app_anr");
+ DROPBOX_TAGS.add("data_app_native_crash");
+ DROPBOX_TAGS.add("data_app_crash");
+ }
+ // time waiting for app to launch
private int mAppLaunchTimeout = 7000;
+ // time waiting for launcher home screen to show up
private int mWorkspaceLaunchTimeout = 2000;
private Context mContext;
private ActivityManager mActivityManager;
private PackageManager mPackageManager;
- private AppCompatibilityRunner mRunner;
private Bundle mArgs;
+ private Instrumentation mInstrumentation;
+ private String mLauncherPackageName;
+ private IActivityController mCrashSupressor = new CrashSuppressor();
+ private Map<String, List<String>> mAppErrors = new HashMap<>();
- @Override
+ @Before
public void setUp() throws Exception {
- super.setUp();
- mRunner = (AppCompatibilityRunner) getInstrumentation();
- assertNotNull("Could not fetch InstrumentationTestRunner.", mRunner);
-
- mContext = mRunner.getTargetContext();
- Assert.assertNotNull("Could not get the Context", mContext);
-
- mActivityManager = (ActivityManager)
- mContext.getSystemService(Context.ACTIVITY_SERVICE);
- Assert.assertNotNull("Could not get Activity Manager", mActivityManager);
-
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mContext = InstrumentationRegistry.getTargetContext();
+ mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
mPackageManager = mContext.getPackageManager();
- Assert.assertNotNull("Missing Package Manager", mPackageManager);
+ mArgs = InstrumentationRegistry.getArguments();
- mArgs = mRunner.getBundle();
+ // resolve launcher package name
+ Intent intent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME);
+ ResolveInfo resolveInfo = mPackageManager.resolveActivity(
+ intent, PackageManager.MATCH_DEFAULT_ONLY);
+ mLauncherPackageName = resolveInfo.activityInfo.packageName;
+ Assert.assertNotNull("failed to resolve package name for launcher", mLauncherPackageName);
+ Log.v(TAG, "Using launcher package name: " + mLauncherPackageName);
// Parse optional inputs.
String appLaunchTimeoutMsecs = mArgs.getString(APP_LAUNCH_TIMEOUT_MSECS);
@@ -83,13 +112,20 @@
if (workspaceLaunchTimeoutMsecs != null) {
mWorkspaceLaunchTimeout = Integer.parseInt(workspaceLaunchTimeoutMsecs);
}
- getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_0);
+ mInstrumentation.getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_0);
+
+ // set activity controller to suppress crash dialogs and collects them by process name
+ mAppErrors.clear();
+ IActivityManager.Stub.asInterface(ServiceManager.checkService(Context.ACTIVITY_SERVICE))
+ .setActivityController(mCrashSupressor, false);
}
- @Override
- protected void tearDown() throws Exception {
- getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_UNFREEZE);
- super.tearDown();
+ @After
+ public void tearDown() throws Exception {
+ // unset activity controller
+ IActivityManager.Stub.asInterface(ServiceManager.checkService(Context.ACTIVITY_SERVICE))
+ .setActivityController(null, false);
+ mInstrumentation.getUiAutomation().setRotation(UiAutomation.ROTATION_UNFREEZE);
}
/**
@@ -98,6 +134,7 @@
*
* @throws Exception
*/
+ @Test
public void testAppStability() throws Exception {
String packageName = mArgs.getString(PACKAGE_TO_LAUNCH);
if (packageName != null) {
@@ -107,13 +144,23 @@
Log.w(TAG, String.format("Skipping %s; no launch intent", packageName));
return;
}
- ProcessErrorStateInfo err = launchActivity(packageName, intent);
- // Make sure there are no errors when launching the application,
- // otherwise raise an
- // exception with the first error encountered.
- assertNull(getStackTrace(err), err);
+ long startTime = System.currentTimeMillis();
+ launchActivity(packageName, intent);
try {
- assertTrue("App crashed after launch.", processStillUp(packageName));
+ checkDropbox(startTime, packageName);
+ if (mAppErrors.containsKey(packageName)) {
+ StringBuilder message = new StringBuilder("Error detected for package: ")
+ .append(packageName);
+ for (String err : mAppErrors.get(packageName)) {
+ message.append("\n\n");
+ message.append(err);
+ }
+ Assert.fail(message.toString());
+ }
+ // last check: see if app process is still running
+ Assert.assertTrue("app package \"" + packageName + "\" no longer found in running "
+ + "tasks, but no explicit crashes were detected; check logcat for details",
+ processStillUp(packageName));
} finally {
returnHome();
}
@@ -124,31 +171,30 @@
}
/**
- * Gets the stack trace for the error.
- *
- * @param in {@link ProcessErrorStateInfo} to parse.
- * @return {@link String} the long message of the error.
+ * Check dropbox for entries of interest regarding the specified process
+ * @param startTime if not 0, only check entries with timestamp later than the start time
+ * @param processName the process name to check for
*/
- private String getStackTrace(ProcessErrorStateInfo in) {
- if (in == null) {
- return null;
- } else {
- return in.stackTrace;
- }
- }
-
- /**
- * Returns the process name that the package is going to use.
- *
- * @param packageName name of the package
- * @return process name of the package
- */
- private String getProcessName(String packageName) {
- try {
- PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
- return pi.applicationInfo.processName;
- } catch (NameNotFoundException e) {
- return packageName;
+ private void checkDropbox(long startTime, String processName) {
+ DropBoxManager dropbox = (DropBoxManager) mContext
+ .getSystemService(Context.DROPBOX_SERVICE);
+ DropBoxManager.Entry entry = null;
+ while (null != (entry = dropbox.getNextEntry(null, startTime))) {
+ try {
+ // only check entries with tag that's of interest
+ String tag = entry.getTag();
+ if (DROPBOX_TAGS.contains(tag)) {
+ String content = entry.getText(4096);
+ if (content != null) {
+ if (content.contains(processName)) {
+ addProcessError(processName, "dropbox:" + tag, content);
+ }
+ }
+ }
+ startTime = entry.getTimeMillis();
+ } finally {
+ entry.close();
+ }
}
}
@@ -166,8 +212,7 @@
}
private Intent getLaunchIntentForPackage(String packageName) {
- UiModeManager umm = (UiModeManager)
- getInstrumentation().getContext().getSystemService(Context.UI_MODE_SERVICE);
+ UiModeManager umm = (UiModeManager) mContext.getSystemService(Context.UI_MODE_SERVICE);
boolean isLeanback = umm.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION;
Intent intent = null;
if (isLeanback) {
@@ -186,35 +231,32 @@
* @return {@link Collection} of {@link ProcessErrorStateInfo} detected
* during the app launch.
*/
- private ProcessErrorStateInfo launchActivity(String packageName, Intent intent) {
+ private void launchActivity(String packageName, Intent intent) {
Log.d(TAG, String.format("launching package \"%s\" with intent: %s",
packageName, intent.toString()));
- String processName = getProcessName(packageName);
-
// Launch Activity
mContext.startActivity(intent);
try {
+ // artificial delay: in case app crashes after doing some work during launch
Thread.sleep(mAppLaunchTimeout);
} catch (InterruptedException e) {
// ignore
}
+ }
- // See if there are any errors. We wait until down here to give ANRs as much time as
- // possible to occur.
- final Collection<ProcessErrorStateInfo> postErr =
- mActivityManager.getProcessesInErrorState();
-
- if (postErr == null) {
- return null;
+ private void addProcessError(String processName, String errorType, String errorInfo) {
+ // parse out the package name if necessary, for apps with multiple proceses
+ String pkgName = processName.split(":", 2)[0];
+ List<String> errors;
+ if (mAppErrors.containsKey(pkgName)) {
+ errors = mAppErrors.get(pkgName);
+ } else {
+ errors = new ArrayList<>();
}
- for (ProcessErrorStateInfo error : postErr) {
- if (error.processName.equals(processName)) {
- return error;
- }
- }
- return null;
+ errors.add(String.format("type: %s details:\n%s", errorType, errorInfo));
+ mAppErrors.put(pkgName, errors);
}
/**
@@ -233,4 +275,55 @@
}
return false;
}
+
+ /**
+ * An {@link IActivityController} that instructs framework to kill processes hitting crashes
+ * directly without showing crash dialogs
+ *
+ */
+ private class CrashSuppressor extends IActivityController.Stub {
+
+ @Override
+ public boolean activityStarting(Intent intent, String pkg) throws RemoteException {
+ Log.d(TAG, "activity starting: " + intent.getComponent().toShortString());
+ return true;
+ }
+
+ @Override
+ public boolean activityResuming(String pkg) throws RemoteException {
+ Log.d(TAG, "activity resuming: " + pkg);
+ return true;
+ }
+
+ @Override
+ public boolean appCrashed(String processName, int pid, String shortMsg, String longMsg,
+ long timeMillis, String stackTrace) throws RemoteException {
+ Log.d(TAG, "app crash: " + processName);
+ addProcessError(processName, "crash", stackTrace);
+ // don't show dialog
+ return false;
+ }
+
+ @Override
+ public int appEarlyNotResponding(String processName, int pid, String annotation)
+ throws RemoteException {
+ // ignore
+ return 0;
+ }
+
+ @Override
+ public int appNotResponding(String processName, int pid, String processStats)
+ throws RemoteException {
+ Log.d(TAG, "app ANR: " + processName);
+ addProcessError(processName, "ANR", processStats);
+ // don't show dialog
+ return -1;
+ }
+
+ @Override
+ public int systemNotResponding(String msg) throws RemoteException {
+ // ignore
+ return -1;
+ }
+ }
}
diff --git a/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibilityRunner.java b/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibilityRunner.java
index 258937f..b61ec34 100644
--- a/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibilityRunner.java
+++ b/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibilityRunner.java
@@ -16,20 +16,7 @@
package com.android.compatibilitytest;
-import android.os.Bundle;
-import android.test.InstrumentationTestRunner;
+import android.support.test.runner.AndroidJUnitRunner;
-public class AppCompatibilityRunner extends InstrumentationTestRunner {
-
- private Bundle mArgs;
-
- @Override
- public void onCreate(Bundle args) {
- super.onCreate(args);
- mArgs = args;
- }
-
- public Bundle getBundle() {
- return mArgs;
- }
-}
+// empty subclass to maintain backwards compatibility on host-side harness
+public class AppCompatibilityRunner extends AndroidJUnitRunner {}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 9c498c7..335e6240 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -121,7 +121,6 @@
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.BooleanSupplier;
import java.util.function.Predicate;
/**
@@ -3212,68 +3211,68 @@
}
@SmallTest
- public void testNetworkRequestMaximum() {
+ public void testNetworkCallbackMaximum() {
final int MAX_REQUESTS = 100;
- // Test that the limit is enforced when MAX_REQUESTS simultaneous requests are added.
+ final int CALLBACKS = 90;
+ final int INTENTS = 10;
+ assertEquals(MAX_REQUESTS, CALLBACKS + INTENTS);
+
NetworkRequest networkRequest = new NetworkRequest.Builder().build();
- ArrayList<NetworkCallback> networkCallbacks = new ArrayList<NetworkCallback>();
- try {
- for (int i = 0; i < MAX_REQUESTS; i++) {
- NetworkCallback networkCallback = new NetworkCallback();
- mCm.requestNetwork(networkRequest, networkCallback);
- networkCallbacks.add(networkCallback);
- }
- fail("Registering " + MAX_REQUESTS + " NetworkRequests did not throw exception");
- } catch (TooManyRequestsException expected) {}
- for (NetworkCallback networkCallback : networkCallbacks) {
- mCm.unregisterNetworkCallback(networkCallback);
- }
- networkCallbacks.clear();
+ ArrayList<Object> registered = new ArrayList<>();
- try {
- for (int i = 0; i < MAX_REQUESTS; i++) {
- NetworkCallback networkCallback = new NetworkCallback();
- mCm.registerNetworkCallback(networkRequest, networkCallback);
- networkCallbacks.add(networkCallback);
- }
- fail("Registering " + MAX_REQUESTS + " NetworkCallbacks did not throw exception");
- } catch (TooManyRequestsException expected) {}
- for (NetworkCallback networkCallback : networkCallbacks) {
- mCm.unregisterNetworkCallback(networkCallback);
+ int j = 0;
+ while (j++ < CALLBACKS / 2) {
+ NetworkCallback cb = new NetworkCallback();
+ mCm.requestNetwork(networkRequest, cb);
+ registered.add(cb);
}
- networkCallbacks.clear();
+ while (j++ < CALLBACKS) {
+ NetworkCallback cb = new NetworkCallback();
+ mCm.registerNetworkCallback(networkRequest, cb);
+ registered.add(cb);
+ }
+ j = 0;
+ while (j++ < INTENTS / 2) {
+ PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, new Intent("a" + j), 0);
+ mCm.requestNetwork(networkRequest, pi);
+ registered.add(pi);
+ }
+ while (j++ < INTENTS) {
+ PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, new Intent("b" + j), 0);
+ mCm.registerNetworkCallback(networkRequest, pi);
+ registered.add(pi);
+ }
- ArrayList<PendingIntent> pendingIntents = new ArrayList<PendingIntent>();
+ // Test that the limit is enforced when MAX_REQUESTS simultaneous requests are added.
try {
- for (int i = 0; i < MAX_REQUESTS + 1; i++) {
- PendingIntent pendingIntent =
- PendingIntent.getBroadcast(mContext, 0, new Intent("a" + i), 0);
- mCm.requestNetwork(networkRequest, pendingIntent);
- pendingIntents.add(pendingIntent);
- }
- fail("Registering " + MAX_REQUESTS +
- " PendingIntent NetworkRequests did not throw exception");
+ mCm.requestNetwork(networkRequest, new NetworkCallback());
+ fail("Registering " + MAX_REQUESTS + " network requests did not throw exception");
} catch (TooManyRequestsException expected) {}
- for (PendingIntent pendingIntent : pendingIntents) {
- mCm.unregisterNetworkCallback(pendingIntent);
- }
- pendingIntents.clear();
+ try {
+ mCm.registerNetworkCallback(networkRequest, new NetworkCallback());
+ fail("Registering " + MAX_REQUESTS + " network callbacks did not throw exception");
+ } catch (TooManyRequestsException expected) {}
+ try {
+ mCm.requestNetwork(networkRequest,
+ PendingIntent.getBroadcast(mContext, 0, new Intent("c"), 0));
+ fail("Registering " + MAX_REQUESTS + " PendingIntent requests did not throw exception");
+ } catch (TooManyRequestsException expected) {}
+ try {
+ mCm.registerNetworkCallback(networkRequest,
+ PendingIntent.getBroadcast(mContext, 0, new Intent("d"), 0));
+ fail("Registering " + MAX_REQUESTS
+ + " PendingIntent callbacks did not throw exception");
+ } catch (TooManyRequestsException expected) {}
- try {
- for (int i = 0; i < MAX_REQUESTS + 1; i++) {
- PendingIntent pendingIntent =
- PendingIntent.getBroadcast(mContext, 0, new Intent("a" + i), 0);
- mCm.registerNetworkCallback(networkRequest, pendingIntent);
- pendingIntents.add(pendingIntent);
+ for (Object o : registered) {
+ if (o instanceof NetworkCallback) {
+ mCm.unregisterNetworkCallback((NetworkCallback)o);
}
- fail("Registering " + MAX_REQUESTS +
- " PendingIntent NetworkCallbacks did not throw exception");
- } catch (TooManyRequestsException expected) {}
- for (PendingIntent pendingIntent : pendingIntents) {
- mCm.unregisterNetworkCallback(pendingIntent);
+ if (o instanceof PendingIntent) {
+ mCm.unregisterNetworkCallback((PendingIntent)o);
+ }
}
- pendingIntents.clear();
- waitForIdle(5000);
+ waitForIdle();
// Test that the limit is not hit when MAX_REQUESTS requests are added and removed.
for (int i = 0; i < MAX_REQUESTS; i++) {
@@ -3281,23 +3280,23 @@
mCm.requestNetwork(networkRequest, networkCallback);
mCm.unregisterNetworkCallback(networkCallback);
}
- waitForIdle();
+
for (int i = 0; i < MAX_REQUESTS; i++) {
NetworkCallback networkCallback = new NetworkCallback();
mCm.registerNetworkCallback(networkRequest, networkCallback);
mCm.unregisterNetworkCallback(networkCallback);
}
- waitForIdle();
+
for (int i = 0; i < MAX_REQUESTS; i++) {
PendingIntent pendingIntent =
- PendingIntent.getBroadcast(mContext, 0, new Intent("b" + i), 0);
+ PendingIntent.getBroadcast(mContext, 0, new Intent("e" + i), 0);
mCm.requestNetwork(networkRequest, pendingIntent);
mCm.unregisterNetworkCallback(pendingIntent);
}
- waitForIdle();
+
for (int i = 0; i < MAX_REQUESTS; i++) {
PendingIntent pendingIntent =
- PendingIntent.getBroadcast(mContext, 0, new Intent("c" + i), 0);
+ PendingIntent.getBroadcast(mContext, 0, new Intent("f" + i), 0);
mCm.registerNetworkCallback(networkRequest, pendingIntent);
mCm.unregisterNetworkCallback(pendingIntent);
}
diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp
index 5f586a1..627a231 100644
--- a/tools/aapt/Images.cpp
+++ b/tools/aapt/Images.cpp
@@ -1246,7 +1246,7 @@
if (kIsDebug) {
printf("Adding 9-patch info...\n");
}
- strcpy((char*)unknowns[p_index].name, "npTc");
+ memcpy((char*)unknowns[p_index].name, "npTc", 5);
unknowns[p_index].data = (png_byte*)imageInfo.serialize9patch();
unknowns[p_index].size = imageInfo.info9Patch.serializedSize();
// TODO: remove the check below when everything works
@@ -1254,7 +1254,7 @@
// automatically generated 9 patch outline data
int chunk_size = sizeof(png_uint_32) * 6;
- strcpy((char*)unknowns[o_index].name, "npOl");
+ memcpy((char*)unknowns[o_index].name, "npOl", 5);
unknowns[o_index].data = (png_byte*) calloc(chunk_size, 1);
png_byte outputData[chunk_size];
memcpy(&outputData, &imageInfo.outlineInsetsLeft, 4 * sizeof(png_uint_32));
@@ -1266,7 +1266,7 @@
// optional optical inset / layout bounds data
if (imageInfo.haveLayoutBounds) {
int chunk_size = sizeof(png_uint_32) * 4;
- strcpy((char*)unknowns[b_index].name, "npLb");
+ memcpy((char*)unknowns[b_index].name, "npLb", 5);
unknowns[b_index].data = (png_byte*) calloc(chunk_size, 1);
memcpy(unknowns[b_index].data, &imageInfo.layoutBoundsLeft, chunk_size);
unknowns[b_index].size = chunk_size;
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp
index b80780e..6f2b865 100644
--- a/tools/aapt2/LoadedApk.cpp
+++ b/tools/aapt2/LoadedApk.cpp
@@ -20,11 +20,15 @@
#include "ValueVisitor.h"
#include "flatten/Archive.h"
#include "flatten/TableFlattener.h"
+#include "flatten/XmlFlattener.h"
#include "io/BigBufferInputStream.h"
#include "io/Util.h"
+#include "xml/XmlDom.h"
namespace aapt {
+using xml::XmlResource;
+
std::unique_ptr<LoadedApk> LoadedApk::LoadApkFromPath(IAaptContext* context,
const android::StringPiece& path) {
Source source(path);
@@ -52,6 +56,7 @@
if (!parser.Parse()) {
return {};
}
+
return util::make_unique<LoadedApk>(source, std::move(apk), std::move(table));
}
@@ -63,7 +68,7 @@
bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table,
const TableFlattenerOptions& options, FilterChain* filters,
- IArchiveWriter* writer) {
+ IArchiveWriter* writer, XmlResource* manifest) {
std::set<std::string> referenced_resources;
// List the files being referenced in the resource table.
for (auto& pkg : split_table->packages) {
@@ -119,6 +124,20 @@
return false;
}
+ } else if (manifest != nullptr && path == "AndroidManifest.xml") {
+ BigBuffer buffer(8192);
+ XmlFlattener xml_flattener(&buffer, {});
+ if (!xml_flattener.Consume(context, manifest)) {
+ context->GetDiagnostics()->Error(DiagMessage(path) << "flattening failed");
+ return false;
+ }
+
+ uint32_t compression_flags = file->WasCompressed() ? ArchiveEntry::kCompress : 0u;
+ io::BigBufferInputStream manifest_buffer_in(&buffer);
+ if (!io::CopyInputStreamToArchive(context, &manifest_buffer_in, path, compression_flags,
+ writer)) {
+ return false;
+ }
} else {
uint32_t compression_flags = file->WasCompressed() ? ArchiveEntry::kCompress : 0u;
if (!io::CopyFileToArchive(context, file, path, compression_flags, writer)) {
@@ -129,4 +148,26 @@
return true;
}
+std::unique_ptr<xml::XmlResource> LoadedApk::InflateManifest(IAaptContext* context) {
+ IDiagnostics* diag = context->GetDiagnostics();
+
+ io::IFile* manifest_file = GetFileCollection()->FindFile("AndroidManifest.xml");
+ if (manifest_file == nullptr) {
+ diag->Error(DiagMessage(source_) << "no AndroidManifest.xml found");
+ return {};
+ }
+
+ std::unique_ptr<io::IData> manifest_data = manifest_file->OpenAsData();
+ if (manifest_data == nullptr) {
+ diag->Error(DiagMessage(manifest_file->GetSource()) << "could not open AndroidManifest.xml");
+ return {};
+ }
+
+ std::unique_ptr<xml::XmlResource> manifest =
+ xml::Inflate(manifest_data->data(), manifest_data->size(), diag, manifest_file->GetSource());
+ if (manifest == nullptr) {
+ diag->Error(DiagMessage() << "failed to read binary AndroidManifest.xml");
+ }
+ return manifest;
+}
} // namespace aapt
diff --git a/tools/aapt2/LoadedApk.h b/tools/aapt2/LoadedApk.h
index dacd0c2..d779b7e 100644
--- a/tools/aapt2/LoadedApk.h
+++ b/tools/aapt2/LoadedApk.h
@@ -25,17 +25,17 @@
#include "flatten/TableFlattener.h"
#include "io/ZipArchive.h"
#include "unflatten/BinaryResourceParser.h"
+#include "xml/XmlDom.h"
namespace aapt {
/** Info about an APK loaded in memory. */
class LoadedApk {
public:
- LoadedApk(
- const Source& source,
- std::unique_ptr<io::IFileCollection> apk,
- std::unique_ptr<ResourceTable> table)
- : source_(source), apk_(std::move(apk)), table_(std::move(table)) {}
+ LoadedApk(const Source& source, std::unique_ptr<io::IFileCollection> apk,
+ std::unique_ptr<ResourceTable> table)
+ : source_(source), apk_(std::move(apk)), table_(std::move(table)) {
+ }
io::IFileCollection* GetFileCollection() { return apk_.get(); }
@@ -51,13 +51,20 @@
IArchiveWriter* writer);
/**
- * Writes the APK on disk at the given path, while also removing the resource
- * files that are not referenced in the resource table. The provided filter
- * chain is applied to each entry in the APK file.
+ * Writes the APK on disk at the given path, while also removing the resource files that are not
+ * referenced in the resource table. The provided filter chain is applied to each entry in the APK
+ * file.
+ *
+ * If the manifest is also provided, it will be written to the new APK file, otherwise the
+ * original manifest will be written. The manifest is only required if the contents of the new APK
+ * have been modified in a way that require the AndroidManifest.xml to also be modified.
*/
virtual bool WriteToArchive(IAaptContext* context, ResourceTable* split_table,
const TableFlattenerOptions& options, FilterChain* filters,
- IArchiveWriter* writer);
+ IArchiveWriter* writer, xml::XmlResource* manifest = nullptr);
+
+ /** Inflates the AndroidManifest.xml file from the APK. */
+ std::unique_ptr<xml::XmlResource> InflateManifest(IAaptContext* context);
static std::unique_ptr<LoadedApk> LoadApkFromPath(IAaptContext* context,
const android::StringPiece& path);
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index 704faee..56b61d0 100644
--- a/tools/aapt2/cmd/Optimize.cpp
+++ b/tools/aapt2/cmd/Optimize.cpp
@@ -283,24 +283,8 @@
bool ExtractAppDataFromManifest(OptimizeContext* context, LoadedApk* apk,
OptimizeOptions* out_options) {
- io::IFile* manifest_file = apk->GetFileCollection()->FindFile("AndroidManifest.xml");
- if (manifest_file == nullptr) {
- context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
- << "missing AndroidManifest.xml");
- return false;
- }
-
- std::unique_ptr<io::IData> data = manifest_file->OpenAsData();
- if (data == nullptr) {
- context->GetDiagnostics()->Error(DiagMessage(manifest_file->GetSource())
- << "failed to open file");
- return false;
- }
-
- std::unique_ptr<xml::XmlResource> manifest = xml::Inflate(
- data->data(), data->size(), context->GetDiagnostics(), manifest_file->GetSource());
+ std::unique_ptr<xml::XmlResource> manifest = apk->InflateManifest(context);
if (manifest == nullptr) {
- context->GetDiagnostics()->Error(DiagMessage() << "failed to read binary AndroidManifest.xml");
return false;
}
diff --git a/tools/aapt2/compile/Png.cpp b/tools/aapt2/compile/Png.cpp
index 6d6147d..33122dc 100644
--- a/tools/aapt2/compile/Png.cpp
+++ b/tools/aapt2/compile/Png.cpp
@@ -538,7 +538,7 @@
if (kDebug) {
diag->Note(DiagMessage() << "adding 9-patch info..");
}
- strcpy((char*)unknowns[pIndex].name, "npTc");
+ memcpy((char*)unknowns[pIndex].name, "npTc", 5);
unknowns[pIndex].data = (png_byte*)info->serialize9Patch();
unknowns[pIndex].size = info->info9Patch.serializedSize();
// TODO: remove the check below when everything works
@@ -546,7 +546,7 @@
// automatically generated 9 patch outline data
int chunkSize = sizeof(png_uint_32) * 6;
- strcpy((char*)unknowns[oIndex].name, "npOl");
+ memcpy((char*)unknowns[oIndex].name, "npOl", 5);
unknowns[oIndex].data = (png_byte*)calloc(chunkSize, 1);
png_byte outputData[chunkSize];
memcpy(&outputData, &info->outlineInsetsLeft, 4 * sizeof(png_uint_32));
@@ -558,7 +558,7 @@
// optional optical inset / layout bounds data
if (info->haveLayoutBounds) {
int chunkSize = sizeof(png_uint_32) * 4;
- strcpy((char*)unknowns[bIndex].name, "npLb");
+ memcpy((char*)unknowns[bIndex].name, "npLb", 5);
unknowns[bIndex].data = (png_byte*)calloc(chunkSize, 1);
memcpy(unknowns[bIndex].data, &info->layoutBoundsLeft, chunkSize);
unknowns[bIndex].size = chunkSize;
diff --git a/tools/aapt2/configuration/ConfigurationParser.cpp b/tools/aapt2/configuration/ConfigurationParser.cpp
index 9d6d328..a79a577 100644
--- a/tools/aapt2/configuration/ConfigurationParser.cpp
+++ b/tools/aapt2/configuration/ConfigurationParser.cpp
@@ -27,6 +27,7 @@
#include "ConfigDescription.h"
#include "Diagnostics.h"
+#include "ResourceUtils.h"
#include "io/File.h"
#include "io/FileSystem.h"
#include "io/StringInputStream.h"
@@ -329,15 +330,32 @@
// TODO: Validate all references in the configuration are valid. It should be safe to assume from
// this point on that any references from one section to another will be present.
+ // TODO: Automatically arrange artifacts so that they match Play Store multi-APK requirements.
+ // see: https://developer.android.com/google/play/publishing/multiple-apks.html
+ //
+ // For now, make sure the version codes are unique.
+ std::vector<Artifact>& artifacts = config.artifacts;
+ std::sort(artifacts.begin(), artifacts.end());
+ if (std::adjacent_find(artifacts.begin(), artifacts.end()) != artifacts.end()) {
+ diag_->Error(DiagMessage() << "Configuration has duplicate versions");
+ return {};
+ }
+
return {config};
}
ConfigurationParser::ActionHandler ConfigurationParser::artifact_handler_ =
[](PostProcessingConfiguration* config, Element* root_element, IDiagnostics* diag) -> bool {
+ // This will be incremented later so the first version will always be different to the base APK.
+ int current_version = (config->artifacts.empty()) ? 0 : config->artifacts.back().version;
+
Artifact artifact{};
+ Maybe<int> version;
for (const auto& attr : root_element->attributes) {
if (attr.name == "name") {
artifact.name = attr.value;
+ } else if (attr.name == "version") {
+ version = std::stoi(attr.value);
} else if (attr.name == "abi-group") {
artifact.abi_group = {attr.value};
} else if (attr.name == "screen-density-group") {
@@ -355,6 +373,9 @@
<< attr.value);
}
}
+
+ artifact.version = (version) ? version.value() : current_version + 1;
+
config->artifacts.push_back(artifact);
return true;
};
@@ -499,11 +520,11 @@
AndroidSdk entry;
for (const auto& attr : child->attributes) {
if (attr.name == "minSdkVersion") {
- entry.min_sdk_version = {attr.value};
+ entry.min_sdk_version = ResourceUtils::ParseSdkVersion(attr.value);
} else if (attr.name == "targetSdkVersion") {
- entry.target_sdk_version = {attr.value};
+ entry.target_sdk_version = ResourceUtils::ParseSdkVersion(attr.value);
} else if (attr.name == "maxSdkVersion") {
- entry.max_sdk_version = {attr.value};
+ entry.max_sdk_version = ResourceUtils::ParseSdkVersion(attr.value);
} else {
diag->Warn(DiagMessage() << "Unknown attribute: " << attr.name << " = " << attr.value);
}
diff --git a/tools/aapt2/configuration/ConfigurationParser.h b/tools/aapt2/configuration/ConfigurationParser.h
index 9bc9081..c5d3284 100644
--- a/tools/aapt2/configuration/ConfigurationParser.h
+++ b/tools/aapt2/configuration/ConfigurationParser.h
@@ -17,6 +17,7 @@
#ifndef AAPT2_CONFIGURATION_H
#define AAPT2_CONFIGURATION_H
+#include <set>
#include <string>
#include <unordered_map>
#include <vector>
@@ -41,6 +42,12 @@
struct Artifact {
/** Name to use for output of processing foo.apk -> foo.<name>.apk. */
Maybe<std::string> name;
+ /**
+ * Value to add to the base Android manifest versionCode. If it is not present in the
+ * configuration file, it is set to the previous artifact + 1. If the first artifact does not have
+ * a value, artifacts are a 1 based index.
+ */
+ int version;
/** If present, uses the ABI group with this name. */
Maybe<std::string> abi_group;
/** If present, uses the screen density group with this name. */
@@ -60,6 +67,15 @@
/** Convert an artifact name template into a name string based on configuration contents. */
Maybe<std::string> Name(const android::StringPiece& apk_name, IDiagnostics* diag) const;
+
+ bool operator<(const Artifact& rhs) const {
+ // TODO(safarmer): Order by play store multi-APK requirements.
+ return version < rhs.version;
+ }
+
+ bool operator==(const Artifact& rhs) const {
+ return version == rhs.version;
+ }
};
/** Enumeration of currently supported ABIs. */
@@ -103,14 +119,14 @@
};
struct AndroidSdk {
- Maybe<std::string> min_sdk_version;
- Maybe<std::string> target_sdk_version;
- Maybe<std::string> max_sdk_version;
+ Maybe<int> min_sdk_version;
+ Maybe<int> target_sdk_version;
+ Maybe<int> max_sdk_version;
Maybe<AndroidManifest> manifest;
- static AndroidSdk ForMinSdk(std::string min_sdk) {
+ static AndroidSdk ForMinSdk(int min_sdk) {
AndroidSdk sdk;
- sdk.min_sdk_version = {std::move(min_sdk)};
+ sdk.min_sdk_version = min_sdk;
return sdk;
}
diff --git a/tools/aapt2/configuration/ConfigurationParser_test.cpp b/tools/aapt2/configuration/ConfigurationParser_test.cpp
index 7ffb3d5..3654901 100644
--- a/tools/aapt2/configuration/ConfigurationParser_test.cpp
+++ b/tools/aapt2/configuration/ConfigurationParser_test.cpp
@@ -24,6 +24,15 @@
#include "xml/XmlDom.h"
namespace aapt {
+
+namespace configuration {
+void PrintTo(const AndroidSdk& sdk, std::ostream* os) {
+ *os << "SDK: min=" << sdk.min_sdk_version.value_or_default(-1)
+ << ", target=" << sdk.target_sdk_version.value_or_default(-1)
+ << ", max=" << sdk.max_sdk_version.value_or_default(-1);
+}
+} // namespace configuration
+
namespace {
using ::android::ResTable_config;
@@ -76,9 +85,9 @@
</locale-group>
<android-sdk-group label="v19">
<android-sdk
- minSdkVersion="v19"
- targetSdkVersion="v24"
- maxSdkVersion="v25">
+ minSdkVersion="19"
+ targetSdkVersion="24"
+ maxSdkVersion="25">
<manifest>
<!--- manifest additions here XSLT? TODO -->
</manifest>
@@ -156,7 +165,7 @@
EXPECT_EQ(1ul, value.android_sdk_groups.size());
EXPECT_TRUE(value.android_sdk_groups["v19"].min_sdk_version);
- EXPECT_EQ("v19", value.android_sdk_groups["v19"].min_sdk_version.value());
+ EXPECT_EQ(19, value.android_sdk_groups["v19"].min_sdk_version.value());
EXPECT_EQ(1ul, value.gl_texture_groups.size());
EXPECT_EQ(1ul, value.gl_texture_groups["dxt1"].size());
@@ -174,55 +183,117 @@
}
TEST_F(ConfigurationParserTest, ArtifactAction) {
- static constexpr const char* xml = R"xml(
+ PostProcessingConfiguration config;
+ {
+ const auto doc = test::BuildXmlDom(R"xml(
+ <artifact
+ abi-group="arm"
+ screen-density-group="large"
+ locale-group="europe"
+ android-sdk-group="v19"
+ gl-texture-group="dxt1"
+ device-feature-group="low-latency"/>)xml");
+
+ ASSERT_TRUE(artifact_handler_(&config, NodeCast<Element>(doc->root.get()), &diag_));
+
+ EXPECT_EQ(1ul, config.artifacts.size());
+
+ auto& artifact = config.artifacts.back();
+ EXPECT_FALSE(artifact.name); // TODO: make this fail.
+ EXPECT_EQ(1, artifact.version);
+ EXPECT_EQ("arm", artifact.abi_group.value());
+ EXPECT_EQ("large", artifact.screen_density_group.value());
+ EXPECT_EQ("europe", artifact.locale_group.value());
+ EXPECT_EQ("v19", artifact.android_sdk_group.value());
+ EXPECT_EQ("dxt1", artifact.gl_texture_group.value());
+ EXPECT_EQ("low-latency", artifact.device_feature_group.value());
+ }
+
+ {
+ // Perform a second action to ensure we get 2 artifacts.
+ const auto doc = test::BuildXmlDom(R"xml(
+ <artifact
+ abi-group="other"
+ screen-density-group="large"
+ locale-group="europe"
+ android-sdk-group="v19"
+ gl-texture-group="dxt1"
+ device-feature-group="low-latency"/>)xml");
+
+ ASSERT_TRUE(artifact_handler_(&config, NodeCast<Element>(doc.get()->root.get()), &diag_));
+ EXPECT_EQ(2ul, config.artifacts.size());
+ EXPECT_EQ(2, config.artifacts.back().version);
+ }
+
+ {
+ // Perform a third action with a set version code.
+ const auto doc = test::BuildXmlDom(R"xml(
<artifact
- abi-group="arm"
+ version="5"
+ abi-group="other"
screen-density-group="large"
locale-group="europe"
android-sdk-group="v19"
gl-texture-group="dxt1"
- device-feature-group="low-latency"/>)xml";
+ device-feature-group="low-latency"/>)xml");
- auto doc = test::BuildXmlDom(xml);
+ ASSERT_TRUE(artifact_handler_(&config, NodeCast<Element>(doc.get()->root.get()), &diag_));
+ EXPECT_EQ(3ul, config.artifacts.size());
+ EXPECT_EQ(5, config.artifacts.back().version);
+ }
- PostProcessingConfiguration config;
- bool ok = artifact_handler_(&config, NodeCast<Element>(doc->root.get()), &diag_);
- ASSERT_TRUE(ok);
-
- EXPECT_EQ(1ul, config.artifacts.size());
-
- auto& artifact = config.artifacts.front();
- EXPECT_FALSE(artifact.name); // TODO: make this fail.
- EXPECT_EQ("arm", artifact.abi_group.value());
- EXPECT_EQ("large", artifact.screen_density_group.value());
- EXPECT_EQ("europe", artifact.locale_group.value());
- EXPECT_EQ("v19", artifact.android_sdk_group.value());
- EXPECT_EQ("dxt1", artifact.gl_texture_group.value());
- EXPECT_EQ("low-latency", artifact.device_feature_group.value());
-
- // Perform a second action to ensure we get 2 artifacts.
- static constexpr const char* second = R"xml(
+ {
+ // Perform a fourth action to ensure the version code still increments.
+ const auto doc = test::BuildXmlDom(R"xml(
<artifact
abi-group="other"
screen-density-group="large"
locale-group="europe"
android-sdk-group="v19"
gl-texture-group="dxt1"
- device-feature-group="low-latency"/>)xml";
- doc = test::BuildXmlDom(second);
+ device-feature-group="low-latency"/>)xml");
- ok = artifact_handler_(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
- ASSERT_TRUE(ok);
- EXPECT_EQ(2ul, config.artifacts.size());
+ ASSERT_TRUE(artifact_handler_(&config, NodeCast<Element>(doc.get()->root.get()), &diag_));
+ EXPECT_EQ(4ul, config.artifacts.size());
+ EXPECT_EQ(6, config.artifacts.back().version);
+ }
+}
+
+TEST_F(ConfigurationParserTest, DuplicateArtifactVersion) {
+ static constexpr const char* configuration = R"xml(<?xml version="1.0" encoding="utf-8" ?>
+ <pst-process xmlns="http://schemas.android.com/tools/aapt">>
+ <artifacts>
+ <artifact-format>
+ ${base}.${abi}.${screen-density}.${locale}.${sdk}.${gl}.${feature}.release
+ </artifact-format>
+ <artifact
+ name="art1"
+ abi-group="arm"
+ screen-density-group="large"
+ locale-group="europe"
+ android-sdk-group="v19"
+ gl-texture-group="dxt1"
+ device-feature-group="low-latency"/>
+ <artifact
+ name="art2"
+ version = "1"
+ abi-group="other"
+ screen-density-group="alldpi"
+ locale-group="north-america"
+ android-sdk-group="v19"
+ gl-texture-group="dxt1"
+ device-feature-group="low-latency"/>
+ </artifacts>
+ </post-process>)xml";
+ auto result = ConfigurationParser::ForContents(configuration).Parse();
+ ASSERT_FALSE(result);
}
TEST_F(ConfigurationParserTest, ArtifactFormatAction) {
- static constexpr const char* xml = R"xml(
+ const auto doc = test::BuildXmlDom(R"xml(
<artifact-format>
${base}.${abi}.${screen-density}.${locale}.${sdk}.${gl}.${feature}.release
- </artifact-format>)xml";
-
- auto doc = test::BuildXmlDom(xml);
+ </artifact-format>)xml");
PostProcessingConfiguration config;
bool ok = artifact_format_handler_(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
@@ -321,9 +392,9 @@
static constexpr const char* xml = R"xml(
<android-sdk-group label="v19">
<android-sdk
- minSdkVersion="v19"
- targetSdkVersion="v24"
- maxSdkVersion="v25">
+ minSdkVersion="19"
+ targetSdkVersion="24"
+ maxSdkVersion="25">
<manifest>
<!--- manifest additions here XSLT? TODO -->
</manifest>
@@ -342,14 +413,43 @@
auto& out = config.android_sdk_groups["v19"];
AndroidSdk sdk;
- sdk.min_sdk_version = std::string("v19");
- sdk.target_sdk_version = std::string("v24");
- sdk.max_sdk_version = std::string("v25");
+ sdk.min_sdk_version = 19;
+ sdk.target_sdk_version = 24;
+ sdk.max_sdk_version = 25;
sdk.manifest = AndroidManifest();
ASSERT_EQ(sdk, out);
}
+TEST_F(ConfigurationParserTest, AndroidSdkGroupAction_NonNumeric) {
+ static constexpr const char* xml = R"xml(
+ <android-sdk-group label="O">
+ <android-sdk
+ minSdkVersion="M"
+ targetSdkVersion="O"
+ maxSdkVersion="O">
+ </android-sdk>
+ </android-sdk-group>)xml";
+
+ auto doc = test::BuildXmlDom(xml);
+
+ PostProcessingConfiguration config;
+ bool ok = android_sdk_group_handler_(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
+ ASSERT_TRUE(ok);
+
+ ASSERT_EQ(1ul, config.android_sdk_groups.size());
+ ASSERT_EQ(1u, config.android_sdk_groups.count("O"));
+
+ auto& out = config.android_sdk_groups["O"];
+
+ AndroidSdk sdk;
+ sdk.min_sdk_version = {}; // Only the latest development version is supported.
+ sdk.target_sdk_version = 26;
+ sdk.max_sdk_version = 26;
+
+ ASSERT_EQ(sdk, out);
+}
+
TEST_F(ConfigurationParserTest, GlTextureGroupAction) {
static constexpr const char* xml = R"xml(
<gl-texture-group label="dxt1">
diff --git a/tools/aapt2/configuration/aapt2.xsd b/tools/aapt2/configuration/aapt2.xsd
index 47bf99e..134153a 100644
--- a/tools/aapt2/configuration/aapt2.xsd
+++ b/tools/aapt2/configuration/aapt2.xsd
@@ -39,6 +39,7 @@
<!-- Groups output artifacts together by dimension labels. -->
<xsd:complexType name="artifact">
<xsd:attribute name="name" type="xsd:string"/>
+ <xsd:attribute name="version" type="xsd:integer"/>
<xsd:attribute name="abi-group" type="xsd:string"/>
<xsd:attribute name="android-sdk-group" type="xsd:string"/>
<xsd:attribute name="device-feature-group" type="xsd:string"/>
diff --git a/tools/aapt2/java/ClassDefinition.cpp b/tools/aapt2/java/ClassDefinition.cpp
index 6ad0dd6..0c57e7e 100644
--- a/tools/aapt2/java/ClassDefinition.cpp
+++ b/tools/aapt2/java/ClassDefinition.cpp
@@ -41,18 +41,21 @@
ClassDefinition::Result ClassDefinition::AddMember(std::unique_ptr<ClassMember> member) {
Result result = Result::kAdded;
- auto iter = members_.find(member);
- if (iter != members_.end()) {
- members_.erase(iter);
+ auto iter = indexed_members_.find(member->GetName());
+ if (iter != indexed_members_.end()) {
+ // Overwrite the entry.
+ ordered_members_[iter->second].reset();
result = Result::kOverridden;
}
- members_.insert(std::move(member));
+
+ indexed_members_[member->GetName()] = ordered_members_.size();
+ ordered_members_.push_back(std::move(member));
return result;
}
bool ClassDefinition::empty() const {
- for (const std::unique_ptr<ClassMember>& member : members_) {
- if (!member->empty()) {
+ for (const std::unique_ptr<ClassMember>& member : ordered_members_) {
+ if (member != nullptr && !member->empty()) {
return false;
}
}
@@ -61,7 +64,7 @@
void ClassDefinition::WriteToStream(const StringPiece& prefix, bool final,
std::ostream* out) const {
- if (members_.empty() && !create_if_empty_) {
+ if (empty() && !create_if_empty_) {
return;
}
@@ -76,9 +79,14 @@
std::string new_prefix = prefix.to_string();
new_prefix.append(kIndent);
- for (const std::unique_ptr<ClassMember>& member : members_) {
- member->WriteToStream(new_prefix, final, out);
- *out << "\n";
+ for (const std::unique_ptr<ClassMember>& member : ordered_members_) {
+ // There can be nullptr members when a member is added to the ClassDefinition
+ // and takes precedence over a previous member with the same name. The overridden member is
+ // set to nullptr.
+ if (member != nullptr) {
+ member->WriteToStream(new_prefix, final, out);
+ *out << "\n";
+ }
}
*out << prefix << "}";
diff --git a/tools/aapt2/java/ClassDefinition.h b/tools/aapt2/java/ClassDefinition.h
index 6c4bcad..28a3489 100644
--- a/tools/aapt2/java/ClassDefinition.h
+++ b/tools/aapt2/java/ClassDefinition.h
@@ -18,8 +18,9 @@
#define AAPT_JAVA_CLASSDEFINITION_H
#include <ostream>
-#include <set>
#include <string>
+#include <unordered_map>
+#include <vector>
#include "android-base/macros.h"
#include "androidfw/StringPiece.h"
@@ -73,21 +74,18 @@
void WriteToStream(const android::StringPiece& prefix, bool final,
std::ostream* out) const override {
ClassMember::WriteToStream(prefix, final, out);
-
- *out << prefix << "public static " << (final ? "final " : "") << "int "
- << name_ << "=" << val_ << ";";
+ *out << prefix << "public static " << (final ? "final " : "") << "int " << name_ << "=" << val_
+ << ";";
}
private:
+ DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);
+
std::string name_;
T val_;
-
- DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);
};
-/**
- * Specialization for strings so they get the right type and are quoted with "".
- */
+// Specialization for strings so they get the right type and are quoted with "".
template <>
class PrimitiveMember<std::string> : public ClassMember {
public:
@@ -111,10 +109,10 @@
}
private:
+ DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);
+
std::string name_;
std::string val_;
-
- DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);
};
using IntMember = PrimitiveMember<uint32_t>;
@@ -160,10 +158,10 @@
}
private:
+ DISALLOW_COPY_AND_ASSIGN(PrimitiveArrayMember);
+
std::string name_;
std::vector<T> elements_;
-
- DISALLOW_COPY_AND_ASSIGN(PrimitiveArrayMember);
};
using ResourceArrayMember = PrimitiveArrayMember<ResourceId>;
@@ -185,12 +183,16 @@
}
// Even if the method is empty, we always want to write the method signature.
- bool empty() const override { return false; }
+ bool empty() const override {
+ return false;
+ }
void WriteToStream(const android::StringPiece& prefix, bool final,
std::ostream* out) const override;
private:
+ DISALLOW_COPY_AND_ASSIGN(MethodDefinition);
+
std::string signature_;
std::vector<std::string> statements_;
};
@@ -222,19 +224,13 @@
std::ostream* out) const override;
private:
- struct ClassMemberCompare {
- using T = std::unique_ptr<ClassMember>;
- bool operator()(const T& a, const T& b) const {
- return a->GetName() < b->GetName();
- }
- };
+ DISALLOW_COPY_AND_ASSIGN(ClassDefinition);
std::string name_;
ClassQualifier qualifier_;
bool create_if_empty_;
- std::set<std::unique_ptr<ClassMember>, ClassMemberCompare> members_;
-
- DISALLOW_COPY_AND_ASSIGN(ClassDefinition);
+ std::vector<std::unique_ptr<ClassMember>> ordered_members_;
+ std::unordered_map<android::StringPiece, size_t> indexed_members_;
};
} // namespace aapt
diff --git a/tools/aapt2/java/JavaClassGenerator_test.cpp b/tools/aapt2/java/JavaClassGenerator_test.cpp
index 4f449f0..668e434 100644
--- a/tools/aapt2/java/JavaClassGenerator_test.cpp
+++ b/tools/aapt2/java/JavaClassGenerator_test.cpp
@@ -24,6 +24,8 @@
using ::android::StringPiece;
using ::testing::HasSubstr;
+using ::testing::Lt;
+using ::testing::Ne;
using ::testing::Not;
namespace aapt {
@@ -306,6 +308,53 @@
EXPECT_THAT(output, HasSubstr(styleable.GetComment()));
}
+TEST(JavaClassGeneratorTest, StyleableAndIndicesAreColocated) {
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .SetPackageId("android", 0x01)
+ .AddValue("android:attr/layout_gravity", util::make_unique<Attribute>())
+ .AddValue("android:attr/background", util::make_unique<Attribute>())
+ .AddValue("android:styleable/ActionBar",
+ test::StyleableBuilder()
+ .AddItem("android:attr/background", ResourceId(0x01010000))
+ .Build())
+ .AddValue("android:styleable/ActionBar.LayoutParams",
+ test::StyleableBuilder()
+ .AddItem("android:attr/layout_gravity", ResourceId(0x01010001))
+ .Build())
+ .Build();
+
+ std::unique_ptr<IAaptContext> context =
+ test::ContextBuilder()
+ .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
+ .SetNameManglerPolicy(NameManglerPolicy{"android"})
+ .Build();
+
+ JavaClassGeneratorOptions options;
+ JavaClassGenerator generator(context.get(), table.get(), {});
+ std::stringstream out;
+ ASSERT_TRUE(generator.Generate("android", &out));
+ std::string output = out.str();
+
+ std::string::size_type actionbar_pos = output.find("int[] ActionBar");
+ ASSERT_THAT(actionbar_pos, Ne(std::string::npos));
+
+ std::string::size_type actionbar_background_pos = output.find("int ActionBar_background");
+ ASSERT_THAT(actionbar_background_pos, Ne(std::string::npos));
+
+ std::string::size_type actionbar_layout_params_pos = output.find("int[] ActionBar_LayoutParams");
+ ASSERT_THAT(actionbar_layout_params_pos, Ne(std::string::npos));
+
+ std::string::size_type actionbar_layout_params_layout_gravity_pos =
+ output.find("int ActionBar_LayoutParams_layout_gravity");
+ ASSERT_THAT(actionbar_layout_params_layout_gravity_pos, Ne(std::string::npos));
+
+ EXPECT_THAT(actionbar_pos, Lt(actionbar_background_pos));
+ EXPECT_THAT(actionbar_pos, Lt(actionbar_layout_params_pos));
+ EXPECT_THAT(actionbar_background_pos, Lt(actionbar_layout_params_pos));
+ EXPECT_THAT(actionbar_layout_params_pos, Lt(actionbar_layout_params_layout_gravity_pos));
+}
+
TEST(JavaClassGeneratorTest, CommentsForRemovedAttributesAreNotPresentInClass) {
Attribute attr(false);
attr.SetComment(StringPiece("removed"));
diff --git a/tools/aapt2/optimize/MultiApkGenerator.cpp b/tools/aapt2/optimize/MultiApkGenerator.cpp
index 5ff8908..8e4b82c 100644
--- a/tools/aapt2/optimize/MultiApkGenerator.cpp
+++ b/tools/aapt2/optimize/MultiApkGenerator.cpp
@@ -22,22 +22,50 @@
#include "androidfw/StringPiece.h"
#include "LoadedApk.h"
+#include "ResourceUtils.h"
+#include "ValueVisitor.h"
#include "configuration/ConfigurationParser.h"
#include "filter/AbiFilter.h"
#include "filter/Filter.h"
#include "flatten/Archive.h"
+#include "flatten/XmlFlattener.h"
#include "optimize/VersionCollapser.h"
#include "process/IResourceTableConsumer.h"
#include "split/TableSplitter.h"
#include "util/Files.h"
+#include "xml/XmlDom.h"
+#include "xml/XmlUtil.h"
namespace aapt {
using ::aapt::configuration::AndroidSdk;
using ::aapt::configuration::Artifact;
using ::aapt::configuration::PostProcessingConfiguration;
+using ::aapt::xml::kSchemaAndroid;
+using ::aapt::xml::XmlResource;
using ::android::StringPiece;
+namespace {
+
+Maybe<AndroidSdk> GetAndroidSdk(const Artifact& artifact, const PostProcessingConfiguration& config,
+ IDiagnostics* diag) {
+ if (!artifact.android_sdk_group) {
+ return {};
+ }
+
+ const std::string& group_name = artifact.android_sdk_group.value();
+ auto group = config.android_sdk_groups.find(group_name);
+ // TODO: Remove validation when configuration parser ensures referential integrity.
+ if (group == config.android_sdk_groups.end()) {
+ diag->Error(DiagMessage() << "could not find referenced group '" << group_name << "'");
+ return {};
+ }
+
+ return group->second;
+}
+
+} // namespace
+
/**
* Context wrapper that allows the min Android SDK value to be overridden.
*/
@@ -127,6 +155,13 @@
return false;
}
+ std::unique_ptr<XmlResource> manifest;
+ if (!UpdateManifest(artifact, config, &manifest, diag)) {
+ diag->Error(DiagMessage() << "could not update AndroidManifest.xml for "
+ << artifact_name.value());
+ return false;
+ }
+
std::string out = options.out_dir;
if (!file::mkdirs(out)) {
context_->GetDiagnostics()->Warn(DiagMessage() << "could not create out dir: " << out);
@@ -145,7 +180,7 @@
}
if (!apk_->WriteToArchive(context_, table.get(), options.table_flattener_options, &filters,
- writer.get())) {
+ writer.get(), manifest.get())) {
return false;
}
}
@@ -208,37 +243,15 @@
splits.config_filter = &axis_filter;
}
- if (artifact.android_sdk_group) {
- const std::string& group_name = artifact.android_sdk_group.value();
- auto group = config.android_sdk_groups.find(group_name);
- // TODO: Remove validation when configuration parser ensures referential integrity.
- if (group == config.android_sdk_groups.end()) {
- context_->GetDiagnostics()->Error(DiagMessage() << "could not find referenced group '"
- << group_name << "'");
- return {};
- }
-
- const AndroidSdk& sdk = group->second;
- if (!sdk.min_sdk_version) {
- context_->GetDiagnostics()->Error(DiagMessage()
- << "skipping SDK version. No min SDK: " << group_name);
- return {};
- }
-
- ConfigDescription c;
- const std::string& version = sdk.min_sdk_version.value();
- if (!ConfigDescription::Parse(version, &c)) {
- context_->GetDiagnostics()->Error(DiagMessage() << "could not parse min SDK: " << version);
- return {};
- }
-
- wrappedContext.SetMinSdkVersion(c.sdkVersion);
+ Maybe<AndroidSdk> sdk = GetAndroidSdk(artifact, config, context_->GetDiagnostics());
+ if (sdk && sdk.value().min_sdk_version) {
+ wrappedContext.SetMinSdkVersion(sdk.value().min_sdk_version.value());
}
std::unique_ptr<ResourceTable> table = old_table.Clone();
VersionCollapser collapser;
- if (!collapser.Consume(context_, table.get())) {
+ if (!collapser.Consume(&wrappedContext, table.get())) {
context_->GetDiagnostics()->Error(DiagMessage() << "Failed to strip versioned resources");
return {};
}
@@ -248,4 +261,95 @@
return table;
}
+bool MultiApkGenerator::UpdateManifest(const Artifact& artifact,
+ const PostProcessingConfiguration& config,
+ std::unique_ptr<XmlResource>* updated_manifest,
+ IDiagnostics* diag) {
+ *updated_manifest = apk_->InflateManifest(context_);
+ XmlResource* manifest = updated_manifest->get();
+ if (manifest == nullptr) {
+ return false;
+ }
+
+ // Make sure the first element is <manifest> with package attribute.
+ xml::Element* manifest_el = manifest->root.get();
+ if (manifest_el == nullptr) {
+ return false;
+ }
+
+ if (!manifest_el->namespace_uri.empty() || manifest_el->name != "manifest") {
+ diag->Error(DiagMessage(manifest->file.source) << "root tag must be <manifest>");
+ return false;
+ }
+
+ // Update the versionCode attribute.
+ xml::Attribute* versionCode = manifest_el->FindAttribute(kSchemaAndroid, "versionCode");
+ if (versionCode == nullptr) {
+ diag->Error(DiagMessage(manifest->file.source) << "manifest must have a versionCode attribute");
+ return false;
+ }
+
+ auto* compiled_version = ValueCast<BinaryPrimitive>(versionCode->compiled_value.get());
+ if (compiled_version == nullptr) {
+ diag->Error(DiagMessage(manifest->file.source) << "versionCode is invalid");
+ return false;
+ }
+
+ int new_version = compiled_version->value.data + artifact.version;
+ versionCode->compiled_value = ResourceUtils::TryParseInt(std::to_string(new_version));
+
+ // Check to see if the minSdkVersion needs to be updated.
+ Maybe<AndroidSdk> maybe_sdk = GetAndroidSdk(artifact, config, diag);
+ if (maybe_sdk) {
+ // TODO(safarmer): Handle the rest of the Android SDK.
+ const AndroidSdk& android_sdk = maybe_sdk.value();
+
+ if (xml::Element* uses_sdk_el = manifest_el->FindChild({}, "uses-sdk")) {
+ if (xml::Attribute* min_sdk_attr =
+ uses_sdk_el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion")) {
+ // Populate with a pre-compiles attribute to we don't need to relink etc.
+ const std::string& min_sdk_str = std::to_string(android_sdk.min_sdk_version.value());
+ min_sdk_attr->compiled_value = ResourceUtils::TryParseInt(min_sdk_str);
+ } else {
+ // There was no minSdkVersion. This is strange since at this point we should have been
+ // through the manifest fixer which sets the default minSdkVersion.
+ diag->Error(DiagMessage(manifest->file.source) << "missing minSdkVersion from <uses-sdk>");
+ return false;
+ }
+ } else {
+ // No uses-sdk present. This is strange since at this point we should have been
+ // through the manifest fixer which should have added it.
+ diag->Error(DiagMessage(manifest->file.source) << "missing <uses-sdk> from <manifest>");
+ return false;
+ }
+ }
+
+ if (artifact.screen_density_group) {
+ auto densities = config.screen_density_groups.find(artifact.screen_density_group.value());
+ CHECK(densities != config.screen_density_groups.end()) << "Missing density group";
+
+ xml::Element* screens_el = manifest_el->FindChild({}, "compatible-screens");
+ if (!screens_el) {
+ // create a new element.
+ std::unique_ptr<xml::Element> new_screens_el = util::make_unique<xml::Element>();
+ new_screens_el->name = "compatible-screens";
+ screens_el = new_screens_el.get();
+ manifest_el->InsertChild(0, std::move(new_screens_el));
+ } else {
+ // clear out the old element.
+ screens_el->GetChildElements().clear();
+ }
+
+ for (const auto& density : densities->second) {
+ std::unique_ptr<xml::Element> screen_el = util::make_unique<xml::Element>();
+ screen_el->name = "screen";
+ const char* density_str = density.toString().string();
+ screen_el->attributes.push_back(xml::Attribute{kSchemaAndroid, "screenDensity", density_str});
+ screens_el->AppendChild(std::move(screen_el));
+ }
+ }
+
+ return true;
+}
+
} // namespace aapt
diff --git a/tools/aapt2/optimize/MultiApkGenerator.h b/tools/aapt2/optimize/MultiApkGenerator.h
index b064400..e6546ee 100644
--- a/tools/aapt2/optimize/MultiApkGenerator.h
+++ b/tools/aapt2/optimize/MultiApkGenerator.h
@@ -54,6 +54,10 @@
return context_->GetDiagnostics();
}
+ bool UpdateManifest(const configuration::Artifact& artifact,
+ const configuration::PostProcessingConfiguration& config,
+ std::unique_ptr<xml::XmlResource>* updated_manifest, IDiagnostics* diag);
+
LoadedApk* apk_;
IAaptContext* context_;
};
diff --git a/tools/aapt2/optimize/MultiApkGenerator_test.cpp b/tools/aapt2/optimize/MultiApkGenerator_test.cpp
index 23f573c..e8e6adc 100644
--- a/tools/aapt2/optimize/MultiApkGenerator_test.cpp
+++ b/tools/aapt2/optimize/MultiApkGenerator_test.cpp
@@ -50,14 +50,6 @@
using ::testing::Test;
using ::testing::_;
-/** Subclass the LoadedApk class so that we can mock the WriteToArchive method. */
-class MockApk : public LoadedApk {
- public:
- MockApk(std::unique_ptr<ResourceTable> table) : LoadedApk({"test.apk"}, {}, std::move(table)){};
- MOCK_METHOD5(WriteToArchive, bool(IAaptContext*, ResourceTable*, const TableFlattenerOptions&,
- FilterChain*, IArchiveWriter*));
-};
-
/**
* Subclass the MultiApkGenerator class so that we can access the protected FilterTable method to
* directly test table filter.
@@ -111,54 +103,10 @@
ConfigDescription v21_ = ParseConfigOrDie("v21");
};
-TEST_F(MultiApkGeneratorTest, FromBaseApk) {
- std::unique_ptr<ResourceTable> table = BuildTable();
-
- MockApk apk{std::move(table)};
-
- EXPECT_CALL(apk, WriteToArchive(_, _, _, _, _)).Times(0);
-
- test::Context ctx;
- PostProcessingConfiguration empty_config;
- TableFlattenerOptions table_flattener_options;
-
- MultiApkGenerator generator{&apk, &ctx};
- EXPECT_TRUE(generator.FromBaseApk({"out", empty_config, table_flattener_options}));
-
- Artifact x64 = test::ArtifactBuilder()
- .SetName("${basename}.x64.apk")
- .SetAbiGroup("x64")
- .SetLocaleGroup("en")
- .SetDensityGroup("xhdpi")
- .Build();
-
- Artifact intel = test::ArtifactBuilder()
- .SetName("${basename}.intel.apk")
- .SetAbiGroup("intel")
- .SetLocaleGroup("europe")
- .SetDensityGroup("large")
- .Build();
-
- auto config = test::PostProcessingConfigurationBuilder()
- .SetLocaleGroup("en", {"en"})
- .SetLocaleGroup("europe", {"en", "fr", "de", "es"})
- .SetAbiGroup("x64", {Abi::kX86_64})
- .SetAbiGroup("intel", {Abi::kX86_64, Abi::kX86})
- .SetDensityGroup("xhdpi", {"xhdpi"})
- .SetDensityGroup("large", {"xhdpi", "xxhdpi", "xxxhdpi"})
- .AddArtifact(x64)
- .AddArtifact(intel)
- .Build();
-
- // Called once for each artifact.
- EXPECT_CALL(apk, WriteToArchive(Eq(&ctx), _, _, _, _)).Times(2).WillRepeatedly(Return(true));
- EXPECT_TRUE(generator.FromBaseApk({"out", config, table_flattener_options}));
-}
-
TEST_F(MultiApkGeneratorTest, VersionFilterNewerVersion) {
std::unique_ptr<ResourceTable> table = BuildTable();
- MockApk apk{std::move(table)};
+ LoadedApk apk = {{"test.apk"}, {}, std::move(table)};
std::unique_ptr<IAaptContext> ctx = test::ContextBuilder().SetMinSdkVersion(19).Build();
PostProcessingConfiguration empty_config;
TableFlattenerOptions table_flattener_options;
@@ -174,7 +122,7 @@
.SetLocaleGroup("en", {"en"})
.SetAbiGroup("x64", {Abi::kX86_64})
.SetDensityGroup("xhdpi", {"xhdpi"})
- .SetAndroidSdk("v23", AndroidSdk::ForMinSdk("v23"))
+ .SetAndroidSdk("v23", AndroidSdk::ForMinSdk(23))
.AddArtifact(x64)
.Build();
@@ -199,7 +147,7 @@
TEST_F(MultiApkGeneratorTest, VersionFilterOlderVersion) {
std::unique_ptr<ResourceTable> table = BuildTable();
- MockApk apk{std::move(table)};
+ LoadedApk apk = {{"test.apk"}, {}, std::move(table)};
std::unique_ptr<IAaptContext> ctx = test::ContextBuilder().SetMinSdkVersion(1).Build();
PostProcessingConfiguration empty_config;
TableFlattenerOptions table_flattener_options;
@@ -215,7 +163,7 @@
.SetLocaleGroup("en", {"en"})
.SetAbiGroup("x64", {Abi::kX86_64})
.SetDensityGroup("xhdpi", {"xhdpi"})
- .SetAndroidSdk("v4", AndroidSdk::ForMinSdk("v4"))
+ .SetAndroidSdk("v4", AndroidSdk::ForMinSdk(4))
.AddArtifact(x64)
.Build();
@@ -238,7 +186,7 @@
TEST_F(MultiApkGeneratorTest, VersionFilterNoVersion) {
std::unique_ptr<ResourceTable> table = BuildTable();
- MockApk apk{std::move(table)};
+ LoadedApk apk = {{"test.apk"}, {}, std::move(table)};
std::unique_ptr<IAaptContext> ctx = test::ContextBuilder().SetMinSdkVersion(1).Build();
PostProcessingConfiguration empty_config;
TableFlattenerOptions table_flattener_options;
diff --git a/tools/aapt2/xml/XmlDom_test.cpp b/tools/aapt2/xml/XmlDom_test.cpp
index 10a4587..6b97ae6 100644
--- a/tools/aapt2/xml/XmlDom_test.cpp
+++ b/tools/aapt2/xml/XmlDom_test.cpp
@@ -18,6 +18,7 @@
#include <string>
+#include "flatten/XmlFlattener.h"
#include "io/StringInputStream.h"
#include "test/Test.h"
@@ -51,6 +52,36 @@
EXPECT_THAT(el->namespace_decls[0].prefix, StrEq("android"));
}
+TEST(XmlDomTest, BinaryInflate) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+ std::unique_ptr<XmlResource> doc = util::make_unique<XmlResource>();
+ doc->root = util::make_unique<Element>();
+ doc->root->name = "Layout";
+ doc->root->line_number = 2u;
+
+ NamespaceDecl decl;
+ decl.uri = kSchemaAndroid;
+ decl.prefix = "android";
+ decl.line_number = 2u;
+ doc->root->namespace_decls.push_back(decl);
+
+ BigBuffer buffer(4096);
+ XmlFlattener flattener(&buffer, {});
+ ASSERT_TRUE(flattener.Consume(context.get(), doc.get()));
+
+ auto block = util::Copy(buffer);
+ std::unique_ptr<XmlResource> new_doc =
+ Inflate(block.get(), buffer.size(), context->GetDiagnostics(), Source("test.xml"));
+ ASSERT_THAT(new_doc, NotNull());
+
+ EXPECT_THAT(new_doc->root->name, StrEq("Layout"));
+ EXPECT_THAT(new_doc->root->line_number, Eq(2u));
+ ASSERT_THAT(new_doc->root->namespace_decls, SizeIs(1u));
+ EXPECT_THAT(new_doc->root->namespace_decls[0].uri, StrEq(kSchemaAndroid));
+ EXPECT_THAT(new_doc->root->namespace_decls[0].prefix, StrEq("android"));
+ EXPECT_THAT(new_doc->root->namespace_decls[0].line_number, Eq(2u));
+}
+
// Escaping is handled after parsing of the values for resource-specific values.
TEST(XmlDomTest, ForwardEscapes) {
std::unique_ptr<XmlResource> doc = test::BuildXmlDom(R"(
diff --git a/wifi/java/android/net/wifi/rtt/IRttCallback.aidl b/wifi/java/android/net/wifi/rtt/IRttCallback.aidl
new file mode 100644
index 0000000..fb1636f
--- /dev/null
+++ b/wifi/java/android/net/wifi/rtt/IRttCallback.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.rtt;
+
+import android.net.wifi.rtt.RangingResult;
+
+/**
+ * Interface for RTT result callback.
+ *
+ * @hide
+ */
+oneway interface IRttCallback
+{
+ /**
+ * Service to manager callback providing RTT status and results.
+ */
+ void onRangingResults(int status, in List<RangingResult> results);
+}
diff --git a/wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl b/wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl
new file mode 100644
index 0000000..ad92e04
--- /dev/null
+++ b/wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.rtt;
+
+import android.net.wifi.rtt.IRttCallback;
+import android.net.wifi.rtt.RangingRequest;
+
+/**
+ * @hide
+ */
+interface IWifiRttManager
+{
+ void startRanging(in IBinder binder, in String callingPackage, in RangingRequest request,
+ in IRttCallback callback);
+}
diff --git a/wifi/java/android/net/wifi/rtt/RangingRequest.aidl b/wifi/java/android/net/wifi/rtt/RangingRequest.aidl
new file mode 100644
index 0000000..8053c94
--- /dev/null
+++ b/wifi/java/android/net/wifi/rtt/RangingRequest.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.rtt;
+
+parcelable RangingRequest;
diff --git a/wifi/java/android/net/wifi/rtt/RangingRequest.java b/wifi/java/android/net/wifi/rtt/RangingRequest.java
new file mode 100644
index 0000000..997b680
--- /dev/null
+++ b/wifi/java/android/net/wifi/rtt/RangingRequest.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.rtt;
+
+import android.net.wifi.ScanResult;
+import android.os.Handler;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringJoiner;
+
+/**
+ * Defines the ranging request to other devices. The ranging request is built using
+ * {@link RangingRequest.Builder}.
+ * A ranging request is executed using
+ * {@link WifiRttManager#startRanging(RangingRequest, RangingResultCallback, Handler)}.
+ * <p>
+ * The ranging request is a batch request - specifying a set of devices (specified using
+ * {@link RangingRequest.Builder#addAp(ScanResult)} and
+ * {@link RangingRequest.Builder#addAps(List)}).
+ *
+ * @hide RTT_API
+ */
+public final class RangingRequest implements Parcelable {
+ private static final int MAX_PEERS = 10;
+
+ /**
+ * Returns the maximum number of peers to range which can be specified in a single {@code
+ * RangingRequest}. The limit applies no matter how the peers are added to the request, e.g.
+ * through {@link RangingRequest.Builder#addAp(ScanResult)} or
+ * {@link RangingRequest.Builder#addAps(List)}.
+ *
+ * @return Maximum number of peers.
+ */
+ public static int getMaxPeers() {
+ return MAX_PEERS;
+ }
+
+ /** @hide */
+ public final List<RttPeer> mRttPeers;
+
+ /** @hide */
+ private RangingRequest(List<RttPeer> rttPeers) {
+ mRttPeers = rttPeers;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeList(mRttPeers);
+ }
+
+ public static final Creator<RangingRequest> CREATOR = new Creator<RangingRequest>() {
+ @Override
+ public RangingRequest[] newArray(int size) {
+ return new RangingRequest[size];
+ }
+
+ @Override
+ public RangingRequest createFromParcel(Parcel in) {
+ return new RangingRequest(in.readArrayList(null));
+ }
+ };
+
+ /** @hide */
+ @Override
+ public String toString() {
+ StringJoiner sj = new StringJoiner(", ", "RangingRequest: mRttPeers=[", ",");
+ for (RttPeer rp : mRttPeers) {
+ sj.add(rp.toString());
+ }
+ return sj.toString();
+ }
+
+ /** @hide */
+ public void enforceValidity() {
+ if (mRttPeers.size() > MAX_PEERS) {
+ throw new IllegalArgumentException(
+ "Ranging to too many peers requested. Use getMaxPeers() API to get limit.");
+ }
+ }
+
+ /**
+ * Builder class used to construct {@link RangingRequest} objects.
+ */
+ public static final class Builder {
+ private List<RttPeer> mRttPeers = new ArrayList<>();
+
+ /**
+ * Add the device specified by the {@link ScanResult} to the list of devices with
+ * which to measure range. The total number of results added to a request cannot exceed the
+ * limit specified by {@link #getMaxPeers()}.
+ *
+ * @param apInfo Information of an Access Point (AP) obtained in a Scan Result.
+ * @return The builder to facilitate chaining
+ * {@code builder.setXXX(..).setXXX(..)}.
+ */
+ public Builder addAp(ScanResult apInfo) {
+ if (apInfo == null) {
+ throw new IllegalArgumentException("Null ScanResult!");
+ }
+ mRttPeers.add(new RttPeerAp(apInfo));
+ return this;
+ }
+
+ /**
+ * Add the devices specified by the {@link ScanResult}s to the list of devices with
+ * which to measure range. The total number of results added to a request cannot exceed the
+ * limit specified by {@link #getMaxPeers()}.
+ *
+ * @param apInfos Information of an Access Points (APs) obtained in a Scan Result.
+ * @return The builder to facilitate chaining
+ * {@code builder.setXXX(..).setXXX(..)}.
+ */
+ public Builder addAps(List<ScanResult> apInfos) {
+ if (apInfos == null) {
+ throw new IllegalArgumentException("Null list of ScanResults!");
+ }
+ for (ScanResult scanResult : apInfos) {
+ addAp(scanResult);
+ }
+ return this;
+ }
+
+ /**
+ * Build {@link RangingRequest} given the current configurations made on the
+ * builder.
+ */
+ public RangingRequest build() {
+ return new RangingRequest(mRttPeers);
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+
+ if (!(o instanceof RangingRequest)) {
+ return false;
+ }
+
+ RangingRequest lhs = (RangingRequest) o;
+
+ return mRttPeers.size() == lhs.mRttPeers.size() && mRttPeers.containsAll(lhs.mRttPeers);
+ }
+
+ @Override
+ public int hashCode() {
+ return mRttPeers.hashCode();
+ }
+
+ /** @hide */
+ public interface RttPeer {
+ // empty (marker interface)
+ }
+
+ /** @hide */
+ public static class RttPeerAp implements RttPeer, Parcelable {
+ public final ScanResult scanResult;
+
+ public RttPeerAp(ScanResult scanResult) {
+ this.scanResult = scanResult;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ scanResult.writeToParcel(dest, flags);
+ }
+
+ public static final Creator<RttPeerAp> CREATOR = new Creator<RttPeerAp>() {
+ @Override
+ public RttPeerAp[] newArray(int size) {
+ return new RttPeerAp[size];
+ }
+
+ @Override
+ public RttPeerAp createFromParcel(Parcel in) {
+ return new RttPeerAp(ScanResult.CREATOR.createFromParcel(in));
+ }
+ };
+
+ @Override
+ public String toString() {
+ return new StringBuilder("RttPeerAp: scanResult=").append(
+ scanResult.toString()).toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+
+ if (!(o instanceof RttPeerAp)) {
+ return false;
+ }
+
+ RttPeerAp lhs = (RttPeerAp) o;
+
+ // Note: the only thing which matters for the request identity is the BSSID of the AP
+ return TextUtils.equals(scanResult.BSSID, lhs.scanResult.BSSID);
+ }
+
+ @Override
+ public int hashCode() {
+ return scanResult.hashCode();
+ }
+ }
+}
\ No newline at end of file
diff --git a/wifi/java/android/net/wifi/rtt/RangingResult.aidl b/wifi/java/android/net/wifi/rtt/RangingResult.aidl
new file mode 100644
index 0000000..ae295a6
--- /dev/null
+++ b/wifi/java/android/net/wifi/rtt/RangingResult.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.rtt;
+
+parcelable RangingResult;
diff --git a/wifi/java/android/net/wifi/rtt/RangingResult.java b/wifi/java/android/net/wifi/rtt/RangingResult.java
new file mode 100644
index 0000000..918803e
--- /dev/null
+++ b/wifi/java/android/net/wifi/rtt/RangingResult.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.rtt;
+
+import android.os.Handler;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import libcore.util.HexEncoding;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Ranging result for a request started by
+ * {@link WifiRttManager#startRanging(RangingRequest, RangingResultCallback, Handler)}. Results are
+ * returned in {@link RangingResultCallback#onRangingResults(List)}.
+ * <p>
+ * A ranging result is the distance measurement result for a single device specified in the
+ * {@link RangingRequest}.
+ *
+ * @hide RTT_API
+ */
+public final class RangingResult implements Parcelable {
+ private static final String TAG = "RangingResult";
+
+ private final int mStatus;
+ private final byte[] mMac;
+ private final int mDistanceCm;
+ private final int mDistanceStdDevCm;
+ private final int mRssi;
+ private final long mTimestamp;
+
+ /** @hide */
+ public RangingResult(int status, byte[] mac, int distanceCm, int distanceStdDevCm, int rssi,
+ long timestamp) {
+ mStatus = status;
+ mMac = mac;
+ mDistanceCm = distanceCm;
+ mDistanceStdDevCm = distanceStdDevCm;
+ mRssi = rssi;
+ mTimestamp = timestamp;
+ }
+
+ /**
+ * @return The status of ranging measurement: {@link RangingResultCallback#STATUS_SUCCESS} in
+ * case of success, and {@link RangingResultCallback#STATUS_FAIL} in case of failure.
+ */
+ public int getStatus() {
+ return mStatus;
+ }
+
+ /**
+ * @return The MAC address of the device whose range measurement was requested. Will correspond
+ * to the MAC address of the device in the {@link RangingRequest}.
+ * <p>
+ * Always valid (i.e. when {@link #getStatus()} is either SUCCESS or FAIL.
+ */
+ public byte[] getMacAddress() {
+ return mMac;
+ }
+
+ /**
+ * @return The distance (in cm) to the device specified by {@link #getMacAddress()}.
+ * <p>
+ * Only valid if {@link #getStatus()} returns {@link RangingResultCallback#STATUS_SUCCESS}.
+ */
+ public int getDistanceCm() {
+ if (mStatus != RangingResultCallback.STATUS_SUCCESS) {
+ Log.e(TAG, "getDistanceCm(): invalid value retrieved");
+ }
+ return mDistanceCm;
+ }
+
+ /**
+ * @return The standard deviation of the measured distance (in cm) to the device specified by
+ * {@link #getMacAddress()}. The standard deviation is calculated over the measurements
+ * executed in a single RTT burst.
+ * <p>
+ * Only valid if {@link #getStatus()} returns {@link RangingResultCallback#STATUS_SUCCESS}.
+ */
+ public int getDistanceStdDevCm() {
+ if (mStatus != RangingResultCallback.STATUS_SUCCESS) {
+ Log.e(TAG, "getDistanceStdDevCm(): invalid value retrieved");
+ }
+ return mDistanceStdDevCm;
+ }
+
+ /**
+ * @return The average RSSI (in units of -0.5dB) observed during the RTT measurement.
+ * <p>
+ * Only valid if {@link #getStatus()} returns {@link RangingResultCallback#STATUS_SUCCESS}.
+ */
+ public int getRssi() {
+ if (mStatus != RangingResultCallback.STATUS_SUCCESS) {
+ // TODO: should this be an exception?
+ Log.e(TAG, "getRssi(): invalid value retrieved");
+ }
+ return mRssi;
+ }
+
+ /**
+ * @return The timestamp (in us) at which the ranging operation was performed
+ * <p>
+ * Only valid if {@link #getStatus()} returns {@link RangingResultCallback#STATUS_SUCCESS}.
+ */
+ public long getRangingTimestamp() {
+ return mTimestamp;
+ }
+
+ /** @hide */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** @hide */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mStatus);
+ dest.writeByteArray(mMac);
+ dest.writeInt(mDistanceCm);
+ dest.writeInt(mDistanceStdDevCm);
+ dest.writeInt(mRssi);
+ dest.writeLong(mTimestamp);
+ }
+
+ /** @hide */
+ public static final Creator<RangingResult> CREATOR = new Creator<RangingResult>() {
+ @Override
+ public RangingResult[] newArray(int size) {
+ return new RangingResult[size];
+ }
+
+ @Override
+ public RangingResult createFromParcel(Parcel in) {
+ int status = in.readInt();
+ byte[] mac = in.createByteArray();
+ int distanceCm = in.readInt();
+ int distanceStdDevCm = in.readInt();
+ int rssi = in.readInt();
+ long timestamp = in.readLong();
+ return new RangingResult(status, mac, distanceCm, distanceStdDevCm, rssi, timestamp);
+ }
+ };
+
+ /** @hide */
+ @Override
+ public String toString() {
+ return new StringBuilder("RangingResult: [status=").append(mStatus).append(", mac=").append(
+ mMac == null ? "<null>" : HexEncoding.encodeToString(mMac)).append(
+ ", distanceCm=").append(mDistanceCm).append(", distanceStdDevCm=").append(
+ mDistanceStdDevCm).append(", rssi=").append(mRssi).append(", timestamp=").append(
+ mTimestamp).append("]").toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+
+ if (!(o instanceof RangingResult)) {
+ return false;
+ }
+
+ RangingResult lhs = (RangingResult) o;
+
+ return mStatus == lhs.mStatus && Arrays.equals(mMac, lhs.mMac)
+ && mDistanceCm == lhs.mDistanceCm && mDistanceStdDevCm == lhs.mDistanceStdDevCm
+ && mRssi == lhs.mRssi && mTimestamp == lhs.mTimestamp;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mStatus, mMac, mDistanceCm, mDistanceStdDevCm, mRssi, mTimestamp);
+ }
+}
\ No newline at end of file
diff --git a/wifi/java/android/net/wifi/rtt/RangingResultCallback.java b/wifi/java/android/net/wifi/rtt/RangingResultCallback.java
new file mode 100644
index 0000000..d7270ad
--- /dev/null
+++ b/wifi/java/android/net/wifi/rtt/RangingResultCallback.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.rtt;
+
+import android.os.Handler;
+
+import java.util.List;
+
+/**
+ * Base class for ranging result callbacks. Should be extended by applications and set when calling
+ * {@link WifiRttManager#startRanging(RangingRequest, RangingResultCallback, Handler)}. A single
+ * result from a range request will be called in this object.
+ *
+ * @hide RTT_API
+ */
+public abstract class RangingResultCallback {
+ /**
+ * Individual range request status, {@link RangingResult#getStatus()}. Indicates ranging
+ * operation was successful and distance value is valid.
+ */
+ public static final int STATUS_SUCCESS = 0;
+
+ /**
+ * Individual range request status, {@link RangingResult#getStatus()}. Indicates ranging
+ * operation failed and the distance value is invalid.
+ */
+ public static final int STATUS_FAIL = 1;
+
+ /**
+ * Called when a ranging operation failed in whole - i.e. no ranging operation to any of the
+ * devices specified in the request was attempted.
+ */
+ public abstract void onRangingFailure();
+
+ /**
+ * Called when a ranging operation was executed. The list of results corresponds to devices
+ * specified in the ranging request.
+ *
+ * @param results List of range measurements, one per requested device.
+ */
+ public abstract void onRangingResults(List<RangingResult> results);
+}
diff --git a/wifi/java/android/net/wifi/rtt/WifiRttManager.java b/wifi/java/android/net/wifi/rtt/WifiRttManager.java
new file mode 100644
index 0000000..a085de1
--- /dev/null
+++ b/wifi/java/android/net/wifi/rtt/WifiRttManager.java
@@ -0,0 +1,100 @@
+package android.net.wifi.rtt;
+
+import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
+import static android.Manifest.permission.ACCESS_WIFI_STATE;
+import static android.Manifest.permission.CHANGE_WIFI_STATE;
+
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.List;
+
+/**
+ * This class provides the primary API for measuring distance (range) to other devices using the
+ * IEEE 802.11mc Wi-Fi Round Trip Time (RTT) technology.
+ * <p>
+ * The devices which can be ranged include:
+ * <li>Access Points (APs)
+ * <p>
+ * Ranging requests are triggered using
+ * {@link #startRanging(RangingRequest, RangingResultCallback, Handler)}. Results (in case of
+ * successful operation) are returned in the {@link RangingResultCallback#onRangingResults(List)}
+ * callback.
+ *
+ * @hide RTT_API
+ */
+@SystemService(Context.WIFI_RTT2_SERVICE)
+public class WifiRttManager {
+ private static final String TAG = "WifiRttManager";
+ private static final boolean VDBG = true;
+
+ private final Context mContext;
+ private final IWifiRttManager mService;
+
+ /** @hide */
+ public WifiRttManager(Context context, IWifiRttManager service) {
+ mContext = context;
+ mService = service;
+ }
+
+ /**
+ * Initiate a request to range to a set of devices specified in the {@link RangingRequest}.
+ * Results will be returned in the {@link RangingResultCallback} set of callbacks.
+ *
+ * @param request A request specifying a set of devices whose distance measurements are
+ * requested.
+ * @param callback A callback for the result of the ranging request.
+ * @param handler The Handler on whose thread to execute the callbacks of the {@code
+ * callback} object. If a null is provided then the application's main thread
+ * will be used.
+ */
+ @RequiresPermission(allOf = {ACCESS_COARSE_LOCATION, CHANGE_WIFI_STATE, ACCESS_WIFI_STATE})
+ public void startRanging(RangingRequest request, RangingResultCallback callback,
+ @Nullable Handler handler) {
+ if (VDBG) {
+ Log.v(TAG, "startRanging: request=" + request + ", callback=" + callback + ", handler="
+ + handler);
+ }
+
+ Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper();
+ Binder binder = new Binder();
+ try {
+ mService.startRanging(binder, mContext.getOpPackageName(), request,
+ new RttCallbackProxy(looper, callback));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ private static class RttCallbackProxy extends IRttCallback.Stub {
+ private final Handler mHandler;
+ private final RangingResultCallback mCallback;
+
+ RttCallbackProxy(Looper looper, RangingResultCallback callback) {
+ mHandler = new Handler(looper);
+ mCallback = callback;
+ }
+
+ @Override
+ public void onRangingResults(int status, List<RangingResult> results) throws RemoteException {
+ if (VDBG) {
+ Log.v(TAG, "RttCallbackProxy: onRanginResults: status=" + status + ", results="
+ + results);
+ }
+ mHandler.post(() -> {
+ if (status == RangingResultCallback.STATUS_SUCCESS) {
+ mCallback.onRangingResults(results);
+ } else {
+ mCallback.onRangingFailure();
+ }
+ });
+ }
+ }
+}
diff --git a/wifi/java/android/net/wifi/rtt/package.html b/wifi/java/android/net/wifi/rtt/package.html
new file mode 100644
index 0000000..221b94b
--- /dev/null
+++ b/wifi/java/android/net/wifi/rtt/package.html
@@ -0,0 +1,39 @@
+<HTML>
+<BODY>
+<p>Provides classes which allow applications to use Wi-Fi RTT (IEEE 802.11mc) to measure distance
+ to supporting Access Points and peer devices.</p>
+<p>The primary entry point to Wi-Fi RTT capabilities is the
+ {@link android.net.wifi.rtt.WifiRttManager} class, which is acquired by calling
+ {@link android.content.Context#getSystemService(String)
+ Context.getSystemService(Context.WIFI_RTT_SERVICE)}</p>
+
+<p>Some APIs may require the following user permissions:</p>
+<ul>
+ <li>{@link android.Manifest.permission#ACCESS_WIFI_STATE}</li>
+ <li>{@link android.Manifest.permission#CHANGE_WIFI_STATE}</li>
+ <li>{@link android.Manifest.permission#ACCESS_COARSE_LOCATION}</li>
+</ul>
+
+<p class="note"><strong>Note:</strong> Not all Android-powered devices support Wi-Fi RTT
+ functionality.
+ If your application only works with Wi-Fi RTT (i.e. it should only be installed on devices which
+ support Wi-Fi RTT), declare so with a <a
+ href="{@docRoot}guide/topics/manifest/uses-feature-element.html">
+ {@code <uses-feature>}</a>
+ element in the manifest file:</p>
+<pre>
+<manifest ...>
+ <uses-feature android:name="android.hardware.wifi.rtt" />
+ ...
+</manifest>
+</pre>
+<p>Alternatively, if your application does not require Wi-Fi RTT but can take advantage of it if
+ available, you can perform
+ the check at run-time in your code using {@link
+ android.content.pm.PackageManager#hasSystemFeature(String)} with {@link
+ android.content.pm.PackageManager#FEATURE_WIFI_RTT}:</p>
+<pre>
+ getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)
+</pre>
+</BODY>
+</HTML>
diff --git a/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java b/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
new file mode 100644
index 0000000..23c75ce
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.rtt;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+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.content.Context;
+import android.net.wifi.ScanResult;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.test.TestLooper;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import libcore.util.HexEncoding;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Unit test harness for WifiRttManager class.
+ */
+@SmallTest
+public class WifiRttManagerTest {
+ private WifiRttManager mDut;
+ private TestLooper mMockLooper;
+ private Handler mMockLooperHandler;
+
+ private final String packageName = "some.package.name.for.rtt.app";
+
+ @Mock
+ public Context mockContext;
+
+ @Mock
+ public IWifiRttManager mockRttService;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ mDut = new WifiRttManager(mockContext, mockRttService);
+ mMockLooper = new TestLooper();
+ mMockLooperHandler = new Handler(mMockLooper.getLooper());
+
+ when(mockContext.getOpPackageName()).thenReturn(packageName);
+ }
+
+ /**
+ * Validate ranging call flow with succesful results.
+ */
+ @Test
+ public void testRangeSuccess() throws Exception {
+ RangingRequest request = new RangingRequest.Builder().build();
+ List<RangingResult> results = new ArrayList<>();
+ results.add(new RangingResult(RangingResultCallback.STATUS_SUCCESS, null, 15, 5, 10, 666));
+ RangingResultCallback callbackMock = mock(RangingResultCallback.class);
+ ArgumentCaptor<IRttCallback> callbackCaptor = ArgumentCaptor.forClass(IRttCallback.class);
+
+ // verify ranging request passed to service
+ mDut.startRanging(request, callbackMock, mMockLooperHandler);
+ verify(mockRttService).startRanging(any(IBinder.class), eq(packageName), eq(request),
+ callbackCaptor.capture());
+
+ // service calls back with success
+ callbackCaptor.getValue().onRangingResults(RangingResultCallback.STATUS_SUCCESS, results);
+ mMockLooper.dispatchAll();
+ verify(callbackMock).onRangingResults(results);
+
+ verifyNoMoreInteractions(mockRttService, callbackMock);
+ }
+
+ /**
+ * Validate ranging call flow which failed.
+ */
+ @Test
+ public void testRangeFail() throws Exception {
+ RangingRequest request = new RangingRequest.Builder().build();
+ RangingResultCallback callbackMock = mock(RangingResultCallback.class);
+ ArgumentCaptor<IRttCallback> callbackCaptor = ArgumentCaptor.forClass(IRttCallback.class);
+
+ // verify ranging request passed to service
+ mDut.startRanging(request, callbackMock, mMockLooperHandler);
+ verify(mockRttService).startRanging(any(IBinder.class), eq(packageName), eq(request),
+ callbackCaptor.capture());
+
+ // service calls back with failure code
+ callbackCaptor.getValue().onRangingResults(RangingResultCallback.STATUS_FAIL, null);
+ mMockLooper.dispatchAll();
+ verify(callbackMock).onRangingFailure();
+
+ verifyNoMoreInteractions(mockRttService, callbackMock);
+ }
+
+ /**
+ * Validate that RangingRequest parcel works (produces same object on write/read).
+ */
+ @Test
+ public void testRangingRequestParcel() {
+ // Note: not validating parcel code of ScanResult (assumed to work)
+ ScanResult scanResult1 = new ScanResult();
+ scanResult1.BSSID = "00:01:02:03:04:05";
+ ScanResult scanResult2 = new ScanResult();
+ scanResult2.BSSID = "06:07:08:09:0A:0B";
+ ScanResult scanResult3 = new ScanResult();
+ scanResult3.BSSID = "AA:BB:CC:DD:EE:FF";
+ List<ScanResult> scanResults2and3 = new ArrayList<>(2);
+ scanResults2and3.add(scanResult2);
+ scanResults2and3.add(scanResult3);
+
+ RangingRequest.Builder builder = new RangingRequest.Builder();
+ builder.addAp(scanResult1);
+ builder.addAps(scanResults2and3);
+ RangingRequest request = builder.build();
+
+ Parcel parcelW = Parcel.obtain();
+ request.writeToParcel(parcelW, 0);
+ byte[] bytes = parcelW.marshall();
+ parcelW.recycle();
+
+ Parcel parcelR = Parcel.obtain();
+ parcelR.unmarshall(bytes, 0, bytes.length);
+ parcelR.setDataPosition(0);
+ RangingRequest rereadRequest = RangingRequest.CREATOR.createFromParcel(parcelR);
+
+ assertEquals(request, rereadRequest);
+ }
+
+ /**
+ * Validate that can request as many range operation as the upper limit on number of requests.
+ */
+ @Test
+ public void testRangingRequestAtLimit() {
+ ScanResult scanResult = new ScanResult();
+ List<ScanResult> scanResultList = new ArrayList<>();
+ for (int i = 0; i < RangingRequest.getMaxPeers() - 2; ++i) {
+ scanResultList.add(scanResult);
+ }
+
+ // create request
+ RangingRequest.Builder builder = new RangingRequest.Builder();
+ builder.addAp(scanResult);
+ builder.addAps(scanResultList);
+ builder.addAp(scanResult);
+ RangingRequest request = builder.build();
+
+ // verify request
+ request.enforceValidity();
+ }
+
+ /**
+ * Validate that limit on number of requests is applied.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testRangingRequestPastLimit() {
+ ScanResult scanResult = new ScanResult();
+ List<ScanResult> scanResultList = new ArrayList<>();
+ for (int i = 0; i < RangingRequest.getMaxPeers() - 1; ++i) {
+ scanResultList.add(scanResult);
+ }
+
+ // create request
+ RangingRequest.Builder builder = new RangingRequest.Builder();
+ builder.addAp(scanResult);
+ builder.addAps(scanResultList);
+ builder.addAp(scanResult);
+ RangingRequest request = builder.build();
+
+ // verify request
+ request.enforceValidity();
+ }
+
+ /**
+ * Validate that RangingResults parcel works (produces same object on write/read).
+ */
+ @Test
+ public void testRangingResultsParcel() {
+ // Note: not validating parcel code of ScanResult (assumed to work)
+ int status = RangingResultCallback.STATUS_SUCCESS;
+ final byte[] mac = HexEncoding.decode("000102030405".toCharArray(), false);
+ int distanceCm = 105;
+ int distanceStdDevCm = 10;
+ int rssi = 5;
+ long timestamp = System.currentTimeMillis();
+
+ RangingResult result = new RangingResult(status, mac, distanceCm, distanceStdDevCm, rssi,
+ timestamp);
+
+ Parcel parcelW = Parcel.obtain();
+ result.writeToParcel(parcelW, 0);
+ byte[] bytes = parcelW.marshall();
+ parcelW.recycle();
+
+ Parcel parcelR = Parcel.obtain();
+ parcelR.unmarshall(bytes, 0, bytes.length);
+ parcelR.setDataPosition(0);
+ RangingResult rereadResult = RangingResult.CREATOR.createFromParcel(parcelR);
+
+ assertEquals(result, rereadResult);
+ }
+}